# IOTA Documentation
> IOTA is a next-generation smart contract platform with high throughput, low latency, and an asset-oriented programming model powered by Move
This file contains all documentation content in a single document following the llmstxt.org standard.
## FAQs
## 1. How does the MoveVM improve security and developer experience?
MoveVM offers:
- **Resource-Oriented Programming:** Secure and flexible asset management.
- **Strong Data Abstraction:** Simplifies resource management tasks.
- **Static Verification:** Detects errors before code execution, enhancing security.
- **Formal Verification Support:** Allows rigorous validation of smart contract logic.
- **Improved Developer Experience:** Reduces bugs and vulnerabilities through strict typing.
## 2. How can I participate in the testnet and provide feedback?
To participate:
- **Join the Public Testnet:** Access the IOTA public testnet to explore new features.
- **Provide Feedback:** Use dedicated channels on the [IOTA Builders Discord](https://discord.gg/iota-builders) server or [GitHub](https://github.com/iotaledger/iota) to report issues.
## 3. What are the hardware requirements for validators?
[Validators](https://docs.iota.org/operator/validator-node/overview) are expected to have:
- **RAM:** 128 GB
- **CPU:** 24-core processor / 48 vCPUs
- **Storage:** 4 TB NVMe SSD
- **Network Uplink:** 1 Gbps
- **Minimum Stake:** 2 million IOTAs (can be delegated to your validator by someone else)
- **RAM:** 64 GB
- **CPU:** 8-core processor / 16 vCPUs
- **Storage:** 2 TB NVMe SSD
- **Network Uplink:** 1 Gbps
- **Minimum Stake:** 2 million IOTAs (can be delegated to your validator by someone else)
## 4. What happens to the existing IOTA EVM?
The [IOTA EVM](https://wiki.iota.org/isc/introduction/) on Layer 2 will:
- **Continue Operating:** It will eventually run alongside the new IOTA Layer 1.
- **Integration Plans:** Future plans include integrating EVM capabilities directly into Layer 1.
- **Temporary Pause During Upgrade:** The EVM chain will be paused and upgraded but will resume normal operations
afterward.
## 5. What are the key features introduced with IOTA Rebased?
Key features include:
- **L1 Smart Contracts:** Smart contract capabilities directly on the Layer 1 network using MoveVM.
- **[Delegated Proof of Stake (dPoS)](./tokenomics/proof-of-stake.mdx):** A fully decentralized network governed by validators and stakers.
- **[Enhanced Tokenomics](./tokenomics/tokenomics.mdx):** Staking rewards, transaction fees with fee-burning, and storage deposits.
- **[Improved Security and Performance](./iota-architecture/iota-security.mdx):** Resilient [consensus](./iota-architecture/consensus.mdx) mechanisms, fairer gas pricing, and dynamic validator selection.
## 6. Why is IOTA moving to the MoveVM and an object-based architecture?
The shift to the MoveVM and an object-based architecture is designed to:
- **Enhance Flexibility and Programmability:** Allow complex applications to be written via smart contracts directly on L1.
- **Support Advanced Use Cases:** Enable sophisticated financial instruments, decentralized exchanges, and intricate supply chain systems.
- **Improve Security:** Leverage MoveVM features like resource-oriented programming and static verification to enhance security.
- **Simplify Development:** Provide strong data abstraction capabilities and support for formal verification, improving the developer experience.
## 7. How will the tokenomics change under the IOTA Rebased proposal?
The new tokenomics model includes:
- **[Staking Rewards](./tokenomics/validators-staking.mdx):** Validators and delegators receive newly minted IOTA tokens as rewards (approximately 767,000 IOTAs per epoch), resulting in an initial annual inflation rate of about 6%.
- **[Transaction Fees](./tokenomics/gas-pricing.mdx):** Small fees are charged on transactions (around 0.005 IOTA for an average transaction) and are burned to create deflationary pressure.
- **[Storage Deposits](./tokenomics/gas-pricing.mdx#storage-units):** A redeemable deposit is required for storage, similar to the storage deposit system used in IOTA Stardust.
## 8. How does staking work in the new tokenomics model?
Staking involves:
- **[Delegation to Validators](./tokenomics/validators-staking.mdx):** Token holders can delegate their tokens to validators to help secure the network.
- **[Earning Rewards](./tokenomics/validators-staking.mdx#validator-pool-rewards):** Both validators and their delegators receive staking rewards from newly minted tokens.
- **Proportional Distribution:** Rewards are distributed based on the amount of stake and validator commissions.
## 9. How will the new fee-burning mechanism work?
The fee-burning mechanism:
- **Burns Transaction Fees:** Collected fees are burned, reducing the overall token supply.
- **Deflationary Effect:** Increased network usage leads to more fees burned, creating deflationary pressure.
- **Supply Dynamics:** The mechanism balances inflation from staking rewards and deflation from fee burning.
## 10. How will the introduction of transaction fees affect users?
Transaction fees are minimal and serve as a congestion control mechanism:
- **Low Fees:** Approximately 0.005 IOTA per average transaction.
- **Fee Burning:** Fees are burned to reduce the total supply, creating deflationary pressure.
- **Staking Rewards Offset Fees:** Users can earn staking rewards that may exceed the cost of transaction fees.
- **Sponsored Transactions:** Developers can cover transaction fees on behalf of users, allowing for feeless user experiences.
## 11. How will this affect current token holders?
For current token holders:
- **Balances Maintained:** All balances will be migrated to the new network without loss.
- **Same Private Keys:** Users can access their tokens using their existing private keys in the new IOTA Wallet.
- **[Staking Opportunities](./tokenomics/validators-staking.mdx):** Token holders can participate in staking or delegation to earn rewards.
## 12. Firefly Isn't Working
**Firefly for IOTA is deprecated** and no longer supports the new IOTA Mainnet network.
You should switch to the [new IOTA Wallet](https://chrome.google.com/webstore/detail/iota-wallet/lfhohhmmcplfddhojblhpbblpbcoecha).
- You can import your **mnemonic** or connect your **Ledger device**.
- If the in-app updater is broken (on Windows), [download the latest version manually from Firefly](https://firefly.iota.org/).
## 13. How to Migrate from Firefly/Bloom?
Firefly IOTA is no longer compatible with the new IOTA Mainnet. Please migrate to the new [IOTA Wallet](https://chrome.google.com/webstore/detail/iota-wallet/lfhohhmmcplfddhojblhpbblpbcoecha).
### Using a Mnemonic:
1. Go to the new wallet.
2. Create a new profile by importing your mnemonic.
3. See: [Getting Started with the IOTA Wallet](../users/iota-wallet/getting-started.mdx)
### Using a Ledger Device:
:::info Supported Ledger Devices
| Device | Minimum IOTA App Version | Notes |
|--------------------|--------------------------|-------|
| Ledger Nano S | 0.9.2 | The app on the this device has to be [installed manually](../../users/iota-wallet/how-to/import/ledger.mdx?install-method=manual) because it is deprecated. |
| Ledger Nano S Plus | 0.9.3 | |
| Ledger Nano X | 0.9.3 | |
| Ledger Flex | 1.0.0 | |
| Ledger Stax | 1.0.0 | |
:::
1. Ensure your IOTA Ledger App is up to date
2. Install via Ledger Live.
3. See: [Use IOTA Wallet with a Ledger Device](../users/iota-wallet/how-to/import/ledger.mdx)
If you're using a **Ledger Nano S**, follow this [specific guide](../users/iota-wallet/how-to/import/ledger.mdx).
:::info
After importing your mnemonic or connecting your Ledger, run the **Balance Finder**. This tool will help locate all your addresses. You may need to press "search" multiple times, especially if your funds are widely distributed.
:::
:::tip
Tip: It's easier to use the Balance Finder from the expanded wallet view.
:::
## 14. I Have Missing Balances. Where's My Money?
1. Ensure you're using the **correct mnemonic, seed, or Ledger**.
2. Use the **Balance Finder** to search for all your addresses:
- [How to use Balance Finder](../users/iota-wallet/getting-started.mdx)
3. After finding your addresses, go to the [IOTA Wallet Dashboard](../users/iota-wallet-dashboard/getting-started.mdx) and check:
- **Migration Tab**: For unmigrated Stardust balances
[Migrate Stardust Assets](../users/iota-wallet-dashboard/how-to/migration.mdx)
- **Vesting Tab**: For airdropped or locked funds from the October 2024 upgrade
[Manage Vesting and Time-Locked Assets](../users/iota-wallet-dashboard/how-to/vesting.mdx)
## 15. I'm Sure My Funds Are in a Specific Address But They’re Not Showing
1. Connect that address to the [Wallet Dashboard](../users/iota-wallet-dashboard/getting-started.mdx).
2. Navigate to the **Migration** tab and copy your legacy address.
3. Paste it into the [Archived Explorer](https://archive.explorer.iota.org) to check past balances.
If you don’t see your funds there, they are likely in a **different address**. Run the **Balance Finder** again.
## 16. I Can't Connect My New Accounts to the Wallet Dashboard
This is a known issue. Please follow these steps:
1. Go to `IOTA Wallet > Apps Tabs > Active Connections > Wallet Dashboard`.
2. **Disconnect all** accounts.
3. Reconnect them again from the Wallet Dashboard.
## 17. I Lost My Mnemonic. Can I Still Migrate?
Yes—if you still have your **Stronghold file** and its **password**, you can extract the seed:
1. Use **Firefly v2.1.0+** to extract the seed.
- [Restore From Seed or Stronghold](../users/iota-wallet/how-to/import/seed.mdx)
2. Import the extracted mnemonic into the new wallet:
- [Getting Started with the IOTA Wallet](../users/iota-wallet/getting-started.mdx)
:::note
Restoring from seed is not an industry standard and may only work with IOTA Foundation-supported wallets. Once restored, transfer your funds to a wallet with a **known mnemonic**.
:::
## 18. Importing a Stronghold Crashes Firefly
If you still have a Firefly profile:
- Follow this guide to export the seed:
[Back up a Seed from a Firefly Profile](../users/iota-wallet/how-to/import/seed.mdx)
If you **don’t** have the profile:
1. Download [Firefly Shimmer](https://firefly.iota.org/).
2. Create a Shimmer profile using your **mnemonic**.
3. Log out and export the seed:
[Guide to Exporting Seed](../users/iota-wallet/how-to/import/seed.mdx)
## 19. What Does It Mean If My Account is Marked as "Legacy"?
This means your addresses originate from the **"Chrysalis rotating address era"**. These addresses are considered outdated and may not be recognized by newer wallets.
:::info
**We recommend** moving your funds out of legacy addresses to ensure compatibility and accessibility.
:::
## 20. Will there be any migration steps for users?
- **Seamless Transition:** The [migration process](../developer/stardust/stardust-migration.mdx) is designed to be automatic; However, more complex asset structures such as NFTs, Aliases or time-locked assets need to be migrated via the Start Migration button on the IOTA Wallet Dashboard.
- **New Wallet Access:** Users will need to use the new [IOTA Wallet](../users/iota-wallet/getting-started.mdx) and can import their existing mnemonics or private keys.
:::tip Migrate Stardust Assets
Here is a step by step process on how to [Migrate Stardust Assets](../users/iota-wallet-dashboard/how-to/migration.mdx).
:::
## 21. Will transaction fees impact the feeless nature of IOTA?
Yes, but:
- **Minimal Impact:** Fees are very low and designed as a congestion control mechanism.
- **Net Gain for Users:** Staking rewards can offset transaction fees, potentially resulting in more tokens than before.
- **Sponsored Transactions:** Developers can sponsor fees, allowing users to transact without holding IOTA tokens.
## 22. How will the governance vote work?
The governance vote allows IOTA token holders to decide on the proposed upgrade:
- **Announcement Phase:** The proposal is announced, and the community is informed.
- **Voting Open Phase (7 days):** Voters cast their ballots before counting begins.
- **Counting Phase (7 days):** Votes accumulate over time; each IOTA token accumulates voting power at a rate of 0.01 votes per milestone.
- **Quorum Requirement:** A minimum of 5% of the circulating supply must participate for the vote to be valid.
- **Outcome Determination:** The option with the majority of votes prevails.
## 23. What happens if the proposal is accepted?
If accepted:
- **Mainnet Upgrade:** The IOTA network will transition to the new IOTA Rebased protocol after thorough testing and audits.
- **Network Transition:** A final snapshot of the current network will migrate balances to the new network on a 1:1 basis.
- **IOTA EVM Chain Upgrade:** The IOTA EVM Layer 2 chain will be temporarily paused and upgraded to integrate with the new ledger.
- **Wallet Transition:** The IOTA Firefly wallet will be discontinued. Users can access their holdings with the new IOTA Wallet using the same private keys.
- **Token Continuity:** No token migration is necessary; tokens will be available immediately after the launch.
## 24. What happens if the proposal is rejected?
If rejected:
- **Current Operations Continue:** The IOTA network will continue operating as it currently does.
- **Future Decisions:** The IOTA Foundation will decide on future development paths and how to proceed with network improvements.
## 25. What is the IOTA Rebased proposal?
The IOTA Rebased proposal is a significant upgrade to the IOTA protocol that aims to enhance the network's capabilities by:
- **Transitioning to an Object-Based Architecture:** Moving away from the current UTXO model to an object-based ledger.
- **Introducing the Move Virtual Machine (MoveVM):** Implementing MoveVM to enable Layer 1 (L1) smart contract capabilities.
- **Establishing Full Decentralization:** Adopting a delegated proof-of-stake (dPoS) system with validators and stakers to secure the network.
- **Updating Tokenomics:** Introducing staking rewards, transaction fees, and a fee-burning mechanism to create a dynamic supply.
## 26. What is the future roadmap for IOTA?
The future roadmap includes:
- **Protocol Refinements:** Enhancements like resilient consensus mechanisms and fairer gas pricing.
- **Multi-VM Ledger:** Transitioning to support multiple virtual machines, including EVM, on Layer 1.
- **Tooling and Products:** Developing new wallets, SDKs, CLI tools, and identity solutions.
- **Mainnet Launch Timeline:** A potential launch in early 2025 after thorough testing and audits.
## 27. Why is IOTA making this change now?
The change addresses:
- **Market Demands:** There's a clear need for Layer 1 programmability and smart contracts to meet modern application requirements.
- **Technological Evolution:** The new architecture allows for faster, more secure, and scalable solutions.
- **Avoiding Delays:** Continuing with the current roadmap would require additional years of research and development with uncertain outcomes.
## 28. Where can I find more information and stay updated?
Stay informed by:
- **Visiting Official Resources:** Visit the official [IOTA Foundation Blog](https://blog.iota.org/) for regular updated.
- **Joining Community Channels:** Engage with the IOTA community on the [IOTA Community Discord](https://discord.iota.org/), the
[IOTA Builders Discord](https://discord.gg/iota-builders),
[YouTube](https://www.youtube.com/c/iotafoundation), [X](https://www.twitter.com/iota/) and [GitHub](https://www.github.com/iotaledger/).
- **Following Announcements:** Keep an eye on official blog posts and updates from the IOTA Foundation.
---
## About IOTA
The IOTA ecosystem enables programmability in both [Layer 1](#layer-1) and [Layer 2](#layer-2) using [Move](#move) and [EVM/Solidity](#evm) smart contracts respectively.
## Layer 1
### Move
Move is a powerful, secure programming language designed specifically for digital asset management and smart contracts. Its unique features make it an ideal choice for developers working in the blockchain space. Here are the key features of Move:
#### Object-Centric Design
Move is fundamentally object-centric, allowing developers to intuitively model complex data structures and interactions. In Move, you can define objects representing assets, users, contracts, and more, facilitating a natural and straightforward way to manage state and behavior.
#### Performance
Move is based on the object model, not a shared global state. This allows transactions to be executed in parallel, which translates into a network with high throughput, less congestion, and therefore lower [gas](#gas-on-iota) fees.
#### Security
Move prioritizes safety and efficiency, with Rust’s ownership model inspiring Move’s approach to memory management and resource control. The compiler enforces strict rules to prevent common programming errors, ensuring that assets remain secure within user accounts and cannot be accessed without the correct keys. While the compiler catches many potential issues before deployment, developers should still be mindful of logical errors, arithmetic overflows, and other runtime concerns when implementing smart contracts.
:::warning
While the Move compiler catches many development mistakes, smart contracts can still have unintended edge cases and issues within their written logic. For this reason, it's still highly recommended to have smart contracts audited and double-checked, even when written in Move.
:::
### Networks
#### IOTA Mainnet
The [IOTA Mainnet](https://wiki.iota.org/build/networks-endpoints/#iota) is the L1 "production" network of IOTA. The IOTA Mainnet's tokens have a real-world value, so we recommend that you use the IOTA Testnet or Devnet to develop your application.
#### IOTA Testnet
The IOTA Testnet serves as a staging network and quality assurance. You can use this network to test your dApps and verify that planned changes do not adversely impact performance before deploying them to production.
#### IOTA Devnet
The IOTA Devnet is used to develop new features. You can use this network to code with the latest planned features of IOTA.
## Layer 2
### EVM
[EVM](https://ethereum.org/en/developers/docs/evm/) stands for "Ethereum Virtual Machine" and is currently the tried and tested virtual machine running most smart contract networks.
[Solidity](https://soliditylang.org/) is the programming language of choice for the EVM. It was created for this specific purpose.
The main benefit of using EVM/Solidity is its sheer amount of resources from years of development. The [IOTA Smart Contracts](https://wiki.iota.org/isc/introduction/) implementation is fully compatible with these resources, allowing you to leverage all existing EVM developer tools for developing on the IOTA EVM. Any contracts you've previously written can be deployed on IOTA Smart Contracts without modification.
Keep in mind that while EVM has become a standard for smart contract execution on L2s,
it is not inherently designed for the unique features and capabilities of L1s like Move smart contracts.
Move, with its focus on asset safety, resource management, and formal verification,
offers a fundamentally different approach at the L1 level.
### Networks
#### IOTA EVM
IOTA EVM is the distinct Layer 2 EVM running on top of the [IOTA Mainnet](./tokenomics/iota-token.mdx).
#### IOTA EVM Testnet
IOTA EVM Testnet is a distinct Layer 2 EVM on top of the IOTA testnet.
:::info
This network is subject to occasional resets (no data retention) which are usually announced with a one-week grace period.
:::
## IOTA Tokens
The [IOTA token](./tokenomics/iota-token.mdx) is the main token in the IOTA ecosystem. One IOTA can be divided into smaller units called NANOs, with one IOTA being equivalent to one billion NANOs.
### Gas on IOTA
Transactions on the IOTA network require [gas](./tokenomics/gas-pricing.mdx) fees, which are paid using IOTA or NANOs.
## Consensus on IOTA
IOTA uses a [delegated proof-of-stake (DPoS)](./tokenomics/proof-of-stake.mdx) consensus mechanism to validate on-chain transaction blocks. [Validators](iota-architecture/validator-committee.mdx) must secure a certain amount of IOTA tokens to participate in the network, where they actively run the [Starfish](./iota-architecture/consensus.mdx) consensus protocol to finalize transactions. This approach incentivizes honest behavior, enhances security, and ensures an efficient and scalable blockchain while avoiding the high energy demands of Proof-of-Work (PoW) systems, which rely on computationally intensive mining.
---
## Consensus on IOTA
import ThemedImage from '@theme/ThemedImage';
The primary goal of consensus in distributed systems is to establish a consistent order of transactions and ensure their availability. In IOTA, consensus is achieved through a combination of Delegated Proof-of-Stake (dPoS) and a Byzantine Fault Tolerant (BFT) protocol. All IOTA networks — Devnet, Testnet, and Mainnet — run the **Starfish** BFT consensus protocol.
IOTA's consensus mechanism ensures:
- **Low latency**: Transactions are confirmed quickly due to efficient leader election and consensus mechanisms.
- **High throughput**: The protocol can process a large number of transactions per second, ensuring scalability.
- **Fast finality**: Transactions reach finality in a short time, reducing the risk of rollbacks.
- **Energy efficiency**: Unlike Proof-of-Work (PoW), a BFT consensus mechanism requires minimal computational resources.
- **Security & decentralization**: The protocol resists common attacks by relying on an honest majority of validators while maintaining a decentralized structure.
## Delegated Proof-of-Stake (dPoS) in IOTA
IOTA employs Delegated Proof-of-Stake (dPoS) as the overarching consensus mechanism. In this model:
- Token holders delegate their voting power to validators.
- Validators participate in block production and execute the Starfish protocol to finalize transactions.
- Staking rewards serve as the main incentive for validators to behave honestly and secure the network.
- This structure ensures security and decentralization while maintaining scalability.
## Consensus Committee
Validators that participate in the consensus protocol collectively form the **Consensus Committee**. This committee is responsible for executing the consensus mechanism and finalizing transactions.
### Key Aspects of the Consensus Committee
- **Validator Set**: The consensus committee consists of validators, which are selected based on delegated stake.
- **Fixed Over an Epoch**: The validator set remains unchanged during an epoch to ensure stability.
- **Roles of Validators**:
- Accept transactions and execute the consensus protocol.
- Maintain a consistently ordered ledger state.
- Prevent double-spending and conflicts.
For more details on validator staking, refer to the [Validators Staking](../tokenomics/validators-staking.mdx) page. To understand epoch transitions, see the [Epochs](./epochs.mdx) documentation.
## The Starfish Protocol
**Starfish** is a _BFT_ consensus protocol optimized for **low latency** and **high throughput** using an uncertified _DAG_ structure. It is designed for robust operation under disrupted connections, uneven network latency, and adversarial validator behavior.
### Key Features of Starfish
- **Parallel Block Proposals**
Multiple validators can propose blocks simultaneously, maximizing network bandwidth and improving censorship resistance — a core advantage of DAG-based protocols.
- **Three-Round Finality Rule**
Blocks reach finality in only three rounds of communication, matching the efficiency of pBFT and achieving the theoretical minimum for BFT consensus.
- **Optimized Voting**
Validators vote and certify blocks in parallel rather than sequentially behind a single leader, significantly reducing median and tail latencies.
- **Decoupled Block Headers and Transaction Payloads**
Block header metadata is separated from transaction data, enabling efficient and flexible dissemination of headers.
- **Cordial Dissemination of Block Headers**
Even if multiple network routes are unavailable, a single functioning connection is sufficient to propagate block headers — without retries or request–response cycles.
This ensures deterministic and predictable commit performance.
- **Push-based Header Dissemination**
Block headers are propagated between validators by push rather than on-demand pull. Validators at the edge of the network — with long round-trip times or a single reliable peer — achieve stable p95 commit latency, because no chain of request–response round-trips is needed to assemble a block's history.
- **Linear Communication Cost for Transaction Data**
Transactions are encoded into shards using Reed–Solomon erasure coding. Nodes can reconstruct missing data from partial shards, removing redundant broadcasts and enabling scalable throughput.
- **Fault Tolerance**
The protocol tolerates up to one-third of validators by stake being offline, crashed, or actively misbehaving, without substantially impacting commit latency.
🔗 **Reference:** [Starfish Paper](https://eprint.iacr.org/2025/567)
---
## Epochs and Reconfiguration
## Epoch
In IOTA, an epoch is a fixed period (typically around 24 hours) during which the [validator set](./validator-committee.mdx) and their stakes remain constant. This stable period ensures that [transactions](../../developer/iota-101/transactions/transactions.mdx) are processed smoothly without unexpected validator changes.
## Epoch Numbering & Transaction Data
Epochs are sequentially numbered, and each transaction on the IOTA network includes an epoch identifier. While regular users generally do not need to worry about epochs, they are relevant when dealing with expiring transactions, which must be completed before a specific epoch ends.
## Consensus & Checkpoints
During each epoch, the Starfish consensus protocol operates to finalize transactions. Validators reach agreement by collecting transaction effect certificates, ensuring a consistent transaction order. A key part of this process is the checkpoint, which is a snapshot of finalized transactions at the end of an epoch. The checkpoint includes:
- A set of finalized transactions
- Validator agreement data
- State updates required for the next epoch
## Reconfiguration
At the end of each epoch, a reconfiguration process occurs to prepare the network for the next epoch. This involves the following.
### 1. Finalizing Transactions & Checkpoints
- Validators finalize the order of transactions and generate a checkpoint, ensuring a synchronized network state.
- This step guarantees that an honest majority of validators share the same transaction history, reinforcing consistency and security.
### 2. Distribution of Gas Rewards
- Computation gas fees are distributed to the validator staking reward pool.
- Stakers can withdraw their rewards after the epoch ends.
Refer to the [Staking and Rewards](./staking-rewards.mdx) page for more details.
### 3. Validator Set Updates
- Any pending staking and unstaking requests are processed.
- The validator set is updated—new validators may be added, and inactive ones may be removed.
- Since staking influences validator selection, it is only processed at epoch transitions.
### 4. Protocol Upgrades (Optional)
:::info
In Byzantine Fault Tolerant (BFT) `f` represents the number of faulty validators. `2f+1` represents the minimum number of validators
needed to agree on a transaction to ensure integrity and finality, even if up to `f` validators are faulty.
For example, if `f = 1`, this means 3 validators must confirm a transaction (a supermajority) to guarantee its
integrity,
ensuring that even if one validator is faulty, the correct decision still stands.
:::
- If 2f+1 validators (a Byzantine Fault Tolerant supermajority) agree, the network may upgrade to a new protocol version.
- These upgrades may include:
- Security patches
- New protocol features
- Updates to the IOTA Move framework
Refer to the [Protocol Upgrades](./protocol-upgrades.mdx) page for details.
---
## IOTA Architecture
import ThemedImage from '@theme/ThemedImage';
IOTA shares some similarities with traditional blockchains but is unique in many ways. Use the topics in this section to understand the features that define the IOTA network.
## Understand IOTA Security
Learn about the mechanisms available to secure on-chain assets, and the assurances IOTA provides regarding asset security. "Understand IOTA Security" explores the overall IOTA security architecture, to ensure the asset types you design leverage IOTA to provide a secure experience for asset holders.
Go to [Understand IOTA Security](iota-security.mdx).
## Life of a Transaction
"Life of a Transaction" details the transitions that all transactions on IOTA go through from creation to finality. This topic also explores some features of the blockchain (like epochs and checkpoints) that play a role in the life of a transaction.
Go to [Life of a Transaction](transaction-lifecycle.mdx).
## Consensus
Every transaction on IOTA that touches a shared object must go through a consensus process. This is to ensure that all nodes in the network agree on which transactions should be allowed to modify the ledger state.
IOTA uses the [Starfish](https://eprint.iacr.org/2025/567) consensus algorithm, the successor of [Mysticeti](https://arxiv.org/pdf/2310.14821).
Go to [Consensus](consensus.mdx).
## Sequencing
Once consensus provides the set of transactions to be included in the ledger, they must be sequenced to determine their exact execution order. IOTA uses a unique sequencing algorithm aimed at maximizing throughput by leveraging concurrent processing capabilities.
Go to [Sequencing](sequencing.mdx).
## Protocol Upgrades
The IOTA protocol, framework, and execution engine are frequently extended to include new functionality and bug fixes. This functionality is added in the form of new code which is released to validator operators as part of our regular software releases. The IOTA protocol, however, requires a supermajority of validators to agree on those protocol upgrades.
Go to [Protocol Upgrades](protocol-upgrades.mdx).
## IOTA Architecture Diagram
The following diagram describes the architectural structure for IOTA's solution.
The core components are:
- [Execution Layer](../../developer/references/execution-architecture/execution-layer.mdx)
- [IOTA Node](../../operator/full-node/overview.mdx)
- [IOTA RPC](../../developer/references/iota-api.mdx)
- [IOTA CLI](../../developer/references/cli.mdx)
---
## Security
## Access to Assets
IOTA uses two key mechanisms to secure access to assets. First, the asset owner must cryptographically prove knowledge of their private key tied to their account address to use or transfer an asset. Thus, account keys must be securely stored and used. Second, access to assets, which are represented as Move objects in a smart contract, follows the object ownership model of the Move language. The Move VM enforces ownership rules and ensures that no bytecode execution can violate them. The only potential risks stem from logic errors within smart contracts. Once a transaction reaches consensus and is committed to the ledger, any modified or created assets are persistently updated and available for further use.
:::tip Validator Selection
The set of validators changes periodically and is [determined by the amount of locked and delegated IOTAs held](../tokenomics/validators-staking.mdx).
:::
### Delegated PoS Consensus Mechanism
IOTA employs a delegated Proof-of-Stake (dPoS) mechanism to select validators (nodes that help secure and operate the network) for each epoch. Users can lock and delegate their IOTA tokens to validators, granting them voting power. Validators are chosen based on the number of delegated tokens, and any node with sufficient support can become a validator.
## Validators and Consensus Protocol
The IOTA [consensus protocol](./consensus.mdx) is run by a set of independent [validators](../tokenomics/validators-staking.mdx). All validators follow the same protocol and participate in transaction validation, using their delegated voting power to reach consensus. The consensus protocol produces a consistently ordered stream of transactions, ensuring system reliability and security. It is designed to be Byzantine fault tolerant (BFT), meaning transactions will still be processed even if up to one-third of validators attempt to disrupt execution or violate protocol guarantees.
Additionally, all transactions in IOTA are publicly available and auditable to verify that asset modifications are correctly executed.
### Rewards for Validators and Stakers
Validators receive incentives through a fixed inflation of 767,000 IOTA tokens per epoch. These tokens are distributed to validators and their delegators based on specific rules, such as the validator's commission rate and total stake. Transaction fees are burned and do not contribute to validator rewards. Staked tokens remain secure and cannot be seized by validators or other participants. For more details, refer to the [staking and rewards](./staking-rewards.mdx) documentation.
## Addresses and Keys
To access and manage assets on IOTA, users must hold the corresponding private key. This key must be kept secret, as even a majority of malicious validators cannot access assets without it.
Each private key corresponds to a public address on the IOTA network. Users can generate multiple addresses, and sending an asset to an address automatically creates it. Since transactions are irreversible once they reach finality, users should always verify recipient addresses before sending assets.
## Asset Types and Logic
The type and logic of any asset on the IOTA network are defined within smart contracts. While some core contracts are embedded in the protocol, most smart contracts are developed externally. IOTA smart contracts are immutable, allowing for third-party audits and preventing post-deployment modifications.
The Move language enforces strong security guarantees by integrating asset security and smart contract verification at its core. Additionally, Move's capability objects provide a robust mechanism for defining access control and permissioned asset usage.
### Shared Assets
Move allows for shared assets that, while publicly accessible, can have restricted usage enforced by the defining smart contract. Developers can specify which addresses have permission to interact with shared assets.
## Transaction Finality
### Certification and Finalization
When a transaction is submitted in IOTA, validators must collectively agree on its validity. Once agreement is reached, they issue a cryptographic _certificate_ confirming its correctness. Even if some validators act maliciously, the transaction can still be finalized by a supermajority of honest validators. This ensures that transactions cannot be invalidated or blocked by a small group of malicious actors.
### Gas and Transaction Execution
Every transaction incurs a gas fee for computational processing. A transaction either executes successfully or fails. Failures can result from smart contract errors or insufficient gas. If a transaction succeeds, its effects are permanently recorded on the IOTA network. If it fails, no changes occur, but some gas fees are still deducted to mitigate spam attacks. For more details, see the [gas and gas fees](../tokenomics/gas-pricing.mdx) documentation.
### Submitting Transactions
Users can submit transactions directly or use third-party services. These services cannot generate transactions on behalf of users since they do not have access to private keys. However, they can confirm transaction finalization by collecting validator signatures. A transaction is considered final once it has accumulated sufficient validator signatures, ensuring its irreversibility.
## Auditing and Privacy
### Reading Assets and Transaction History
IOTA full nodes provide access to asset balances and transaction histories. Validators generate cryptographic proofs verifying every transaction that contributed to an asset’s current state. Users can request and verify these proofs to ensure all transactions were correctly executed and consensus was followed.
### Public Auditability
All transactions and assets on IOTA are publicly viewable, ensuring auditability. However, users can maintain pseudonymity by utilizing multiple addresses. Third-party custodial services can further enhance privacy by managing assets on behalf of users. Additionally, privacy-preserving smart contracts can be developed to add extra confidentiality layers.
---
## Protocol Upgrades
The IOTA protocol, framework, and execution engine are frequently updated to introduce new features and bug fixes. These updates are released as part of regular software updates for validator operators. However, since all validators must agree on the results of each transaction execution, introducing changes to transaction execution presents a challenge.
- How to ensure that all validators upgrade their software in a coordinated manner?
- How to ensure that the transaction history remains consistent and replayable despite protocol changes?
IOTA addresses these challenges through a structured **protocol upgrade** process.
## Protocol Upgrade Process
### Protocol Versioning
Validators run the `iota-node` software, which supports multiple protocol versions, including future versions. The protocol version is determined by the `ProtocolConfig` struct. Validators that do not support the current protocol version cannot participate in consensus.
The protocol version to be executed in the next epoch is recorded on-chain in a special end-of-epoch transaction. This ensures that all validators switch to the new protocol version at the same time.
### Upgrade Steps
1. **Implementation**: IOTA developers introduce a new protocol version by updating the `ProtocolConfig` struct with properties and values, which may include feature flags to control specific functionalities within the new version.
2. **Software Release**: A new `iota-node` binary is released, and validators update their software. After restarting, validators continue to run the previous protocol version until the upgrade is activated.
3. **Upgrade Signaling**: Upgraded validators signal their readiness to switch to the new protocol version. This is done through consensus among the validator committee.
4. **Consensus and Activation**: If enough validators agree to switch, the new protocol version is recorded on-chain at the end of the current epoch. The next epoch then executes using the upgraded protocol version.
Full nodes follow a similar process but do not participate in voting. Instead, they synchronize with validators to ensure they execute transactions using the correct protocol version.
## IOTA Move Framework Upgrades
The **IOTA Move Framework** is a collection of system smart contracts built into the validator binary. These contracts provide essential functionalities, such as native functions for smart contracts.
The upgrade process for the IOTA Move Framework follows a similar structure to protocol upgrades:
1. **Framework Update in Software**: IOTA developers introduce changes to the IOTA Move Framework within the validator binary.
2. **Software Release and Validator Updates**: A new iota-node binary containing the updated framework is released. Validators update their software but continue using the existing framework until the upgrade is activated.
3. **Upgrade Signaling**: If a validator detects that its built-in framework differs from the framework stored on-chain (object 0x2), it signals its intent to upgrade.
4. **Consensus and Activation**: Once enough validators agree, the new framework version is written to object 0x2 at the end of the epoch. The next epoch then executes using the updated framework.
---
## Sequencing on IOTA
# Sequencing
Sequencing is the post-consensus phase in which transactions agreed upon by the IOTA [consensus protocol](./consensus.mdx) are processed and scheduled for execution.
Due to the nature of [shared objects](../../developer/iota-101/objects/object-ownership/shared.mdx), conflicting transactions writing to the same shared objects must be executed sequentially.
If not carefully managed, scheduling a large number of such conflicting transactions can lead to congestion during execution.
The primary goal of sequencing is to schedule as many transactions as possible while avoiding an unmanageable load on the execution layer.
The sequencing phase is responsible for two main tasks:
- **Ordering**: Establishing the causal order of transactions committed by the IOTA [consensus protocol](./consensus.mdx).
- **Congestion prevention**: Deferring the execution of transactions that could otherwise overwhelm the execution layer.
The IOTA sequencing algorithm addresses both of these tasks simultaneously.
## Sequencing Algorithm
In IOTA, transactions are initially ordered based on their gas prices.
Each transaction is then evaluated individually using the placement algorithm described below to determine its position in the execution trace.
During this evaluation, every transaction is subject to a binary decision: **Schedule** or **Defer**.
- **Deferred** transactions are carried over to the transaction set of the next consensus commit. If a transaction is deferred a specific number of times (currently 10), is it eventually **cancelled**.
- **Scheduled** transactions are forwarded to the execution phase in the order determined by the placement algorithm.
:::info Best-effort sequencing
In the IOTA sequencing algorithm, a transaction is deferred only if there is no way to schedule it without exceeding the load threshold on any individual execution worker.
:::
## Placement algorithm: Causal ordering of transactions
The IOTA sequencing algorithm orders transactions with a strong emphasis on execution efficiency.
When a transaction is evaluated, the algorithm searches for a suitable position in the execution trace where it can be placed without causing conflicts.
This allows for parallel execution of transactions that operate on disjoint sets of shared objects.
To achieve this, the algorithm maintains an allocation map that tracks access to shared objects.
This ensures that no shared object is written to by more than one transaction at the same time, preserving execution safety.
Once all transactions have been evaluated, the allocation map implicitly defines the causal ordering of the scheduled transactions.
The sequencing algorithm guarantees that the longest sequential execution trace remains within a predefined load threshold.
:::info Fairness in sequencing
In IOTA, transactions included in the same consensus commit that write to an identical set of shared objects are guaranteed to be executed in descending order of their gas prices.
:::
### Example
In the example below, we consider three transactions:
- `Tx1` touches only object `a`,
- `Tx3` touches only object `b`,
- `Tx2` touches both objects `a` and `b`.
`Tx1` is willing to pay the highest gas price, while `Tx3` offers the lowest.
Additionally, `Tx2` is _estimated_ to have the longest execution time, while `Tx3` has the shortest.
In the figure below, the length of the transactions depict their execution time.

A naive sequencing of these transactions based solely on gas price would result in a serial execution, since `Tx2` would have to wait for `Tx1` to complete (due to their shared access to object `a`), and `Tx3` would need to wait for `Tx2` (due to shared access to `b`).
As a result, all transactions would be executed one after another.
Instead, IOTA's sequencing algorithm carefully places `Tx3` before `Tx2` in the causal order. This enables simultaneous execution of `Tx1` and `Tx3` (which access disjoint objects), provided that there are sufficient parallel resources.
The case is illustrated in the following image.

## Gas Price Feedback for Cancelled Transactions
When a transaction is cancelled due to shared object congestion, IOTA provides
a **suggested gas price** in the execution status of that cancelled transaction.
This suggested gas price informs the sender about the minimum gas price they
should have paid for their transaction to have been successfully scheduled in
the _same_ consensus commit.
Other networks such as Sui only report which shared objects were congested, but
not what gas price would have been enough for successful execution. Users on
those networks have to rely on dry-run simulations to figure out a sufficient
gas price. The IOTA protocol instead provides gas price feedback based on the
actual scheduling decisions in the latest commits, which helps the sender
estimate a sufficient gas price for a retry.
### How the suggested gas price is calculated
- The gas price feedback algorithm simulates the allocation of the
cancelled transaction at the latest possible execution start time within the
commit's capacity, so that only the last scheduled transactions on each
congested object overlap with it.
- The clearing gas price for each object is the maximum gas price across those
last scheduled transactions that overlap with the simulated allocation of the
cancelled transaction.
- The suggested gas price is then calculated as the maximum clearing gas price
across all input objects of the cancelled transaction plus one, ensuring
that it would outbid competing transactions and get scheduled.
- The suggested gas price value is capped at the protocol's maximum gas price.
### Using the suggested gas price
The sender can then retry the cancelled transaction with a gas price equal to
or greater than the suggested value.
:::note Suggested gas price is an estimate
If the same congestion pattern repeats in a future commit, paying the suggested
gas price guarantees scheduling. In practice, congestion changes between
commits, so the suggested value should be considered as a good starting
estimate but not as a hard guarantee to be scheduled. For better price estimate,
please refer to [gas price prediction during dry run](../tokenomics/gas-pricing.mdx#gas-price-prediction).
:::
---
## Staking and Rewards
IOTA uses a [Delegated Proof-of-Stake (DPoS)](../tokenomics/proof-of-stake.mdx) system, where [validators](../tokenomics/validators-staking.mdx) get their
voting power from IOTA token holders who delegate their stakes to them.
When rewards are distributed at the end of each [epoch](epochs.mdx),
validators receive their [rewards](#rewards-distribution) based on their [performance](#performance)
and [commission rate](#commission-rate).
The rewards automatically increase as validators' staking pools receive new delegated stakes.
## Staking on IOTA vs. Other Blockchains
The IOTA staking mechanism has some unique features compared to other blockchains.
### Self-custodial Staking
Stakers keep their staked IOTA tokens in their own account.
### Auto-compounding Rewards
Rewards automatically reinvest due to a liquidity-pool-inspired design.
### Staking Timing
When a user stakes with a validator, their stake counts towards the validator's voting power starting from the next
epoch. Similarly, when a user withdraws their stake, it stops counting from the next epoch.
## Validator Staking Pool Requirements
There are minimum staking requirements a validator must satisfy to become active and to stay in the active validator set.
More precisely:
- A validator candidate must accrue at least 2M IOTA of stake before they can request to join the validator set.
- If an active validator’s stake falls below 1.5M IOTA, the validator has seven epochs of grace period to gain back the stake before being removed from the validator set.
- If an active validator’s stake falls below 1M IOTA, the validator is removed from the validator set at the end of the current epoch boundary.
IOTA uses 24-hour epochs.
## Rewards Distribution
At the end of each [epoch](epochs.mdx), newly minted IOTA tokens are distributed as rewards among validators and stakers. Within each [validator staking](../tokenomics/validators-staking.mdx) pool, stakers receive rewards proportionally through the appreciation of the pool's exchange rate. Validators also earn additional rewards, represented as StakedIOTA objects, which they receive at the end of each epoch in proportion to the commissions generated by their staking pool.
Each epoch's rewards are funded by newly minted IOTA tokens, totaling 767k IOTA per epoch. This amount is distributed across staking pools based on their voting power and the specified tallying rule. The amount of rewards a validator gets depends on.
:::tip Validator Selection
Refer to the [Proof-of-Stake](../tokenomics/proof-of-stake.mdx) page to learn how validators are selected for transaction processing and the underlying economic model.
:::
### Performance
If a validator underperforms, other validators can report them, causing the reported validator to lose all their rewards
for that epoch.
### Commission Rate
This is the percentage a validator takes from their stakers' rewards.
For example, if a validator's commission rate is 10%, they take 10% of the rewards each epoch as new stake objects.
### Rewards Withdrawal
Validators receive rewards as regular stake objects, so they withdraw their staking rewards the same way as stakers.
Validators can call
the [`0x3::iota_system::request_withdraw_stake`](https://github.com/iotaledger/iota/blob/develop/crates/iota-framework/packages/iota-system/sources/iota_system.move#L260)
function to withdraw their stake and receive their rewards.
---
## Transaction Life Cycle
import ThemedImage from '@theme/ThemedImage';
# Transaction Life Cycle
## High-level Overview
## Understanding the Transaction Lifecycle in IOTA
The IOTA transaction lifecycle outlines the journey of a transaction from its creation by a user to its final settlement and recording on the ledger. This process involves client applications, full nodes, and validators, ensuring secure and consistent state transitions across the network.
### 1. Make Transaction
A user or smart contract initiates a transaction through a wallet or application. This transaction can affect objects owned exclusively by the user (owned objects) or objects that multiple users can interact with ([shared objects](../../developer/iota-101/objects/object-ownership/shared.mdx)). The transaction typically includes:
- Sender and recipient addresses
- Value or assets to transfer
- Timestamp and nonce
- Digital signature (using the user's private key)
The wallet application signs the transaction with the user's private key, ensuring its authenticity and integrity.
### 2. Process Transaction
Once created and signed, the transaction is submitted to a full node. The full node performs an initial validation of the transaction structure and checks for sufficient account balance. It then distributes the transaction to validators in the network.
Validators independently verify the transaction's validity. If deemed valid, they sign it and return the signed transaction to the full node.
### 3. Assemble Certificate
After collecting signed responses from a supermajority of validators, the client assembles these responses into a transaction _certificate_. This step is crucial as it ensures that the transaction has been pre-approved by a sufficient number of validators before proceeding to consensus. Unlike traditional consensus-based blockchains, the client or gateway is responsible for propagating signatures and aggregating certificates, reducing the burden on validators.
The client sends the assembled _certificate_ back to all validators. Upon receipt, validators verify the certificate's integrity and acknowledge its receipt. They then forward the _certificate_ to the IOTA DAG-based consensus protocol.
If the transaction involves only owned objects, IOTA can process and execute it immediately without waiting for global consensus, leveraging **fast path consensus**.
### 4. Sequence
All certificates, regardless of whether they involve **owned** or **shared objects**, are forwarded to the IOTA DAG-based consensus protocol. This protocol eventually produces a total order of certificates. Validators then verify and execute transactions that involve shared objects, ensuring deterministic and consistent state transitions across all nodes.
### 5. Process Certificate
Certified transactions are then sent to validators for execution. Validators verify the certificate signatures to ensure the transaction is valid and not attempting to double-spend.
Depending on whether the transaction uses shared input objects, the validators will either:
- Execute it immediately if no shared objects are involved.
- Submit it to IOTA's consensus layer to order the transaction with others if shared objects are involved, and then execute it.
This ensures that transactions involving shared objects are consistently ordered across validators, preventing conflicts.
### 6. Assemble Effect Certificate
After the transaction has been executed, clients can gather responses from a supermajority of validators again. These responses are then assembled into an effect _certificate_. This certificate serves as proof that the transaction has been fully executed, providing evidence of settlement finality and a guarantee that the transaction will be recorded in a checkpoint.
### 7. Checkpoint Certificate
IOTA periodically creates checkpoints during consensus commits. These checkpoints record the finalized transaction state, providing a stable point of reference. They are also used to drive the validator reconfiguration protocol, supporting epoch transitions and validator set changes.
## Epoch Transitions and Their Impact
The IOTA network undergoes [epoch](./epochs.mdx) transitions, which can affect how transactions are handled. Near epoch boundaries, transactions might occasionally need to be resubmitted. Generally, full nodes handle resubmission, though some client applications may automate this process. As a best practice, it's advisable to avoid submitting time-sensitive transactions immediately before epoch transitions.
## Verifying Finality
If your wallet app crashes during a transaction, it stores the signed transaction locally. Upon restarting, it will verify if the transaction was finalized. If finalized, no further steps are required. If not, the app will need to resubmit the transaction.
The wallet app can query the full node with the getTransactionBlock method to check if the transaction is finalized. If the response contains transaction details, it is finalized. If the response is None, the transaction may need to be resubmitted. This ensures that the coffee shop's full node will eventually recognize the transaction once it's included in a checkpoint and update the coffee shop's balance.
---
## Validator Committee
A set of independent validators participate on the IOTA network, each running its own instance of the IOTA software on a dedicated machine or virtual server. Each validator handles read and write requests sent by clients, verifying transactions and updating on-chain information.
To learn how to set up and run an IOTA validator node, including how staking and rewards work, see [IOTA Validator Node Configuration](../../operator/validator-node/configuration.mdx).
IOTA uses Delegated Proof-of-Stake (DPoS) to determine which validators operate the network and their voting power. Validators are incentivized to participate in good faith via staking rewards, which are slashed in case of misbehavior.
## Epochs
Operation of the IOTA network is temporally partitioned into non-overlapping, approximate fixed-duration (~24-hour) epochs. During a particular epoch, the set of validators participating in the network and their voting power is fixed. At an epoch boundary, reconfiguration might occur and can change the set of validators participating in the network and their voting power. Conceptually, reconfiguration starts a new instance of the IOTA protocol with the previous epoch's final state as [genesis](../../operator/common/genesis.mdx) and the new set of validators as the operators. Besides validator set changes, tokenomics operations such as staking/un-staking, and distribution of staking rewards are also processed at epoch boundaries.
## Quorums
A quorum is a set of validators whose combined voting power is greater than two-thirds (>2/3) of the total during a particular epoch. For example, in an IOTA instance operated by four validators that all have the same voting power, any group containing three validators is a quorum.
The quorum size of >2/3 ensures Byzantine fault tolerance (BFT). A validator commits a transaction (durably store the transaction and update its internal state with the effects of the transaction) only if it is accompanied by cryptographic signatures from a quorum. IOTA calls the combination of the transaction and the quorum signatures on its bytes a _certificate_. The policy of committing only _certificates_ ensures Byzantine fault tolerance: if >2/3 of the validators faithfully follow the protocol, they are guaranteed to eventually agree on both the set of committed _certificates_ and their effects.
## Write requests
A validator can handle two types of write requests: transactions and _certificates_. At a high level, a client:
- Communicates a transaction to a quorum of validators to collect the signatures required to form a _certificate_.
- Submits a _certificate_ to a validator to commit state changes on that validator.
### Transactions
When a validator receives a transaction from a client, it first performs transaction validity checks (validity of the sender's signature). If the checks pass, the validator locks all owned-objects and signs the transaction bytes, then returns the signature to the client. The client repeats this process with multiple validators until it has collected signatures on its transaction from a quorum, thereby forming a _certificate_.
The process of collecting validator signatures on a transaction into a _certificate_ and the process of submitting _certificates_ can be performed in parallel. The client can simultaneously multicast transactions/_certificates_ to an arbitrary number of validators. Alternatively, a client can outsource either or both of these tasks to a third-party service provider. This provider must be trusted for liveness (it can refuse to form a _certificate_), but not for safety (it cannot change the effects of the transaction, and does not need the user's secret key).
### Certificates
After the client forms a _certificate_, it submits it to the validators, which perform _certificate_ validity checks. These checks ensure the signers are validators in the current epoch, and the signatures are cryptographically valid. If the checks pass, the validators execute the transaction inside the _certificate_. Execution of a transaction either succeeds and commits all of its effects or aborts and has no effect other than debiting the transaction's gas input. Some reasons a transaction might abort include an explicit abort instruction, a runtime error such as division by zero, or exceeding the maximum gas budget. Whether it succeeds or aborts, the validator durably stores the _certificate_ indexed by the hash of its inner transaction.
If a client collects a quorum of signatures on the effects of a transaction, the transaction is final. This means the effects will persist on the shared database and be permanently recorded in a checkpoint within a few seconds. The epoch boundary serves as an upper bound, but in practice, the effects certificate can be used immediately to prove finality, access results, and trigger new transactions. Clients may share the certificate directly with others or use a third-party service to help propagate it.
---
## IOTA Bounty Program
The IOTA Bounty Program connects the community with funded tasks that help improve the IOTA products and ecosystem.
[Terms & Conditions](/iota-bounty-program-terms-and-conditions) apply.
## Current Active Programs
Help us test and improve the new IOTA SDK supporting Rust, Go, Kotlin and Python.
All the rules and details on how to participate can be found on the project board by clicking on this card.
This program starts on February 16th for selected community members and will be open for everyone on the 2nd of March.
---
## IOTA Bounty Program Terms & Conditions
These Terms and Conditions (“Terms”) govern your participation in the IOTA Bounty Program (“Campaign”) operated by the IOTA Foundation (“we”, “us”, or “our”). By participating in the Campaign you confirm that you have read, understood, and agreed to these Terms.
**The Campaign is provided "as is" without any warranties of any kind, express or implied. We make no guarantees regarding availability, security, continuity, or outcomes of the Campaign. We disclaim all liability for any losses, delays, errors, or issues arising from your participation, including the non-receipt of rewards or technical disruptions. To the fullest extent permitted by law, our total liability is limited to the actual IOTA rewards distributed to you, if any. Participation is at your own risk, and no specific outcome or reward is guaranteed.**
## 1. Purpose of the Campaign
The IOTA Bounty Program offers participants the opportunity to improve the IOTA ecosystem and receive IOTA tokens as a reward for completing designated tasks. The program is managed and hosted on a dedicated GitHub Project board, which acts as the central hub for all available tasks. For details on currently active tasks, please consult the GitHub Project board.
## 2. Participation
Participate in the Campaign by:
1. **Choosing a Task:** Browse the open issues on the GitHub Project board and find a task that aligns with your skillset. Once you have chosen a task, add a comment to it asking for it to be assigned to you.
2. **Contributing and Submitting:** Work on the selected task and submit your contribution via the linked repository.
3. **Raising a New Issue:** At times, we may also invite IOTA community members to create new issues and link them to the board for others to work on.
## 3. Eligibility
All participants in the Campaign must:
* Be at least 18 years old or the age of legal majority in your jurisdiction or have the consent of your legal guardian to participate;
* Join the IOTA Builders Discord and have a valid GitHub account to submit content via the GitHub Project board;
* Have a valid IOTA wallet address to receive token rewards;
* Not be subject to any economic, trade, or financial sanctions.
We reserve the right to screen wallet addresses through third-party compliance tools for anti-money laundering, sanctions, abuse, or fraud prevention purposes. Wallets flagged during compliance screening may be disqualified from reward distribution without prior notice.
By participating in the Campaign, you confirm that you are not subject to any sanctions, including but not limited to sanctions imposed by the United Nations, the UK, the U.S., the EU, Switzerland or the UAE, and that there are no criminal or regulatory investigations, decisions or laws applicable to you that would prevent you from participating in the Campaign.
## 4. Selection and Rewards
A designated Bounty Committee (“Committee”) will review and evaluate all submissions.
Submissions are judged at the Committee’s sole discretion based on creativity, quality, relevance, and alignment with the task description. The Committee may choose to award full, partial, or no rewards. Rewards will be distributed in IOTA tokens. There is no guarantee of a reward, even if you make a submission. The reward will be distributed only after the submission has been deemed complete and satisfactory. The value of the reward may vary per bounty and is subject to change due to campaign parameters, technical issues, or budgetary constraints. The decisions of the Committee are final and cannot be appealed.
## 5. Content Moderation
We reserve the right to moderate, hide, edit, or remove any content submitted in connection with the Campaign, at our sole discretion and without prior notice, especially if it violates these Terms, the bounty guidelines, or community standards.
You agree to maintain an inclusive and welcoming environment and agree to abstain from submitting or otherwise distributing any content that could be construed as discriminatory, harassing, or unlawful.
## 6. Intellectual Property and Usage Rights
By submitting content as part of the Campaign, you confirm that:
* You are the original creator of the content and/or hold all necessary licenses and rights to submit the content;
* The content does not infringe any third-party rights, such as trademarks, copyright or related rights and that the content does not violate any applicable laws.
You grant us a worldwide, royalty-free, non-exclusive license to use, reproduce, modify, publish, and share your submission, including for promotional and community-building purposes, with credit where reasonably possible.
## 7. Disclaimer and Limitation of Liability
Participation in the Campaign, including the use of any third-party platforms such as the GitHub Project platform, is undertaken entirely at your own risk. We provide no warranty regarding the availability, functionality, or continuity of the Campaign, its technical infrastructure, the GitHub Project platform, or the reward distribution process. Specifically, no warranties (express or implied) are made concerning:
* Receipt or value of IOTA rewards;
* Platform uptime, reliability, or error-free operation;
* Freedom from bugs, exploits, or malicious activity.
To the fullest extent permitted by law, we disclaim all liability for:
* Loss or non-receipt of digital assets;
* Submission errors, platform malfunctions, or technical failures;
* Any incidental, indirect, special, or consequential damages arising from your participation in the Campaign.
Our total liability, if any, is limited to the actual reward amount distributed to you (if any). You agree to waive any claims against us, including under contract, tort, or statutory provisions.
## 8. Data Collection and Privacy
Participation in the Campaign requires the processing of certain personal data. By participating, you acknowledge that your data will be processed in accordance with the [Privacy Policy](https://www.iota.org/privacy-policy).
## 9. Governing Law and Jurisdiction
These Terms shall be governed by and construed in accordance with the laws of Germany, without regard to conflict of law principles. Any disputes shall be subject to the exclusive jurisdiction of courts located in Berlin, Germany.
## 10. Final Provisions
If any part of these Terms is held to be invalid or unenforceable, the remainder shall remain in full force and effect. These Terms constitute the entire agreement between you and us in relation to the Campaign. We reserve the right to modify, pause, or terminate the Campaign or any individual bounties at any time, and we reserve the right to amend these Terms at any time by publishing a new version of the Terms on the Campaign page. Continued participation after changes implies acceptance of the updated Terms.
---
## Gas Pricing and Transaction Fees
The IOTA gas pricing mechanism determines how transaction fees are computed and plays a central role in ensuring efficient network operation. It serves two primary objectives:
1. Delivering **low, predictable transaction fees**.
2. Preventing **denial-of-service (DoS) attacks**.
To achieve these goals, every IOTA transaction pays fees for **computation**, required to execute the transaction, and **storage**, required to persist data on-chain.
Hence, transaction fees decompose into:
`net gas fees = Computation fee + Storage fee − Storage rebate`
where:
- **Computation fee** = `computation_units * gas_price`
- **Storage fee (deposit)** = `storage_units * storage_price`
- **Storage rebate** is the amount refunded when previously stored data is deleted.
Equivalently, the total gas fees are:
`gas_fees = computation_units * gas_price + storage_units * storage_price - storage_rebate`
This formulation separates the cost of execution from the cost of storage, while ensuring that users only pay for the net storage they consume over time.
## Computation Fees
The computation fee captures the cost of executing a transaction:
`computation_fee = computation_units * gas_price`
### Computation Units
Different IOTA transactions require varying amounts of computational time for processing and execution. IOTA translates these varying operational loads into transaction fees by measuring each transaction in terms of _computation units_. In general, more complex transactions require more computation units.
Importantly, though, the IOTA computation gas schedule is built with a _bucketing/step approach_. Two reasonably similar transactions translate into the exact same amount of computation units if they are in the same bucket, whereas two relatively different transactions translate into different amounts of computation units if they fall in separate buckets. The smallest bucket maps into 1,000 computation units, meaning that all transactions that fall into the smallest bucket cost 1,000 computation units. The step between buckets is 1,000 and the largest bucket maps into 5,000,000 computation units; if a transaction requires more computation units, it aborts.
Using bucketing accomplishes two important goals:
- Frees users from optimizing their smart contracts to deliver marginal gains in gas costs via "gas golfing" — instead, they can focus on step-function improvements in their products and services.
- Gives users the freedom to adjust per-instruction gas costs and experiment with new gas metering schemes without creating significant development disruption. This can happen frequently, so it is important that they do not rely on per-instruction gas costs remaining stable over time.
### Gas Price
The gas price is specified by the user and must be at least a protocol-defined baseline:
`gas_price = reference_gas_price + tip`
- The **reference gas price** is defined by the protocol (currently set to 1,000 NANOS) and acts as a baseline for transaction inclusion. All transactions must pay at least this amount, and fees up to this level are burned.
- The **tip** is an optional additional fee paid by users to prioritize their transactions. Any amount above the reference gas price is transferred to validators as part of their rewards.
During normal network conditions, most transactions use the reference gas price with no tip, ensuring predictable and stable fees.
However, during periods of congestion, users can request an estimated minimum gas price for successful execution through a transaction dry run.
This estimation is computed using a [predictive gas pricing algorithm](#gas-price-prediction), which helps users determine an appropriate tip.
The algorithm leverages historical congestion data and dynamically adjusts weights for shared objects accessed by transactions using an online gradient descent method.
## Storage Fees
The storage fee captures the cost of storing data on-chain:
`storage_fee = storage_units * storage_price`
### Storage Units
Similarly, IOTA transactions vary depending on the amount of new data written into on-chain storage. The variable storage units capture these differences by mapping the number of bytes held in storage into _storage units_. The current IOTA schedule is linear and maps each byte into 100 storage units. So, for example, a transaction that stores 25 bytes costs 2,500 storage units, while a transaction that stores 75 bytes costs 7,500 units.
Importantly, in IOTA's storage model, users pay storage deposit fees for storing data in perpetuity but can also get a full rebate on previously stored data if that data is deleted. Hence, the amount of storage fees that users pay is 100% rebateable. This storage deposit mechanism incentivizes users to minimize the storage burden they place on all nodes by reducing their storage requirements and cleaning up unused objects.
### Storage Price
- The **storage price** is fixed and shared across all transactions. It is set through governance proposals and updated infrequently.
- Storage fees act as a **deposit**: users pay upfront for storing data, but receive a **100% rebate** when that data is deleted.
The storage price is set exogenously with the goal of targeting the real-world cost of data storage. Over time, governance can adjust this value to reflect changes in hardware costs and the market value of the IOTA token.
This design ensures that users internalize the long-term cost of storage while retaining strong incentives to minimize and clean up on-chain data.
## Gas Budgets
Every transaction on IOTA must include a **gas budget**, which sets the maximum amount the user is willing to pay for computation and storage.
The gas budget can be set between 1,000,000 NANOS (0.001 IOTA) and 50,000,000,000 NANOS (50 IOTA). This range protects the network against spam and denial-of-service attacks.
Transactions are successfully executed if:
`gas_budget >= max{computation_fees, net_gas_fees}`
If the gas budget does not satisfy this condition, the transaction fails and a portion of the gas budget is charged. The charging rules are as follows:
- If the **gas budget is insufficient to cover both computation fees and storage fees**, then the **entire gas budget** is charged.
- If the **gas budget is sufficient for computation fees** but **not enough for net gas fees**, then a portion of the gas budget is charged corresponding to:
- the computation fees, and
- the fees associated with mutating the transaction's input objects.
Ultimately, a successful transaction requires the end user to pay the transaction's **net gas fees**.
However, since it is difficult to perfectly forecast computation time before the transaction is processed, the gas budget must also **cover at least the computation fees** in case the transaction aborts.
Additionally, in some cases — especially when there are **high storage rebates** leading to **negative net storage fees** — the total gas fees the user pays (`net_gas_fees`) might be **lower than the computation fees**.
As mentioned previously, the **storage rebate is 100%** of the originally paid storage fees. This mechanism ensures that users are reimbursed for previously stored data that is deleted, which encourages efficient use of on-chain storage.
### Examples
The following table provides examples of gas accounting on the IOTA network.
- In the first two and last two rows, computation units are the same because transactions fall within the same bucket.
- The last two transactions are more complex than the first two, so they fall into a higher computation bucket.
- In the last transaction, the storage rebate is large enough to fully offset the transaction gas fees, effectively giving the user a positive net balance.
These examples highlight the importance of the gas budget:
- The minimum gas budget is the smallest amount a transaction can specify to execute successfully.
- When there is a storage rebate, the minimum gas budget is often larger than the net gas fees a user ultimately pays.
- This is particularly evident in the last example, where the user receives a positive amount back after executing the transaction, because the minimum gas budget must still cover the computation fees.
| | Reference Gas Price | Computation Units | Storage Price | Storage Units | Storage Rebate | Minimum Gas Budget | Net Gas Fees |
| ------------------------------------------------------- | ----------------- | ---------------- | ------------- | ------------- | --------------- | ---------------- | --------------- |
| Simple transaction storing 10 bytes | 1,000 NANOS | 1,000 | 75 NANOS | 1,000 | 0 NANOS | 1,075,000 NANOS | 1,075,000 NANOS |
| Simple transaction storing 10 bytes and deleting data | 500 NANOS | 1,000 | 75 NANOS | 1,000 | 100,000 NANOS | 500,000 NANOS | 475,000 NANOS |
| Complex transaction storing 120 bytes | 1,000 NANOS | 5,000 | 200 NANOS | 12,000 | 0 NANOS | 7,400,000 NANOS | 7,400,000 NANOS |
| Complex transaction storing 120 bytes and deleting data | 500 NANOS | 5,000 | 200 NANOS | 12,000 | 5,000,000 NANOS | 2,500,000 NANOS | -100,000 NANOS |
## Gas Price Prediction During Dry Run {#gas-price-prediction}
When you execute a **dry run** or **dev inspect** transaction, the IOTA network provides a `suggested_gas_price` in the response.
This value helps users estimate an appropriate gas price for transactions that interact with shared objects, particularly during periods of network congestion.
:::info When to Use It
If your transaction touches popular shared objects (e.g., a DEX pool), the suggested gas price reflects the current level of congestion on those objects and helps reduce the probability that the transaction will be cancelled.
For transactions that only use owned objects, no additional tip is required.
:::
The network maintains a **congestion tracker** that monitors shared-object access patterns across checkpoints.
For each mutable shared object, the tracker computes a _hotness_ value that reflects how congested that object is based on recent transaction history.
This hotness value is updated using an online gradient-descent-based mechanism driven by checkpoint statistics (e.g., cancelled transactions, successfully scheduled transactions).
During a dry run, the suggested gas price is calculated as:
`suggested_gas_price = reference_gas_price + max_hotness`
where `max_hotness` is the highest hotness value among all mutable shared objects accessed by the transaction.
If the transaction does not access any tracked shared objects, the suggested gas price falls back to the current `reference_gas_price`.
By using the `suggested_gas_price` from a dry-run response, users can adapt their gas price to current network conditions.
This reduces the risk of underbidding during congestion while avoiding unnecessary overpayment during periods of low activity.
---
## IOTA Token
The native asset on IOTA is called **IOTA**.
At the launch of IOTA Rebased, **4,600,000,000** IOTA tokens were migrated from the previous network called _Stardust_.
**767,000** new IOTA tokens are minted each epoch. As a result, IOTA has no fixed maximum supply — the total supply fluctuates over time based on the balance between token inflation and fee burning.
:::info Decimals
The number of decimals for the IOTA token has changed from **6** to **9** with this release: any balance from the Stardust network has been migrated and multiplied by 1,000 to accommodate.
:::
The IOTA token serves four purposes on the IOTA network:
- **Staking:** You can stake IOTA to participate in the delegated proof-of-stake mechanism.
- **Transaction Fees:** IOTA is the asset denomination needed to pay the gas fees required to execute transactions and store created data on chain or process other operations on the IOTA network.
- **Value transfers:** IOTA can be used as a versatile and liquid asset for various applications, including the standard features of money — a unit of account, a medium of exchange, or a store of value — and more complex functionality enabled by smart contracts, interoperability, and composability across the IOTA ecosystem.
- **Governance:** IOTA tokens play an important role in governance by acting as a right to participate in on-chain voting on issues such as protocol upgrades.
All original IOTA Tokens are represented as the `0x2::iota::IOTA` type of object on IOTA, accessible on the same (Hex format) addresses from the Stardust-based network. No manual migration is needed to access these tokens.
---
## Delegated Proof of Stake
The IOTA platform relies on _delegated proof-of-stake_ (DPoS) to determine the set of validators that process transactions.
## IOTA Token Staking
Within each epoch, all operations on the IOTA network processed by a fixed set of validators, each with a specific amount of stake from IOTA token holders.
A validator's share of total stake is relevant in that it determines each validator's share of voting power for processing transactions.
Staking IOTA implies that the staked IOTA tokens are locked for the entire epoch.
IOTA token holders are free to withdraw their IOTA or to change their selected validator when the epoch changes.
## Economic Model
This section covers how the different components of the IOTA economy interact with each other to introduce the IOTA DPoS system.
For reference, see the Staking and Tokenomics diagram in the [IOTA Tokenomics](./tokenomics.mdx) overview.
The IOTA economic model works as follows.
At the beginning of each epoch, the delegated tokens for a given validator are added up, and a new [validator committee](../iota-architecture/validator-committee.mdx) is formed.
Following this action, the protocol computes the total amount of stake as the sum of staked IOTA.
During each epoch, users submit transactions to the IOTA platform and validators process them.
For each transaction, users pay the associated computation fees, the storage deposit and, optionally, a tip for prioritization.
In cases where users delete previous objects or data within objects, users obtain a rebate of their storage deposit.
Validators observe the behavior of other validators and evaluate each other's performance.
At the end of each epoch, the protocol distributes stake rewards to participants of the DPoS mechanism.
This occurs through three main steps:
- The total amount of stake rewards is calculated. The stake rewards are composed of a validator subsidy, which is currently set as 767,000 IOTA tokens per epoch, plus any tips from user transactions.
- The total amount of stake rewards is distributed across various pools, proportionally to their stake and adjusted by validators' performance.
- Each pool's amount of rewards is distributed between the validator and the other parties. Validators first keep a commission $$\delta_v$$ (maximum 20%) of the total pool rewards as a fee to cover their costs. The rest of the rewards (i.e., after discounting the validator's commission) is distributed among all users (including the validator) proportionally to their stake.
To mitigate stake centralization, the protocol enforces a dynamic minimum commission based on each validator’s voting power (VP%).
In particular, the effective commission applied during an epoch is set to the maximum between the validator’s chosen commission and its VP%.
This prevents large validators from attracting disproportionate stake through very low fees, while preserving flexibility for smaller validators and maintaining a balanced, competitive staking ecosystem.
Finally, let $$\beta_v$$ represent the share of stake managed by a validator $$v$$ that is owned by itself, while $$(1-\beta_v)$$ represents the share owned by third-party stakers.
The rewards for users of validator's $$v$$ staking pool and for the validator $$v$$ itself equal:
$$
UserStakeRewards_v \ = (1-\delta_v) \times (1-\beta_v) \times \mu_v \times \sigma_v \times TotalStakeRewards,
$$
$$
ValidatorRewards_v \ = \ \Big(\beta_v + \delta_v \times (1-\beta_v)\Big) \times \mu_v \times \sigma_v \times TotalStakeRewards.
$$
### Tallying Rule
The $$\mu_v$$ variable is used to incentivize validators to process transactions efficiently.
Throughout each epoch, validators observe the behavior of other validators and evaluate their performance.
This information is used in the _tallying rule_, whereby each validator assigns performance multipliers to others based on observed behavior.
At the end of the epoch, these evaluations are aggregated into a global performance factor $$\mu_v$$ for each validator which directly affects each validator’s share of staking rewards:
- Validators that operate efficiently at the reference gas price receive full rewards ($$\mu_v = 1$$).
- Validators that deviate or perform poorly receive reduced rewards ($$\mu_v < 1$$).
This variable ensures that validators have incurred monetary risk and therefore are incentivized to operate the IOTA network efficiently.
The $$\sigma_v$$ parameter captures each pool's share of total stake.
Consequently, validators with more stake earn more stake rewards and the joint $$\mu_v\sigma_v$$ term incentivizes validators to increase their share of the stake while also operating the network performantly.
In the long-run, this incentive encourages users to shift the stake distribution towards the network's most efficient validators.
---
## Staking and Unstaking
IOTA uses a Delegated-Proof-of-Stake (DPoS) system to secure and operate the network, meaning that the voting power of a validator in the network is determined by the amount of stake delegated to them by IOTA token holders. The more stake delegated to a validator, the more voting power they have. In exchange for processing transactions and performing consensus, validators earn rewards based on a given IOTA inflation rate. These rewards are then shared among stakers as staking rewards.
## Staking
You stake your IOTA tokens by sending a transaction to the network that calls the staking function implemented as part of the system Move package. This transaction wraps the IOTA tokens in a self-custodial stake object. This stake object contains such information as the validator staking pool ID and the activation epoch of the stake.
IOTA-compatible crypto wallets typically have functionality to initiate staking and unstaking from your IOTA address. See the respective documentation for these tools to begin staking your IOTA.
## Unstaking
Similar to staking, a user withdraws their stake from a validator by sending a transaction that calls the unstaking function in the system Move package. This transaction unwraps the stake object, and sends both the principal and the accumulated rewards to the user as IOTA tokens. You accrue rewards only during epochs where the stake is active for the entire epoch. The rewards withdrawn from the validator's rewards pool are calculated based on the activation epoch and unstaking epoch of the stake.
## Choosing a validator for staking
When you stake on IOTA, you have to choose a specific validator you would like to stake with. The choice of validator can potentially impact the amount of staking rewards you receive. The factors determining this amount include, but are not limited to:
- _Validator commission rate_: a validator can set a non-zero commission rate specifying the percentage of staking rewards they are taking from the stakers. For example, if a validator has a commission rate of 10%, then 10% of every staker's staking rewards is given to the validator. Note that a validator can change its commission at a future moment in time without prior notice.
- _Validator performance_: a validator with bad performance might be punished according to the [tallying rule](./proof-of-stake.mdx#tallying-rule). Punished validators receive only a fraction of staking rewards for the epoch during which they are punished, and you also will receive a fraction of that epoch's rewards when you withdraw your stake from that validator.
IOTA-compatible crypto wallets and explorers typically provide validator information such as commission and APY. See the respective documentation for these tools for information on how to retrieve this data.
---
## IOTA Tokenomics
import ThemedImage from '@theme/ThemedImage';
Tokenomics refers to the various concepts that shape the science and behavior of blockchain economies. In basic terms, **tokenomics** is the financial foundation of blockchains. Much the same way a building with a poor foundation is doomed to fail, a blockchain without a well-researched, extensively planned, and painstakingly implemented token economy eventually crumbles.
IOTA tokenomics is based on sound financial concepts confirmed by extensive blockchain research. Designed for scale, the IOTA tokenomics structure is intended to support the financial needs of Web3 now and in the future.
## The Actors in the IOTA Economy
Three main types of participants characterize the IOTA economy:
- **Users** submit transactions to the IOTA platform to create, mutate, and transfer digital assets or interact with more sophisticated applications enabled by smart contracts, interoperability, and composability.
- **Validators** manage transaction processing and execution on the IOTA platform.
- **Delegators** are IOTA token holders who choose to delegate their tokens to validators to participate in the proof-of-stake mechanism. By holding IOTA tokens, they also gain the right to participate in the network’s governance.
## Tokenomics Overview
The following flowchart provides a high-level overview of the monetary flow within the IOTA's tokenomics. At its core, the IOTA economy is driven by the [IOTA token](iota-token.mdx), the native asset of the IOTA ecosystem.
When users submit transactions, they incur gas fees to pay for computation. A portion of this computation fee is burned to mitigate token inflation and users can include an optional tip to incentivize validators for faster processing during network congestion.
In addition to the tips from users, staking rewards also include a validator subsidy. This subsidy of IOTA tokens is minted and distributed to well-behaving validators who contribute to the system's security. A portion of the overall staking rewards is allocated to delegators after deducting the validator's commission.
Additionally, some tokens are locked as a storage deposit when creating objects and are redeemable upon object deletion.
Referring back to this chart after the reader has learned the concepts in this section should provide additional clarity.
---
## Validators and Staking Pools
Each IOTA validator maintains its own staking pool to track the amount of stake and to compound staking rewards. Validator pools operate together with a time series of exchange rates that are computed at each epoch boundary. These exchange rates determine the amount of IOTA tokens that each past IOTA staker can withdraw in the future. Importantly, the exchange rates increase as more rewards are deposited into a staking pool and the longer an amount of IOTA is deposited in a staking pool, the more rewards it will accrue.
When IOTA is deposited to the staking pool in epoch `E`, those IOTA tokens are converted into staked tokens at the epoch `E` exchange rate. As the staking pool earns rewards, the exchange rate appreciates. At epoch `E'`, those staked tokens are worth more and translate into more IOTA.
A global exchange rate table is used to track the accounting. Because all IOTA tokens in the staking pool are treated the same, regardless of whether they were originally deposited as new stake or as stake rewards, all IOTA tokens immediately count as stake and thus compound rewards immediately.
The staking pool is implemented in a system-level smart contract ([staking_pool.move](https://github.com/iotaledger/iota/blob/develop/crates/iota-framework/packages/iota-system/sources/staking_pool.move)) and is part of the IOTA framework.
## Validator Pool Rewards
At each epoch boundary, the system computes the staking rewards for each validator pool proportionally to the staked tokens in each pool. The staking rewards $$rewards(i, E)$$ for validator pool $$i$$ at epoch $$E$$ are computed as follows:
$$
rewards(i, E) = \frac{ stakedTokens(i, E)}{\sum_i (stakedTokens(i, E)) }\times totalRewards(E).
$$
$$rewards(i, E)$$ is then adjusted to consider potential slashed validators who have not met minimum quality requirements. Additionally, validators earn commissions on the staking pool's tokens. IOTA keeps track of the rewards accrued by both validators and delegators using a single global exchange rate table.
## Validator Staking Pool Requirements
There are minimum staking requirements a validator must satisfy to become active and to stay in the active validator set.
More precisely:
- A validator candidate must accrue at least 2M IOTA of stake before they can request to join the validator set.
- If an active validator’s stake falls below 1.5M IOTA, the validator has seven epochs of grace period to gain back the stake before being removed from the validator set.
- If an active validator’s stake falls below 1M IOTA, the validator is removed from the validator set at the end of the current epoch boundary.
IOTA uses 24-hour epochs.
---
## Why Move?
While EVM/Solidity is the most famous smart contracts platform, it has some downsides that IOTA Move aims to address:
- **Performance, scaling, and cost**: EVM builds on top of a global shared state, which is practical but doesn't scale well. This results in limitations in throughput, which is directly reflected in the fees you must pay to interact with these networks. The more congested the network, the more expensive it gets. Other blockchains try to mitigate this with additional extra execution layers (L2s on top of L1s) or rollup solutions, which also have downsides and limitations.
- **Security:** As the first well-used smart contract language, Solidity did not have much to go by in terms of learnings around secure practices (there was no existing ecosystem yet), and it had to develop over the years with that legacy and backward compatibility in mind. Many of the issues from the past have been mitigated with workarounds. Still, given the nature of things, there are some limitations and annoyances we currently can't get around, like the security issues it has with both the code and infamous design patterns like the `approve()` method in the ERC standards.
- **Tokens:** Assets like ERC20 tokens and ERC721/1155 NFTs are not part of the EVM and are purely standards for smart contracts deployed on an EVM chain interpreted as tokens by clients. While this works and allows much flexibility, it also has its downsides. Due to the nature of tokens being contracts and the state of your balance being stored within those contracts, it's not trivial to find all tokens in your account without knowing all token contract addresses and manually adding them, unlike the Ethereum balance itself, which is a different kind of token which can be found directly but works differently over an ERC20 token. This makes discovering your assets difficult and adds additional complexity to applications to close the gap between the native asset (ETH) and ERC20 tokens with workarounds like wrapped tokens, which is not ideal.
- **Developer experience:** Solidity offers a wealth of developer tools and resources, including various libraries and frameworks to choose from, as well as extensive documentation and tutorials. The language, influenced by popular languages like C++ and JavaScript, is easy to learn and get started with. However, Solidity's lack of strictness allows for mistakes that the compiler may not catch, leading to bugs and security issues that are difficult to identify and resolve. Consequently, the developer experience suffers, and the language itself is not as safe to work with as it could be.
IOTA Move is here to learn from these downsides and come up with a better alternative addressing these issues:
* **Performance, scaling, and cost:** Given that IOTA Move is based on the object model (similar to UTXO's) and not a globally shared state, transactions can be executed in parallel, resulting in a much higher (potential) throughput over a traditional blockchain with shared state. This results in a lot less congestion and, thus, lower fees on an actively used network.
* **Security:** Move was designed with security in mind. The language itself is based on Rust and is very strict regarding its typing system. The Move compiler is designed to catch many common programming errors, such as type mismatches, resource misuse, and violations of ownership or borrowing rules, before deployment. This helps ensure safety and correctness without relying solely on runtime checks. There's no such thing as re-entry, and given the object-based approach of Move, Assets residing in your account can't be touched at all by the smart contract itself without access to your account keys.
* **Tokens:** In IOTA Move, there is no difference between the IOTA token (`Coin`) and a custom token (`Coin`), not in terms of use or implementation, except that the IOTA token can be used for gas payments. These objects reside in your own account and can thus easily be found without needing to know a Smart Contract address (this goes for any other type of owned object as well). There's no strange `approve()` functionality, and you keep control over your own owned assets.
* **Developer Experience:** While Move is more challenging to get started with compared to Solidity due to its novelty and less mature developer tooling, the safety of the language and the ease of finding and resolving issues in your code make up for that. With Move, it's not so scary anymore to write complex logic from scratch, given most mistakes (apart from obvious implementation logic, doing things 'as intended') are caught directly by the compiler. This allows for more innovation, fewer value-destroying bugs, and a more excellent developer experience, fueling the next generation of smart contracts.
To sum this up:
IOTA offers both EVM and Move, so you can choose the best tool for the job.
If you want to build something that needs to be secure, scalable, and cost-effective, IOTA Move is definitely the way to go. However, if you want a fast shortcut to get started with IOTA smart contracts, or you want to migrate an existing EVM project to IOTA, EVM/Solidity is a good choice.
| EVM/Solidity | Move |
| ------------------------------------------ | ------------------------------------------------------ |
| State as part of contracts | State as objects |
| Global shared state | Owned and Shared objects |
| Transactions executed one by one | Parallel execution |
| No enforced security for standards | Strict type system for standards, assurances |
| Easy to get started with, hard to do right | Harder to get started with, but less room for mistakes |
---
## Account Abstraction
:::info Account Abstraction RC
Account Abstraction is currently a release candidate and, therefore, only available on Testnet and Devnet.
If you test it out, please share your feedback with us in the [IOTA Builders Discord](https://builders-discord.iota.org/).
:::
Account Abstraction (AA) in IOTA lets you replace fixed cryptographic signature verification with programmable Move logic, enabling flexible and extensible account authentication.
This feature allows you to implement custom authentication logic, multi-signature schemes, time-locked accounts, and other advanced account management patterns.
For a full conceptual introduction, see the [Account Abstraction explanation](./move/explanations/account-abstraction/introduction.mdx).
## Move How-Tos
These guides show how to implement and manage abstract accounts in Move.
Go to [How To](./move/how-tos/account-abstraction).
---
## Asset Tokenization
Asset tokenization refers to the process of representing real-world assets, such as real estate, art, commodities, stocks, or other valuable assets, as digital tokens on the blockchain network. This involves converting the ownership or rights of an asset into digital tokens, which are then recorded and managed on the blockchain.
## High-level Overview
The concept is to divide high-value assets into smaller, more affordable units, representing ownership or a fraction of the asset.
This strategy enables wider participation from investors who might want to mitigate risk by investing in a portion of a digital asset rather than being the sole owner, thereby expanding accessibility to a broader range of investors.
This pattern is similar to the [ERC1155](https://eips.ethereum.org/EIPS/eip-1155) multi-token standard with additional functionality. This makes it a suitable choice for Solidity based use cases that one might want to implement on IOTA.
- **Asset creation**
Each asset is fractionalized into a total supply, with each fraction represented as either a non-fungible token (NFT) or fungible token (FT) type collectible. This ensures that each individual fraction maintains a balance equal to or greater than one, and when combined, all fractions collectively reach the total supply of the asset.
Besides the total supply, each asset is defined by various other fields such as name, description, and more. These fields collectively form the metadata for the asset, and they remain consistent across all fractions of the asset.
- **NFTs vs FTs distinction**
Each time a tokenized asset is minted, there's a possibility for it to be created with new metadata. If new metadata is incorporated, the tokenized asset is deemed unique, transforming it into an NFT. In this case, its balance is limited to one, signifying that only a single instance of this asset exists.
If there's no additional metadata, the tokenized asset is categorized as an FT, allowing its balance to exceed one, enabling multiple identical instances of the asset to exist.
FTs possess the capability to merge (join) among themselves or be split when the balance is greater than one. This functionality allows for the aggregation or division of units of the token, offering flexibility in handling varying quantities as needed.
As previously mentioned, all the collectibles of tokenized assets, whether NFTs or FTs, when combined, can amount to the maximum total supply of the asset.
- **Burnability**
When you create the asset, you can define whether the fractions of the asset are eligible for removal or destruction from circulation. The process of removing or destroying assets is called burning.
If a tokenized asset is burnable, then burning a fraction causes the circulating supply to decrease by the balance of the burnt item. The total supply, however, remains constant, allowing you to mint the burned fractions again if needed, thus maintaining the predetermined total supply of the asset.
## Move Packages
As with all smart contracts on IOTA, Move provides the logic that powers asset tokenization.
### `asset_tokenization` Package
:::info
This reference implementation uses the [Kiosk standard](../standards/kiosk.mdx) to ensure that tokenized assets operate within their defined policy. Use the implementation as presented to have marketable tokenized assets that support rules like royalties, commissions, and so on.
If using Kiosk is not a requirement, then you can exclude the unlock module and some of the proxy's methods related to transfer policies.
:::
Select a module to view its details:
The `tokenized_asset` module operates in a manner similar to the `coin` library.
When it receives a new [one-time witness](../iota-101/move-overview/one-time-witness.mdx) type, it creates a unique representation of a fractional asset. This module employs similar implementations to some methods found in the `Coin` module. It encompasses functionalities pertinent to asset tokenization, including new asset creation, minting, splitting, joining, and burning.
**Structs**
- `AssetCap`
Generate an `AssetCap` for each new asset represented as a fractional NFT. In most scenarios, you should create it as an owned object, which you can then transfer to the platform's administrator for access-restricted method invocation.
```rust
struct AssetCap {
id: UID,
// the current supply in circulation
supply: Supply,
// the total max supply allowed to exist at any time
total_supply: u64,
// Determines if the asset can be burned or not
burnable: bool
}
```
- `AssetMetadata`
The `AssetMetadata` struct defines the metadata representing the entire asset to fractionalize. This should be a shared object.
```rust
struct AssetMetadata has key, store {
id: UID,
/// Name of the asset
name: String,
// the total max supply allowed to exist at any time
total_supply: u64,
/// Symbol for the asset
symbol: ascii::String,
/// Description of the asset
description: String,
/// URL for the asset logo
icon_url: Option
}
```
- `TokenizedAsset`
The `TokenizedAsset` is minted with a specified balance that is less than or equal to the remaining supply. If the `VecMap` of an asset is populated with values, indicating multiple unique entries, it is considered an NFT. Conversely, if the `VecMap` of an asset is not populated, indicating an absence of individual entries, it is considered an FT.
```rust
struct TokenizedAsset has key, store {
id: UID,
/// The balance of the tokenized asset
balance: Balance,
/// If the VecMap is populated, it is considered an NFT, else the asset is considered an FT.
metadata: VecMap,
/// URL for the asset image (optional)
image_url: Option,
}
```
- `PlatformCap`
The `PlatformCap` refers to the capability issued to the individual who deploys the contract. This capability grants specific permissions or authority related to the platform's functionalities, allowing the deployer certain controlled actions or access rights within the deployed contract.
```rust
/// Capability that is issued to the one deploying the contract
struct PlatformCap has key, store { id: UID }
```
**Functions**
- `init`
This function creates a `PlatformCap` and sends it to the sender.
```rust
fun init(ctx: &mut TxContext) {}
```
- `new_asset`
This function holds the responsibility of creating a fresh representation of an asset, defining its crucial attributes. Upon execution, it returns two distinct objects: the `AssetCap` and `AssetMetadata`. These objects encapsulate the necessary information and characteristics defining the asset within the system.
```rust
public fun new_asset(
witness: T,
total_supply: u64,
symbol: ascii::String,
name: String,
description: String,
icon_url: Option,
burnable: bool,
ctx: &mut TxContext
): (AssetCap, AssetMetadata) {}
```
- `mint`
The function performs the minting of a tokenized asset. If new metadata is introduced during this process, the resulting tokenized asset is considered unique, resulting in the creation of an NFT with a balance set to 1. Alternatively, if no new metadata is added, the tokenized asset is classified as an FT, permitting its balance to surpass 1, as specified by a provided argument. Upon execution, the function returns the tokenized asset object.
```rust
public fun mint(
cap: &mut AssetCap,
keys: vector,
values: vector,
value: u64,
ctx: &mut TxContext
): TokenizedAsset {}
```
- `split`
This function is provided with a tokenized asset of the FT type and a balance greater than 1, along with a value less than the object's balance, and performs a split operation on the tokenized asset. The operation divides the existing tokenized asset into two separate tokenized assets. The newly created tokenized asset has a balance equal to the given value, while the balance of the provided object is reduced by the specified value. Upon completion, the function returns the newly created tokenized asset. This function does not accept or operate on tokenized assets of the NFT type.
```rust
public fun split(
self: &mut TokenizedAsset,
split_amount: u64,
ctx: &mut TxContext
): TokenizedAsset {}
```
- `join`
This function is given two tokenized assets of the FT type and executes a merge operation on the tokenized assets. The operation involves increasing the balance of the first tokenized asset by the balance of the second one. Subsequently, the second tokenized asset is burned or removed from circulation. After the process concludes, the function returns the ID of the burned tokenized asset.
This function does not accept or operate on tokenized assets of the NFT type.
```rust
public fun join(
self: &mut TokenizedAsset,
other: TokenizedAsset
): ID {}
```
- `burn`
This function requires the `assetCap` as a parameter, thereby restricting its invocation solely to the platform admin. Additionally, it accepts a tokenized asset that is burned as part of its operation. Upon burning the provided tokenized asset, the circulating supply decreases by the balance of the burnt item. It necessitates a tokenized asset that is burnable.
```rust
public fun burn(
cap: &mut AssetCap,
tokenized_asset: TokenizedAsset
)
```
- `total_supply`
This function retrieves and returns the value representing the total supply of the asset.
```rust
public fun total_supply(cap: &AssetCap): u64 {}
```
- `supply`
This function retrieves and returns the value representing the current circulating supply of the asset.
```rust
public fun supply(cap: &AssetCap): u64 {}
```
- `value`
This function takes a tokenized asset as input and retrieves its associated balance value.
```rust
public fun value(tokenized_asset: &TokenizedAsset): u64 {}
```
- `create_vec_map_from_arrays`
This internal helper function populates a `VecMap`. It assists in the process of filling or setting key-value pairs within the `VecMap` data structure.
```rust
fun create_vec_map_from_arrays(
keys: vector,
values: vector
): VecMap {}
```
- `tokenized_asset` full example
```move file=/examples/move/asset_tokenization/asset_tokenization/sources/tokenized_asset.move
```
The `proxy` module comprises methods that the type owner utilizes to execute publisher-related operations.
**Structs**
- `Proxy`
The `PROXY` struct represents the one-time witness (OTW) to claim the publisher.
```rust
struct PROXY has drop {}
```
- `Registry`
This shared object serves as a repository for the `Publisher` object, specifically intended to control and restrict access to the creation and management of transfer policies for tokenized assets. Mutable access to this object is exclusively granted to the actual publisher.
```rust
struct Registry has key {
id: UID,
publisher: Publisher
}
```
- `ProtectedTP`
This is a shared object that stores an empty transfer policy. It is required to create one per type `` generated by a user. Its involvement is apparent in the unlock module.
```rust
struct ProtectedTP has key, store {
id: UID,
policy_cap: TransferPolicyCap,
transfer_policy: TransferPolicy
}
```
**Functions**
- `init`
This function is responsible for creating the `Publisher` object, encapsulating it within the registry, and subsequently sharing the `Registry` object.
```rust
fun init(otw: PROXY, ctx: &mut TxContext) {}
```
- `setup_tp`
This function leverages the publisher nested within the registry and the sender's publisher. It generates and returns a transfer policy and the associated transfer policy cap specific to the `TokenizedAsset`. This type 'T' is derived from the `Publisher` object.
It also generates an empty transfer policy wrapped in a `ProtectedTP` object, which is shared. You can use this functionality under specific conditions to override the kiosk lock rule.
```rust
public fun setup_tp(
registry: &Registry,
publisher: &Publisher,
ctx: &mut TxContext
): (TransferPolicy>,
TransferPolicyCap>) {}
```
- `new_display`
This function utilizes the publisher nested within the registry and the sender's publisher to generate and return an empty `Display` for the type `TokenizedAsset`, where `T` is encapsulated within the `Publisher` object.
```rust
public fun new_display(
registry: &Registry,
publisher: &Publisher,
ctx: &mut TxContext
): Display> {}
```
- `transfer_policy`
This function, provided with the `protectedTP`, returns the transfer policy specifically designed for the type `TokenizedAsset`
```rust
public(friend) fun transfer_policy(
protected_tp: &ProtectedTP
): &TransferPolicy {}
```
- `publisher_mut`
This function can only be accessed by the owner of the platform cap. It requires the registry as an argument to obtain a mutable reference to the publisher.
```rust
public fun publisher_mut(
_: &PlatformCap,
registry: &mut Registry
): &mut Publisher {}
```
- `proxy` full example
```move file=/examples/move/asset_tokenization/asset_tokenization/sources/proxy.move
```
The `unlock` module facilitates the unlocking of a tokenized asset specifically for authorized burning and joining.
It allows tokenized asset type creators to enable these operations for kiosk assets without necessitating adherence to the default set of requirements, such as rules or policies.
**Structs**
- `JoinPromise`
A promise object is established to prevent attempts of permanently unlocking an object beyond the intended scope of joining.
```rust
struct JoinPromise {
/// the item where the balance of the burnt tokenized asset will be added.
item: ID,
/// burned is the id of the tokenized asset that will be burned
burned: ID,
/// the expected final balance of the item after merging
expected_balance: u64
}
```
- `BurnPromise`
A promise object created to ensure the permanent burning of a specified object.
```rust
struct BurnPromise {
expected_supply: u64
}
```
**Functions**
- `asset_from_kiosk_to_join`
This helper function is intended to facilitate the joining of tokenized assets locked in kiosk. It aids in unlocking the tokenized asset that is set for burning and ensures that another tokenized asset of the same type will eventually contain its balance by returning a `JoinPromise.`
```rust
public fun asset_from_kiosk_to_join(
self: &TokenizedAsset, // A
to_burn: &TokenizedAsset, // B
protected_tp: &ProtectedTP>, // unlocker
transfer_request: TransferRequest> // transfer request for b
): JoinPromise {}
```
- `prove_join`
A function utilized to demonstrate that the unlocked tokenized asset is successfully burned and its balance is incorporated into an existing tokenized asset.
```rust
public fun prove_join(
self: &TokenizedAsset,
promise: JoinPromise,
proof: ID) {
}
```
- `asset_from_kiosk_to_burn`
Helper function that facilitates the burning of tokenized assets locked in a kiosk. It assists in their unlocking while ensuring a promise that the circulating supply will be reduced, achieved by returning a `BurnPromise`.
```rust
public fun asset_from_kiosk_to_burn(
to_burn: &TokenizedAsset,
asset_cap: &AssetCap,
protected_tp: &ProtectedTP>,
transfer_request: TransferRequest>,
): BurnPromise {
}
```
- `prove_burn`
Ensures that the circulating supply of the asset cap is reduced by the balance of the burned tokenized asset.
```rust
public fun prove_burn(
asset_cap: &AssetCap,
promise: BurnPromise) {
}
```
- `unlock` full example
```move file=/examples/move/asset_tokenization/asset_tokenization/sources/unlock.move
```
### `template` Package
An example use case package that enables utilization of Rust WASM functionality to support seamless asset creation on the browser.
This is similar to the launchpad approach and serves as the template package whenever a new asset requires representation as a tokenized asset.
Effectively allowing users to edit fields of this template contract on the fly and publish it with the edits included.
This package implements two essential modules, each catering to distinct functionalities required for asset tokenization.
More details regarding how Rust WASM was implemented can be found in the [Web Assembly](#webassembly-wasm-and-template-package) section.
- **Modules**
- `template`
This is the module that supports defining a new asset.
When you need to represent a new asset as a fractional asset, modify this module to `::`, with the `` (in capitals) being the OTW of this new asset.
This module calls the `asset_tokenization::tokenized_asset::new_asset(...)` method, which facilitates the declaration of new fields for the asset:
- `witness`: The OTW `NEW_ASSET`
- `total_supply`: The total supply allowed to exist at any time
- `symbol`: The symbol for the asset
- `name`: The name of the asset
- `description`: The description of the asset
- `icon_url`: The URL for the asset logo (optional)
- `burnable`: Boolean that defines if the asset can be burned by an admin
- `genesis`
A genesis type of module that includes a OTW so that the sender can claim the publisher.
## Publish and Mint Tokenized Sequence Diagram
```mermaid
sequenceDiagram
participant Platform Admin
participant Asset Creator
participant Kiosk
participant tokenized_asset
participant proxy
participant template
participant genesis
participant genesis
participant Blockchain
Platform Admin->>Blockchain: Publish asset_tokenization package (tokenized_asset, proxy, unlock modules)
Blockchain-->>tokenized_asset: tokenized_asset module is published
Blockchain-->>proxy: proxy module is published
tokenized_asset->>Platform Admin: Send Platform Cap (owned object)
proxy->>Blockchain: Share Registry (shared object)
Asset Creator->>template: Pass Asset Info, AssetOTW as input
Asset Creator->>genesis: Pass PublisherOTW as input
Asset Creator->>Blockchain: Publish template package (template, genesis modules)
Blockchain-->>genesis: genesis module is published
Blockchain-->>template: template module is published
genesis->>Asset Creator: Send Publisher (owned object)
template->>tokenized_asset: Create new asset using Asset Info as input
tokenized_asset-->>Asset Creator: Send Asset Cap (owned object)
tokenized_asset-->>Blockchain: Share Asset Metadata (shared object)
Asset Creator->>proxy: Use Publisher as input to setup_tp
Blockchain->>proxy: Use Registry as input to setup_tp
proxy-->>Blockchain: Share created Transfer Policy, ProtectedTP (shared objects)
proxy-->>Asset Creator: Send created Transfer Policy Cap (owned object)
Asset Creator->>tokenized_asset: Define type of tokenized asset (FT, NFT) to mint
tokenized_asset-->>Asset Creator: Return minted Tokenized Asset
Asset Creator->>Kiosk: Place Tokenized Asset
```
### Join Sequence Diagram
The following sequence diagram presenting how the join flow would take place. The following flow assumes that:
- Tokenized assets X and Y have already been minted by the creator of their type.
- Tokenized assets X and Y are already placed and locked inside the user's kiosk.
- Everything is executed in the same programmable transaction block (PTB).
```mermaid
sequenceDiagram
participant User
participant User's Kiosk
participant kiosk module
participant unlock module
participant tokenized asset module
participant blockchain
User's Kiosk->>kiosk module: Borrow Tokenized Asset X
kiosk module-->>User: Returns Promise, Tokenized Asset X
User's Kiosk->>kiosk module: List Tokenized Asset Y for zero price
User's Kiosk->>kiosk module: Purchase Tokenized Asset Y
kiosk module-->>User: Returns Transfer Request, Tokenized Asset Y
User->>unlock module: Use Transfer Request, Tokenized Asset X, Y as input to asset_from_kiosk_to_join
blockchain->>unlock module: Use Protected TP as input to asset_from_kiosk_to_join
unlock module-->>User: Returns Join Promise, Tokenized Asset X,Y Objects
User->>tokenized asset module: Use Tokenized Asset X,Y as input to join
tokenized asset module-->>User: Return Burn Proof, Tokenized Asset X
User->>unlock module: Use Burn Proof, Join Promise, Tokenized Asset X as input to prove_join
unlock module-->>User: Return Tokenized Asset X
User->>User's Kiosk: Resolve Promise by returning Tokenized Asset X in user's Kiosk
```
### Burn Sequence Diagram
The following sequence diagram shows the burn flow and assumes that:
- Tokenized asset has already been minted by the creator of its type.
- Tokenized asset is already placed and locked inside the user's Kiosk.
- Everything is executed in the same PTB.
```mermaid
sequenceDiagram
participant User
participant User's Kiosk
participant kiosk module
participant unlock module
participant tokenized asset module
participant blockchain
User's Kiosk->>kiosk module: List Tokenized Asset for zero price
User's Kiosk->>kiosk module: Purchase Tokenized Asset
kiosk module-->>User: Returns Transfer Request, Tokenized Asset Object
User->>unlock module: Use Transfer Request, Tokenized Asset Object, Asset Cap as input to asset_from_kiosk_to_burn
blockchain->>unlock module: Use Protected TP as Input to asset_from_kiosk_to_burn
unlock module-->>User: Returns Burn Promise, Tokenized Asset Object, Asset Cap
User->>tokenized asset module: Use Tokenized Asset Object, Asset Cap as input to burn
tokenized asset module-->>User: Returns Asset Cap
User->>unlock module: Use Burn Proof, Asset Cap as input to prove_burn
unlock module-->>User: Returns Asset Cap
```
## Variations
The packages and modules provided demonstrate how you could implement asset tokenization for your project. Your particular use case probably necessitates altering the contract for convenience or to introduce new features.
### Example Convenience Alteration
Instead of implementing the unlock functionality in multiple steps inside of a PTB, it would also be possible to create a method that performs the purchase, borrowing, unlocking and joining of an asset all on one function. This is how that would look like for the joining operation:
```rust
public fun kiosk_join(
kiosk: &mut Kiosk,
kiosk_cap: &KioskOwnerCap,
protected_tp: &ProtectedTP>,
ta1_id: ID,
ta2_id: ID,
ctx: &mut TxContext
) {
kiosk::list>(kiosk, kiosk_cap, ta2_id, 0);
let (ta1, promise_ta1) = kiosk::borrow_val(kiosk, kiosk_cap, ta1_id);
let coin = coin::zero(ctx);
let (ta2, request) = kiosk::purchase(kiosk, ta2_id, coin);
let tp_ref = proxy::transfer_policy(protected_tp);
let (_item, _paid, _from) = transfer_policy::confirm_request(
tp_ref,
request
);
tokenized_asset::join(&mut ta1, ta2);
kiosk::return_val(kiosk, ta1, promise_ta1);
}
```
### Example Alteration For Use Case
:::caution
The following example splits (effectively replacing) the `AssetCap` into two new objects: the `Treasury` and the `AdminCap`. The access to methods defined in the original package, should now be carefully re-designed as this change can introduce unwanted effects. This required re-design is not entirely contained in this example and only some methods are changed for demonstration purposes (or as a thorough exercise).
:::
Assume you want to allow the users to also burn assets, not only admins. This still needs to be an authorized operation but it would allow the flexibility of consuming tokenized assets for a use case specific purpose (for example, burning all of the collectibles you've gathered to combine them). To achieve this, the admin can mint tickets that contain the ID of the asset they are allowed to burn. To support this functionality you must redesign the smart contract and separate the admin from the asset's treasury of each asset, which now holds only supply related information. Sample changes that need to happen follow:
**Structs**
Create a ticket that has only the `key` ability so that the receiver cannot trade it.
```rust
struct BurnTicket has key {
id: UID,
tokenized_asset_id: ID // the tokenized asset that this ticket gives access to burn
}
```
The struct that now only holds treasury related information (results from splitting the `AssetCap`, meaning it's no longer part of this design) is created as a shared object. Change functions like `mint` to also take as input both the `Treasury` object and the `AdminCap` object.
```rust
struct Treasury has key, store {
id: UID,
supply: Supply,
total_supply: u64,
}
```
The other half of the `AssetCap` functionality which retains the admin capability and the configuration of burnability is an owned object sent to the creator of type ``.
```rust
struct AdminCap has key, store {
id: UID,
burnable: bool
}
```
**Method Signatures**
The `AdminCap` here acts both as an admin capability and a type insurance. Encoding the information of both the asset type that is allowed to be deleted with this ticket.
This function should assert that the asset T is burnable and return a `BurnTicket`.
```rust
public fun mint_burn_ticket(
cap: &AdminCap,
tokenized_asset_id: ID,
ctx: &mut TxContext
): BurnTicket
```
Burning on the user side requires for them to access the shared `Treasury` object. This function burns the tokenized asset and decreases the supply.
```rust
public fun burn_with_ticket(
treasury: &mut Treasury,
self: TokenizedAsset,
ticket: BurnTicket)
```
## Deployment
:::info
See [Publish a Package](../developer/getting-started/publish.mdx) for a more detailed guide on publishing packages or [IOTA Client CLI](/developer/references/cli/client.mdx) for a complete reference of `client` commands in the IOTA CLI.
:::
Before publishing your code, you must first initialize the IOTA Client CLI, if you haven't already. To do so, in a terminal or console at the root directory of the project enter `iota client`. If you receive the following response, complete the remaining instructions:
```
Select a default network [mainnet|testnet|devnet|localnet], or enter a custom IOTA full node server URL (defaults to testnet if not specified):
```
Leave this blank (press Enter). You receive the following response:
```
Select key scheme to generate keypair (0 for ed25519, 1 for secp256k1, 2: for secp256r1):
```
Select `0`. Now you should have an IOTA address set up.
### Publishing
At this stage, you can choose to manually deploy the contracts or utilize the publish bash script that automatically deploys the contracts and sets up most of the `.env` Asset Tokenization related fields for you.
The `.env.template` file denotes variables that the script automatically fills in.
You can see a reference here:
```
IOTA_NETWORK = rpc endpoint of the network of your choice | auto filled by publish script
ASSET_TOKENIZATION_PACKAGE_ID = Created by publishing `asset_tokenization` package | auto filled by publish script
REGISTRY = Created by publishing `asset_tokenization` package | auto filled by publish script
TEMPLATE_PACKAGE_ID = Created by publishing `template` package
ASSET_CAP_ID = Created by publishing `template` package
ASSET_METADATA_ID = Created by publishing `template` package
ASSET_PUBLISHER = Created by publishing `template` package
PROTECTED_TP = Created by calling `setup_tp` function
TRANSFER_POLICY = Created by calling `setup_tp` function
OWNER_MNEMONIC_PHRASE = your mnemonic | can be exported locally in the terminal before publishing
BUYER_MNEMONIC_PHRASE = buyer's mnemonic | can be exported locally in the terminal before publishing
TARGET_KIOSK = kiosk id
BUYER_KIOSK = kiosk id
TOKENIZED_ASSET = tokenized asset id (created by minting)
FT1 = tokenized asset id (to be joined)
FT2 = tokenized asset id (to be joined)
```
For more details on publishing, please check the setup folder's [README](https://github.com/iotaledger/asset-tokenization/tree/main/setup).
#### Publishing Packages
Select a package for specific instructions.
##### Manually
In a terminal or console at the `move/asset_tokenization` directory of the project enter:
```bash
iota client publish
```
For the gas budget, use a standard value such as `20000000`.
The package should successfully deploy, and you then see:
```bash
UPDATING GIT DEPENDENCY https://github.com/iotaledger/iota.git
INCLUDING DEPENDENCY IOTA
INCLUDING DEPENDENCY MoveStdlib
BUILDING asset_tokenization
Successfully verified dependencies on-chain against source.
```
You can also view a multitude of information and transactional effects.
You should choose and store the `package ID` and the `registry ID` from the created objects in the respective fields within your .env file.
Afterward, it's necessary to modify the `Move.toml` file. Under the `[addresses]` section, replace `0x0` with the same `package ID`.
##### Automatically
The fields that are automatically filled are: `IOTA_NETWORK`, `ASSET_TOKENIZATION_PACKAGE_ID` and `REGISTRY`.
To publish with the bash script run:
```bash
npm run publish-asset-tokenization
```
After publishing, you can now edit the `Move.toml` file like described in the Manual flow.
For more details regarding this process, please consult the setup folder's [README](https://github.com/iotaledger/asset-tokenization/tree/main/setup).
##### Manually
In a terminal or console at the `move/template` directory of the project enter:
```bash
iota client publish
```
For the gas budget, use a standard value such as `20000000`.
The package should successfully deploy, and you then see:
```bash
UPDATING GIT DEPENDENCY https://github.com/iotaledger/iota.git
INCLUDING DEPENDENCY asset_tokenization
INCLUDING DEPENDENCY IOTA
INCLUDING DEPENDENCY MoveStdlib
BUILDING template
Successfully verified dependencies on-chain against source.
```
You can also view a multitude of information and transactional effects.
You should choose and store the `package ID`, asset `metadata ID`, `asset cap ID` and the `Publisher ID` from the created objects in the respective fields within your .env file.
##### Automatically
The process of automatic deployment for the template package refers to publishing a new asset via the WASM library. Quick start steps:
- Ensure that the `asset_tokenization` package address is set in the `[addresses]` section of `asset_tokenization/Move.toml`. This address should be the same as the original package deployment.
- If a `Move.lock` file exists after running`iota client publish`, go on to the next step.
- Make any changes to the template fields by changing the input parameters of the `publishNewAsset` function.
- Run `npm run publish-template`.
- You should choose and store the _Template Package ID_, _asset metadata ID_, _asset cap ID_ and the _publisher ID_ from the created objects in the respective fields within your **.env** file.
For more details regarding this process, please consult the setup folder's [README](https://github.com/iotaledger/asset-tokenization/tree/main/setup).
### WebAssembly (WASM) and Template Package
:::tip
You can find a public facing reference to the WASM library in the [move-binary-format-wasm](https://github.com/iotaledger/iota/tree/main/sdk/move-binary-format-wasm) IOTA repo subfolder.
:::
This feature was developed with the intent to enable Move bytecode serialization and deserialization on the web. In essence, this feature allows you to edit existing contracts in a web environment.
In the case of asset tokenization, these edits allow you to create and publish new types that represent physical or digital assets that we want to tokenize.
### Bytecode manipulation
:::caution
On modifications that are made to the template package this process needs to be repeated. Note that some alterations, like changing a constant name, do not affect the produced bytecode.
:::
Before proceeding to how to make these edits, it's important to understand how the library exposes the template module bytecode. The process is currently manual. This requires that you build and retrieve the compiled bytecode. To do this, navigate inside the template folder and run the following command:
```bash
xxd -c 0 -p build/template/bytecode_modules/template.mv | head -n 1
```
Toggle response
The response you should receive looks similar to the following:
```bash
a11ceb0b060000000a010010021026033637046d0a05776807df01ec0108cb03800106cb043
e0a8905050c8e0549001303140107010d01120215021602170004020001000c01000101010c
010001020307000302070100000403070006050200070607000009000100010a0a0b0102021
2050700030c010401000311060401000418050800050e0601010c050f1001010c06100d0e00
070b050300030304030109060c070f02080007080600040b040108070b010108000b0201080
00b04010807010807010b04010900010a020109000108030108050108000809000308030805
08050b0401080701070806020b010109000b02010900010b02010800010608060105010b010
10800020900050841737365744361700d41737365744d65746164617461064f7074696f6e06
537472696e670854454d504c415445095478436f6e746578740355726c0561736369690b647
56d6d795f6669656c6404696e6974096e65775f6173736574156e65775f756e736166655f66
726f6d5f6279746573046e6f6e65066f7074696f6e137075626c69635f73686172655f6f626
a6563740f7075626c69635f7472616e736665720673656e64657204736f6d6506737472696e
670874656d706c6174650f746f6b656e697a65645f6173736574087472616e736665720a747
85f636f6e746578740375726c04757466380000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000100000000000000000000000000000000000000000000000000000000000000
02d9ebdef1e3cb5eb135362572b18faeb61259afe651a463f1384745ebd7fd51da030864000
000000000000a02070653796d626f6c0a0205044e616d650a020c0b4465736372697074696f
6e0a02090869636f6e5f75726c0101010a02010000020108010000000002230704070621040
738000c02050b0704110938010c020b020c050b0007000701110207021105070311050b0507
050a0138020c040c030b0438030b030b012e110838040200
```
Copy the output you receive and paste it in the return instruction of the `getBytecode` method, which is located inside the [bytecode-template.ts](https://github.com/iotaledger/asset-tokenization/blob/main/setup/src/utils/bytecode-template.ts) file.
Additionally, because the template package contains two modules, and therefore has another dependency, you also need to retrieve the bytecode of the genesis module in a similar fashion. This module bytecode, however, is not edited and isn't used as is. This operation is not directly relevant to the WASM library, but is necessary to successfully deploy the edited template module. To acquire the bytecode for genesis, navigate to the `template` folder and run:
```bash
xxd -c 0 -p build/template/bytecode_modules/genesis.mv | head -n 1
```
The output format is similar to the template module but smaller in length. Similarly to what you did with the template module, you need to copy this output but this time paste it in the bytecode constant variable located in the [genesis_bytecode.ts](https://github.com/iotaledger/asset-tokenization/blob/main/setup/src/utils/genesis_bytecode.ts) file.
With the above setup, the library can now manipulate the bytecode by deserializing it, editing it, and serializing it again so that you can publish it.
### Closer View of the Template Module
Taking a look at the template module, you should see that a few constants have been defined:
```rust
...
const TOTAL_SUPPLY: u64 = 100;
const SYMBOL: vector = b"Symbol";
const NAME: vector = b"Name";
const DESCRIPTION: vector = b"Description";
const ICON_URL: vector = b"icon_url";
const BURNABLE: bool = true;
...
```
These constants act as a reference point that the WASM library is able to modify. If you take a look at the TypeScript code that performs the edit and deploys, you can see in action how these fields are identified and updated:
```tsx
...
const template = getBytecode();
const compiledModule = new CompiledModule(
JSON.parse(wasm.deserialize(template))
)
.updateConstant(0, totalSupply, "100", "u64")
.updateConstant(1, symbol, "Symbol", "string")
.updateConstant(2, asset_name, "Name", "string")
.updateConstant(3, description, "Description", "string")
.updateConstant(4, iconUrl, "icon_url", "string")
.updateConstant(5, burnable, "true", "bool")
.changeIdentifiers({
template: moduleName,
TEMPLATE: moduleName.toUpperCase(),
});
const bytesToPublish = wasm.serialize(JSON.stringify(compiledModule));
...
```
Examine the `updateConstant` method, which is used to update constants. This method takes four arguments:
- An `idx` (index) that the declared constant would have in the constant pool. The order is sequential, starting from 0 for the first constant defined in the Move file and stepping plus one for each consecutive constant.
- A `value` that contains an updated value of the constant you want to change.
- An `expectedValue` that contains the current value of the constant.
- An `expectedType` that contains the current type of the constant.
The last two arguments are requited to minimize the risk of accidentally updating the wrong constant since this library is directly manipulating complied bytecode, which is quite dangerous.
Additionally, the `changeIdentifiers` method updates identifiers, which in our case are the module name and the struct name. This method takes a JSON object as an argument with keys of the current identifier names in the module and values being the desired names you want to change them into.
Lastly, to deploy the changed template module, build and publish:
```tsx
...
const tx = new Transaction();
tx.setGasBudget(100000000);
const [upgradeCap] = tx.publish({
modules: [[...fromHex(bytesToPublish)], [...fromHex(genesis_bytecode)]],
dependencies: [
normalizeIotaObjectId("0x1"),
normalizeIotaObjectId("0x2"),
normalizeIotaObjectId(packageId),
],
});
tx.transferObjects(
[upgradeCap],
tx.pure(signer.getPublicKey().toIotaAddress(), "address")
);
...
```
As mentioned in the [Bytecode manipulation](#bytecode-manipulation) section, the modules that you need to publish are the template and the genesis, hence the reason you have two elements in the `modules` array. It's also important to include any dependencies defined in the `Move.toml` file of the involved packages. The `packageId` used previously is the address the `asset_tokenization` package has been deployed to.
## TypeScript
Now, you can begin interacting with the deployed smart contract and your tokenized asset.
In a terminal or console within the project's setup directory, utilize the following commands:
- **Create Transfer Policy**
First, create a `TransferPolicy` and a `ProtectedTP` with the following command:
```shell
npm run call create-tp
```
After executing the command, the console displays the effects of the transaction.
By searching the transaction digest on an IOTA network explorer, you can locate the created objects. Subsequently, select and save the `TransferPolicy ID` and the `ProtectedTP ID` from these objects into the respective fields within your .env file.
- **Add Rules**
In the project's file `transferPolicyRules.ts` located in the directory `setup/src/functions`, you can modify the code to include the desired rules for your transfer policy.
Code snippet to be modified:
```rust
// A demonstration of using all the available rule add/remove functions.
// You can chain these commands.
tpTx
.addFloorPriceRule('1000')
.addLockRule()
.addRoyaltyRule(percentageToBasisPoints(10), 0)
// .addPersonalKioskRule()
// .removeFloorPriceRule()
// .removeLockRule()
// .removeRoyaltyRule()
// .removePersonalKioskRule()
```
By running the command `npm run call tp-rules`, the rules will be added to your transfer policy.
Now, investors can trade the fractions of your asset according to the rules you've set.
- **Select Kiosk**
You must place the tokenized assets within a kiosk if marketable assets are desired. Subsequently, you can list and sell them to other users. It's imperative to lock the objects in the kiosk to prevent any future unauthorized usage outside the defined policy that you set.
Best practices recommend a single, comprehensive kiosk for all operations. However, this might not always be the case. Therefore, this project requires the use of only one personal kiosk to ensure consistency and better management, even if you own multiple kiosks.
To enforce this rule, execute the command `npm run call select-kiosk`. This provides you with the specific kiosk ID to use for this project.
Then, store the provided Kiosk ID in the appropriate field within your .env file.
- **Mint**
In the project's file `mint.ts`, found in the directory `setup/src/functions`, you can edit the code to mint the desired type (NFT/FT) and balance for your asset.
As previously mentioned, if additional metadata is provided, the tokenized asset is treated as an NFT with a value of one. However, if there is no extra metadata, the tokenized asset is regarded as an FT, and you have the flexibility to select its balance, which can exceed one.
Here is an example from the code that needs modification:
```rust
// example without metadata -> FT
function getVecMapValues() {
const keys : string[] = [];
const values : string[] = [];
return { keys, values };
}
```
or
```rust
// example with metadata -> NFT
function getVecMapValues() {
const keys = [
"Piece",
"Is it Amazing?",
"In a scale from 1 to 10, how good?",
];
const values = ["8/100", "Yes", "11"];
return { keys, values };
}
```
Upon executing the command `npm run call mint`, a new tokenized asset is minted. You can save the object's `ID` in the .env file for future reference.
- **Lock**
Locking the objects within the kiosk is crucial to prevent any unauthorized usage beyond the established policy.
Upon executing the command `npm run call lock`, your newly minted tokenized asset is secured within your kiosk.
Before running the command, make sure that the field `TOKENIZED_ASSET` within your `.env` file is populated with the object you intend to lock.
- **Mint and Lock**
Executing the command `npm run call mint-lock` performs both the mint and lock functions sequentially, ensuring the minted asset is created and immediately locked within the kiosk.
- **List**
Now that your tokenized asset is placed and locked within your kiosk, you can proceed to list it for sale.
In the project's file `listItem.ts`, found in the directory `setup/src/functions`, you can adjust the code to specify the desired asset for listing.
Code snippet to be modified:
```rust
const SALE_PRICE = '100000';
kioskTx
.list({
itemId,
itemType,
price: SALE_PRICE,
})
.finalize();
```
By running the command `npm run call list`, your tokenized asset is listed and made available for sale.
- **Purchase**
When a user intends to purchase an item, it needs to be listed for sale. After the user selects the item to buy, they are required to modify the following snippet of code found in the file `purchaseItem.ts`, located in the `setup/src/functions` directory.
```rust
const item = {
itemType: tokenizedAssetType,
itemId: tokenized_asset ?? tokenizedAssetID,
price: "100000",
sellerKiosk: targetKioskId,
};
```
Apart from specifying the item and its type, the buyer must set the specific price and the seller's kiosk ID to execute the purchase transaction successfully, accomplished by running `npm run call purchase`.
- **Join**
When you execute the command `npm run call join`, two specified tokenized assets of the FT type are merged together. Before running the command, make sure that the fields `FT1` and `FT2` within your `.env` file are populated with the objects you intend to merge.
- **Burn**
When you intend to burn a tokenized asset, execute the command `npm run call burn`. Following this action, the specified asset is destroyed. Before running the command, make sure that the field `TOKENIZED_ASSET` within your `.env` file is populated with the object you intend to burn.
- **Get Balance**
By executing the command `npm run call get-balance`, you can retrieve the balance value associated with the specified tokenized asset.
- **Get Supply**
By executing the command `npm run call get-supply`, you can retrieve the value representing the current circulating supply of the asset.
- **Get Total Supply**
By executing the command `npm run call get-total-supply`, you can retrieve the value representing the current circulating supply of the asset.
---
## Custom Indexer
import CodeBlock from '@theme/CodeBlock';
You can build custom indexers using the IOTA data ingestion framework, which is maintained through the [iota-data-ingestion-core][iota-data-ingestion-core] library. To create an indexer, you subscribe to a checkpoint stream with full checkpoint content. This stream can be one of the publicly available streams from IOTA, one that you set up in your local environment, or a combination of the two.
Establishing a custom indexer helps improve latency, allows pruning the data of your IOTA full node, and provides efficient assemblage of checkpoint data.
## Setup
To start, you need to specify the proper dependencies in your `Cargo.toml`. Here is what the minimal manifest would look like for a new indexer:
```toml
[package]
name = "custom-indexer"
version = "0.1.0"
edition = "2021"
license = "Apache-2.0"
[dependencies]
iota-data-ingestion-core = { git = "https://github.com/iotaledger/iota", package = "iota-data-ingestion-core" }
iota-types = { git = "https://github.com/iotaledger/iota", package = "iota-types" }
```
:::caution
When resolving `git` dependencies, Cargo records the latest commit hash at the time of the build on `Cargo.lock`. Updating to newer versions requires manually calling `cargo update iota-data-ingestion-core iota-types` and updating `Cargo.lock`.
Network upgrades that introduce new types included in the checkpoint data will thus require updating custom indexers accordingly.
:::
## Interface and Data Format
To use the framework, implement a basic interface:
```rust
#[async_trait]
trait Worker: Send + Sync {
type Error: Debug + Display;
type Message: Send + Sync;
async fn process_checkpoint(&self, checkpoint: Arc) -> Result;
}
```
In this example, the [`CheckpointData`](https://iotaledger.github.io/iota/iota_types/full_checkpoint_content/struct.CheckpointData.html) struct represents full checkpoint content. The struct contains checkpoint summary and contents, as well as detailed information about each individual transaction.
## Checkpoint Stream Sources
Data ingestion for your indexer supports several checkpoint stream sources. A source can be [remote](#remote-reader), [local](#local-reader), or a [combination of both](#hybrid-mode).
### Remote Reader
The most straightforward stream source is to subscribe to a remote store of checkpoint contents. A remote source can be either a historical checkpoint store or a direct gRPC stream to an IOTA full node.
#### Historical Checkpoint Store
An IOTA full node is not guaranteed to retain all historical data, depending on its configuration, older checkpoints may be pruned. To sync from genesis up to the tip of the network, the indexer must rely on a dedicated checkpoint store. The IOTA Foundation provides the following endpoints for downloading historical checkpoint data.
**Historical Checkpoint Data**
For syncing historical data up to the tip of the network:
- Devnet: `https://checkpoints.devnet.iota.cafe/ingestion/historical`
- Testnet: `https://checkpoints.testnet.iota.cafe/ingestion/historical`
- Mainnet: `https://checkpoints.mainnet.iota.cafe/ingestion/historical`
**Live Checkpoint Streaming (Optional)**
For real-time streaming of current epoch checkpoints only:
- Devnet: `https://checkpoints.devnet.iota.cafe/ingestion/live`
- Testnet: `https://checkpoints.testnet.iota.cafe/ingestion/live`
- Mainnet: `https://checkpoints.mainnet.iota.cafe/ingestion/live`
:::info Historical vs Live Endpoints
| Feature | Historical Endpoint | Live Endpoint |
| -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------- |
| **Format** | Batches multiple checkpoints into single files | Individual checkpoint files |
| **Best for** | Initial sync from genesis to near network tip | Real-time ingestion at network tip |
| **Latency behavior** | • Near zero latency during historical sync (processes batches as fast as possible)• Variable latency at network tip (waits for batch completion, typically ~1000 checkpoints or epoch change) | Minimal latency (published immediately) |
| **Data coverage** | Complete data coverage from genesis | Current epoch only (older checkpoints automatically purged) |
| **Optimization** | Throughput-focused for bulk ingestion | Low-latency processing |
1. **Historical endpoint** should always be used as the primary source to guarantee complete data coverage from genesis
2. **Live endpoint** is optional for applications needing real-time access to the very latest checkpoints
:::
```mermaid
flowchart LR
A("fa:fa-cloud Cloud storage(S3, GCP)");
B[("fa:fa-gears
Indexer
daemon")];
A -- checkpoint stream -->B;
B<-->C("fa:fa-floppy-disk Progress store");
subgraph External
D("fa:fa-database Postgres");
E("fa:fa-database BigQuery");
F("fa:fa-database S3");
end
B-->External
```
In this example, we'll explore a simple custom indexer that can ingest data from multiple sources: the `historical` and `live` endpoints, or directly from a local fullnode gRPC API. The [`RemoteUrl`](https://iotaledger.github.io/iota/iota_data_ingestion_core/reader/v2/enum.RemoteUrl.html) enum provides flexible configuration options for these different data sources, including hybrid configurations that combine multiple sources.
```rust file=/examples/custom-indexer/rust/remote_reader.rs
```
#### Fullnode gRPC Checkpoint Data Stream
For local development against a local network, or for public networks that expose a fullnode gRPC API, you can use the [`RemoteUrl::Fullnode`](https://iotaledger.github.io/iota/iota_data_ingestion_core/reader/v2/enum.RemoteUrl.html#variant.Fullnode) variant to connect directly to a fullnode. The gRPC stream delivers checkpoint data efficiently and with minimal latency. For more advanced use cases, it also exposes a filtering mechanism that lets you include only specific transactions in each checkpoint payload.
**Filtering Checkpoint Data**
When using the [`RemoteUrl::Fullnode`](https://iotaledger.github.io/iota/iota_data_ingestion_core/reader/v2/enum.RemoteUrl.html#variant.Fullnode) gRPC checkpoint stream API, you can register a filter that instructs the fullnode to include only specific transactions in each checkpoint payload.
Filtering occurs entirely server-side, so the ingestion framework performs no client-side filtering of its own. This is especially useful when a custom indexer targets specific data, since it avoids transferring irrelevant transactions over the network.
```rust file=/examples/custom-indexer/rust/remote_reader_with_filters.rs
```
In the example above, `CustomWorker::process_checkpoint` is only invoked for checkpoints that contain at least one matching transaction. Checkpoints with no matches are skipped.
A [`TransactionFilter`](https://iotaledger.github.io/iota/iota_data_ingestion_core/reader/filters/fullnode/struct.TransactionFilter.html) is built with a chained builder. Start from `TransactionFilter::new()` and add leaves with the named methods, such as `kinds()`, `sender()`, `receiver()`, and `execution_status()`. An empty `TransactionFilter::new()` is rejected by the fullnode, so always add at least one leaf before passing it to the reader.
:::info Composition semantics
- Each leaf you add **implicitly ANDs** with everything accumulated so far.
- Use `or()` to compose a logical **OR** with another `TransactionFilter`.
- Use `negate()` (or the `!` operator) for **NOT**. It wraps the entire filter accumulated so far, not just the most recent leaf ([see below](#negate-scoping)).
:::
A simple filter, showcasing implicit **AND** composition:
```rust
use iota_data_ingestion_core::filters::fullnode::{TransactionFilter, TransactionKind};
// Programmable AND success
let filter = TransactionFilter::new()
.kinds([TransactionKind::Programmable])
.execution_status(true);
```
Composition with **AND**, **OR**, and **NOT**:
```rust
// (Programmable AND success AND sender == Alice) OR NOT(receiver == Bob)
let filter = TransactionFilter::new()
.kinds([TransactionKind::Programmable])
.execution_status(true)
.sender(alice)
.or(!TransactionFilter::new().receiver(bob));
```
:::caution
#### `negate` scoping {#negate-scoping}
The `negate()` method (or the `!` operator) applies a logical **NOT** to the filter chain. Because the filter is built with a chained builder, `negate()` operates on everything accumulated up to that point, not just the most recent method call. The position of `negate()` determines its scope: calling it early negates only the criteria accumulated before it, which are then **AND**ed with whatever follows; calling it at the end negates the entire accumulated expression.
```rust
// (NOT Programmable) AND sender == Alice
TransactionFilter::new()
.kinds([TransactionKind::Programmable])
.negate()
.sender(alice);
// NOT (Programmable AND sender == Alice)
TransactionFilter::new()
.kinds([TransactionKind::Programmable])
.sender(alice)
.negate();
```
For complex expressions where the scoping is not visually obvious, build sub-filters as named bindings and combine them with `or()`.
:::
### Local Reader
Colocate the data ingestion daemon with a full node and enable checkpoint dumping on the latter to set up a local stream source. After enabling, the full node starts dumping executed checkpoints as files to a local directory, and the data ingestion daemon subscribes to changes in the directory through an inotify-like mechanism. This approach allows minimizing ingestion latency (checkpoint are processed immediately after a checkpoint executor on a full node) and getting rid of dependency on an externally managed bucket.
To enable, add the following to your [full node configuration](../../operator/full-node/overview.mdx) file:
```yaml
checkpoint-executor-config:
checkpoint-execution-max-concurrency: 200
local-execution-timeout-sec: 30
data-ingestion-dir:
```
```mermaid
flowchart LR
subgraph IOTA
A("fa:fa-server Full node");
A-->B("fa:fa-folder Local directory");
B-->C[("fa:fa-gears
Indexer
daemon")];
end
subgraph cloud[Cloud storage]
pg(fa:fa-cloud Postgres);
bq(fa:fa-cloud BigQuery);
s1(fa:fa-cloud S3);
end
C-->cloud;
C<-->D("fa:fa-floppy-disk Progress store");
```
```rust file=/examples/custom-indexer/rust/local_reader.rs
```
Let's highlight a couple lines of code:
```rust
let worker_pool = WorkerPool::new(CustomWorker, "local_reader".to_string(), concurrency);
executor.register(worker_pool).await?;
```
The data ingestion executor can run multiple workflows simultaneously. For each workflow, you need to create a separate worker pool and register it in the executor. The `WorkerPool` requires an instance of the `Worker` trait, the name of the workflow (which is used for tracking the progress of the flow in the progress store and metrics), and concurrency.
The concurrency parameter specifies how many threads the workflow uses. Having a concurrency value greater than 1 is helpful when tasks are idempotent and can be processed in parallel and out of order. The executor only updates the progress/watermark to a certain checkpoint when all preceding checkpoints are processed.
### Hybrid Mode
Specify both a local and remote store as a fallback to ensure constant data flow. The framework always prioritizes locally available checkpoint data over remote data. It's useful when you want to start utilizing your own full node for data ingestion but need to partially backfill historical data or just have a failover.
```rust file=/examples/custom-indexer/rust/hybrid_reader.rs
```
### Manifest
Code for the `Cargo.toml` manifest file for the custom indexer.
```toml file=/examples/custom-indexer/rust/Cargo.toml
```
## Source Code
Find the following source code in the [IOTA repo](https://github.com/iotaledger/iota/tree/main/examples/custom-indexer/rust).
[iota-data-ingestion-core]: https://github.com/iotaledger/iota/tree/develop/crates/iota-data-ingestion-core
---
## Migrating to GraphQL
This guide compares JSON-RPC queries to their equivalent GraphQL counterpart. While it is possible to systematically rewrite JSON-RPC queries (for example, iota_getTotalTransactionBlocks) to their GraphQL counterparts using this guide, it is recommended that you revisit your application's query patterns to take full advantage of the flexibility that GraphQL offers in serving queries that touch multiple potentially nested endpoints (for example transactions, balances, coins), and use the following examples to get a flavor of how the two APIs express similar concepts.
For a comprehensive list of all available GraphQL features, consult the [reference](../../developer/references/iota-graphql.mdx).
### Example 1: Get total transaction blocks
The goal is to get the total number of transaction blocks in the network.
```json
{
"jsonrpc": "2.0",
"id": 1,
"method": "iota_getTotalTransactionBlocks",
"params": []
}
```
```graphql
query {
checkpoint {
networkTotalTransactions
}
}
```
### Example 2: Get a specific transaction block
The goal is to get the transaction block by its digest.
```json
{
"jsonrpc": "2.0",
"id": 1,
"method": "iota_getTransactionBlock",
"params": [
"Hay2tj3GcDYcE3AMHrej5WDsHGPVAYsegcubixLUvXUF",
{
"showInput": true,
"showRawInput": false,
"showEffects": true,
"showEvents": true,
"showObjectChanges": false,
"showBalanceChanges": false
}
]
}
```
```graphql
query {
transactionBlock(digest: "Hay2tj3GcDYcE3AMHrej5WDsHGPVAYsegcubixLUvXUF") {
gasInput {
gasSponsor {
address
}
gasPrice
gasBudget
}
effects {
status
timestamp
checkpoint {
sequenceNumber
}
epoch {
epochId
referenceGasPrice
}
}
}
}
```
### Example 3: Get coin objects owned by an address
The goal is to return all `Coin<0x2::iota::IOTA>` objects an address owns.
```json
query {
"jsonrpc": "2.0",
"id": 1,
"method": "iotax_getCoins",
"params": [
"0x5094652429957619e6efa79a404a6714d1126e63f551f4b6c7fb76440f8118c9", //owner
"0x2::iota::IOTA", //coin type
"0xe5c651321915b06c81838c2e370109b554a448a78d3a56220f798398dde66eab", //cursor
3 //limit
]
}
```
```graphql
query {
address(address: "0x5094652429957619e6efa79a404a6714d1126e63f551f4b6c7fb76440f8118c9") {
coins(
first: 3,
after: "IAB3ha2PEA4ESRF4UErsJufJEwYpmSbCq7UNpxIHnLhG",
type: "0x2::iota::IOTA"
) {
nodes {
address
}
}
}
}
```
:::info
The cursor is now passed in the `after` (or `before`) fields on the connection, and the limit in the `first` or `last` fields.
:::
## Related links
- [GraphQL reference](../../developer/references/iota-graphql.mdx): Auto-generated GraphQL reference for IOTA RPC.
- [GraphQL quick-start](../getting-started/graphql-rpc.mdx): Querying IOTA RPC with GraphQL gets you started using GraphQL to query the IOTA RPC for on-chain data.
- [GraphQL concepts](../graphql-rpc.mdx): GraphQL for IOTA RPC examines the elements of GraphQL that you should know to get the most from the service.
---
## Introducing Move 2024
IOTA launches with the "Move 2024" edition, bringing enhanced features to improve both the writing and readability of Move code. These updates refine the source language without impacting the on-chain binary representation, allowing users to enjoy a smoother experience with the latest language improvements.
The primary goal of the "Move 2024" edition is to make Move easier to write and, ideally, easier to read. The minimal breaking changes introduced in the source language are designed to better prepare Move for future advancements.
This document highlights some new features to try out and shows how to use them in your existing modules.
:::info
Please, provide any feedback or report any issues you encounter via
[GitHub](https://github.com/iotaledger/iota/issues/new/choose) or the [IOTA Builders Discord](https://discord.gg/iota-builders).
:::
## New features
:::info
Below are examples of how to rewrite some legacy code in the Move 2024 edition.
If you find legacy code in the Move examples and would like to rewrite it based on Move 2024, refer to these examples.
:::
### Method Syntax
You can now call certain function methods using the `.` syntax. For example, the following call:
```move
vector::push_back(&mut v, coin::value(&c));
```
Can now be written as:
```move
v.push_back(c.value());
```
Where the receiver of the method (`v` and `c` in this example) is automatically borrowed if necessary (as `&mut v` and `&c` respectively).
You can call any function defined in the same module as the receiver's type as a method if it takes the receiver as its first argument.
For functions defined outside the module, you can declare methods using `public use fun` and `use fun`.
### Index Syntax
With method syntax, you can annotate certain functions as being `#[syntax(index)]` methods. You then call these methods using `v[i]`-style calls.
For example,
```move
*&mut v[i] = v[j];
```
resolves to
```move
*vector::borrow_mut(&mut v, i) = *vector::borrow(&v, j);
```
### Macro Functions
Higher-order functions (such as `map,` `filter,` `fold,` `for_each,` etc.) are useful in many languages for concisely transforming collections. Move does not have lambdas, closures, or function pointers, making defining these operations impossible.
Macro functions will allow for Move to mimic these sorts of operations without supporting the behavior at runtime. The body of the macro mimicking the "higher-order function" will be inlined at each call site. And the call site can provide a "lambda" that will be substituted as the macro is expanded. For example:
```move
let v2 = v.map!(|x| x + 1);
```
Or
```move
v.for_each!(|x| foo(x));
```
The "lambdas" additionally will support control flow through break and return.
### Enums
Enumerations allow you to define a single type that may hold multiple different shapes of data. Unlike structs, which always have the same fields, enums can have different fields depending on the variant of the enum. For example, in `enum Option { None, Some(T) }`, the variant None has no fields, and the variant Some has a single field of type `T`.
Move allows destructuring enums using match expressions. Some examples of enums in Move are the following:
```move
public enum Color {
RGB { red: u8, green: u8, blue: u8 },
HSL { hue: u16, saturation: u8, lightness: u8 },
Hex(u32)
}
public enum Option {
None,
Some(T),
}
public fun is_rgb_color(color: &Color): bool {
match (color) {
Color::RGB { red: _, green: _, blue: _ } => true,
_ => false,
}
}
const EOptionIsNone: u64 = 0;
public fun unwrap_some(option: Option): T {
match (option) {
Option::Some(x) => x,
Option::None => abort EOptionIsNone,
}
}
```
Move will add support for basic high-level enums that have similar visibility rules to structs in Move today; the enumeration type is publicly visible, just like struct types, but the variants of the enumeration are not public, much like fields. However, we plan to add public variants in the future. Similarly, enumerations cannot be recursive at release, but we plan to support this in the future.
### public(package)
`friend` declarations, and the associated `public(friend)` visibility modifiers, are deprecated. In their place is the `public(package)` visibility modifier, which allows calling functions only within the same package where they are defined.
### Positional Fields
You can now define `struct`s with positional fields, which are accessed by zero-based index. For example,
```move
public struct Pair(u64, u64) has copy, drop, store;
```
then to access each field,
```move
public fun sum(p: &Pair): u64 {
p.0 + p.1
}
```
And as this example shows, you can now declare abilities after the struct field list.
### Postfix `has` Ability Declarations
With positional fields, it is a bit awkward to read `has` declarations in the middle of a declaration. As an alternative, `has` can now be written after the fields. For example, both will be valid:
```move
struct Wrapper1 has copy, drop, store (u64)
```
```move
struct Wrapper2(u64) has copy, drop, store;
```
### Nested `use` and Standard Library Defaults
You can now nest `use` aliases for more conciseness.
```move
use iota::{balance, coin::{Self, Coin}};
```
Additionally, the following `use` declarations are now automatically included in every module:
```move
use std::vector;
use std::option::{Self, Option};
use iota::object::{Self, ID, UID};
use iota::transfer;
use iota::tx_context::{Self, TxContext};
```
### Automatic Referencing in Equality
Equality operations, `==` and `!=`, now automatically borrow if one side is a reference and the other is not. For example,
```move
fun check(x: u64, r: &u64): bool {
x == r
}
```
is equivalent to
```move
fun check(x: u64, r: &u64): bool {
&x == r
}
```
This automatic borrowing can occur on either side of `==` and `!=`.
### Loop Labels
When nesting loops, it can be convenient to break to the outer loop. For example,
```move
let mut i = 0;
let mut j = 0;
let mut terminate_loop = false;
while (i < 10) {
while (j < 10) {
if (haystack(i, j) == needle) {
terminate_loop = true;
break;
};
j = j + 1;
};
if (terminate_loop) break;
i = i + 1;
}
```
Now, you can directly name the outer loop (`outer` in this case) and break it all at once:
```move
let mut i = 0;
let mut j = 0;
'outer: while (i < 10) {
while (j < 10) {
if (haystack(i, j) == needle) break'outer;
j = j + 1;
};
i = i + 1;
}
```
### Type Inference Holes `_` On Type Annotations
With type directed programming, often you need to annotate a variable declaration or provide type arguments. But, sometimes you really only need to annotate on specific type, but the other types can be inferred. `_` will be added to allow that type to still be inferred, even when other parts of the type are annotated. For example
```move
dynamic_field::borrow_mut>(&mut id, owner)
```
could be rewritten as
```move
dynamic_field::borrow_mut<_, Coin>(&mut id, owner)
```
where the `_` would be inferred as `address`
### `break` With Value
It's now possible to `break` with a value from a `loop`. For example,
```move
let mut i = 0;
let x: u64 = loop {
if (v[i] > 10) break i;
i = i + 1;
};
```
You can achieve this with labels, as well. For example,
```move
let mut i = 0;
let mut j = 0;
let item = 'outer: loop {
while (j < 10) {
let item = haystack(i, j);
if (item == needle) break'outer option::some(item);
j = j + 1;
};
i = i + 1;
if (i == 10) break option::none();
};
```
### Named Blocks With Enhanced Control Flow Operations
Move 2024 supports naming `loop`, `while`, and normal blocks, allowing for more-complex control
flow.
Previous code with nested `while` loops (such as this simplified excerpt from deepbook) would need to
set a flag to break both loops:
```move
let mut terminate_loop = false;
while (...loop_condition...) {
while (...inner_condition...) {
...
if (...break_condition...) {
terminate_loop = true;
}
...
if (terminate_loop) {
break;
}
}
if (terminate_loop) {
break;
}
}
```
Now, you can directly name the outer loop and break it all at once:
```move
let mut terminate_loop = false;
while (...loop_condition...) 'outer: {
while (...inner_condition...) {
...
if (...break_condition...) {
terminate_loop = true;
}
...
if (terminate_loop) {
break 'outer;
}
}
}
```
This will immediately break to the outer loop, allowing more precise control flow when you'd like
to escape from loops.
This feature also works with normal loop forms, including breaks with values:
```move
let y = loop 'outer: {
let _x = loop 'inner: {
if (true) {
break 'outer 10;
} else {
break 'inner 20
}
};
};
```
In this toy example, `y` will take on the value `10` because the first `break` will break the
'outer` loop with that value.
Finally, this feature can be applied to normal blocks in Move, but instead utilizes the `return`
keyword. This can be useful when sequencing a block of code that may need early returns with values.
```move
public fun auth_user(auth_one: EasyAuth, auth_two: AuthTwo): u64 {
let auth_token = 'auth: {
let maybe_auth_token = try_auth(auth_one);
if (valid_auth(maybe_auth_token)) {
return 'auth unpack_auth(maybe_auth_token);
}
// ... more complicated code involving auth_two
};
// ... code using the auth_token
}
```
While we do not expect programmers to use named blocks with return in everyday cases, we anticipate
that they will ease the development and usage of macros significantly.
## Breaking Changes
### Datatype Visibility Requirements
Currently, all structs in Move are, by convention, public: any other module or package can import them and refer to them by type. To make this clearer, Move 2024 requires that all structs be declared with the `public` keyword. For example:
```move
// legacy code
struct S { x: u64 }
// Move 2024 code
public struct S { x: u64 }
```
Any non-public struct produces an error at this time, though the Move team is working on new visibility options for future releases.
### Mutability Requirements
Previously, all variables in Move were implicitly mutable. For example:
```move
fun f(s: S, y: u64): u64 {
let a = 0;
let S { x } = s;
a = 1;
x = 10;
y = 5;
x + y
}
```
Now, you must declare mutable variables explicitly:
```move
fun f(s: S, mut y: u64): u64 {
let mut a = 0;
let S { mut x } = 5;
a = 1;
x = 10;
y = 5;
x + y
}
```
The compiler now produces an error if you attempt to reassign or borrow a variable mutably without this explicit declaration.
### Removing Friends and `public(friend)`
Friends and the `public(friend)` visibilities were introduced early in Move's development, predating even the package system. As indicated in the [public(package)](#publicpackage) section, `public(package)` deprecates `public(friend)` in Move 2024.
The following declaration now produces an error:
```move
module pkg::m {
friend pkg::a;
public(friend) fun f() { ... }
}
module pkg::a {
fun calls_f() { ... pkg::m::f() ... }
}
```
Instead, if you want your function to be visible only in the package, write:
```move
module pkg::m {
public(package) fun f() { ... }
}
module pkg::a {
// this now works directly
fun calls_f() { ... pkg::m::f() ... }
}
```
### New Keywords
Looking toward the future, Move 2024 Beta adds the following keywords to the language: `enum`, `for`, `match`, `mut`, and `type`. Unfortunately, the compiler now produces parsing errors when it finds these in other positions. This is a necessary change as the language matures.
### Revised Paths and Namespaces
Move 2024 revises how paths and namespaces work compared to legacy Move, toward easing `enum` aliasing in the future. Consider the following snippet from a test annotation in the `iota_system` library:
```move
use iota_system::iota_system;
...
#[expected_failure(abort_code = iota_system::validator_set::EInvalidCap)]
```
Legacy Move would always treat a three-part name as an address(`iota_system`), module(`validator_set`), and module member (`EInvalidCap`). Move 2024 respects scope for `use`, so `iota_system` in the attribute resolves to the module, producing a name resolution error overall.
To avoid cases where this is the intended behavior, Move 2024 introduces a prefix operation for global qualification. To use, you can rewrite this annotation as:
```move
use iota_system::iota_system;
...
#[expected_failure(abort_code = ::iota_system::validator_set::EInvalidCap)]
// ^ note `::` here
```
## Move 2024 Editions
The beta release of Move 2024 comes with some powerful new features in addition to the breaking changes described here. There are also more on the horizon, such as syntactic macros, enums with pattern matching, and other user-defined syntax extensions.
#### `beta` Edition
- `beta` (specified via `edition = "2024"`) is the recommended edition. It includes all the new
features mentioned above and all breaking changes. While there is the risk of breaking changes or
bugs in `beta`, you should feel comfortable using it in your projects. As new features are added
and tested, they will be included in the `beta` edition. The `beta` edition will end after _all_
features for the year have been added and finalized.
#### `alpha` Edition
- `alpha` (specified via `edition = "2024.alpha"`) will get new features and changes as they are
developed. Breaking changes to features in `alpha` should be expected. As such, take caution when
using`alpha` in your projects.
---
## The IOTA Repository
You can find all the official crates and tools offered by IOTA in
the [IOTA monorepo](https://github.com/iotaledger/iota/).
It contains all the source code used to build on and run the IOTA network. The following section will give a brief
overview of the most important folders:
- [apps](https://github.com/iotaledger/iota/tree/develop/apps) Contains the source code for the main web applications
that
IOTA runs, for example, the `IOTA Wallet`.
- [crates](https://github.com/iotaledger/iota/tree/develop/crates): Contains all the Rust crates that are part of the
IOTA
system.
- [dapps](https://github.com/iotaledger/iota/tree/develop/dapps): Contains some examples of decentralized applications
built on top of IOTA, such as Kiosk or Sponsored Transactions.
- [dashboards](https://github.com/iotaledger/iota/tree/develop/dashboards): Currently empty.
- [doc](https://github.com/iotaledger/iota/tree/develop/doc): Contains deprecated documentation related to Move and
IOTA.
- [docker](https://github.com/iotaledger/iota/tree/develop/docker): Contains the docker files needed to spin up a node,
an
indexer, a full node, or other services.
- [docs](https://github.com/iotaledger/iota/tree/develop/docs): Contains this documentation and the source for this
site.
- [examples](https://github.com/iotaledger/iota/tree/develop/examples): Contains examples of apps written for IOTA and
smart contracts written in Move.
- [external-crates](https://github.com/iotaledger/iota/tree/develop/external-crates): Contains the source code for the
Move
programming language.
- [kiosk](https://github.com/iotaledger/iota/tree/develop/kiosk): Contains the source code of the `IOTA Kiosk`
extensions and rules, as well as examples.
- [nre](https://github.com/iotaledger/iota/tree/develop/nre): Contains information about node and network reliability
engineering.
- [scripts](https://github.com/iotaledger/iota/tree/develop/scripts): Contains a number of scripts that are used
internally.
- [sdk](https://github.com/iotaledger/iota/tree/develop/sdk): Contains the source code for different tools and SDKs,
such
as the IOTA TypeScript SDK, Kiosk SDK, BCS, dApp kit, etc.
- [iota-execution](https://github.com/iotaledger/iota/tree/develop/iota-execution): Contains the source code responsible
for abstracting access to the execution layer.
The following primary directories offer a good starting point for exploring the IOTA codebase:
- [move](https://github.com/iotaledger/iota/tree/develop/external-crates/move) - Move VM, compiler, and tools.
- [typescript-sdk](https://github.com/iotaledger/iota/tree/develop/sdk/typescript/) - the IOTA TypeScript SDK.
- [wallet](https://github.com/iotaledger/iota/tree/develop/apps/wallet) - Chrome extension wallet for IOTA.
- [iota](https://github.com/iotaledger/iota/tree/develop/crates/iota) - the IOTA command line tool.
- [iota-core](https://github.com/iotaledger/iota/tree/develop/crates/iota-core) - Core IOTA components.
- [iota-execution](https://github.com/iotaledger/iota/tree/develop/iota-execution) - Execution Layer (programmable
transactions, execution integration).
- [iota-framework](https://github.com/iotaledger/iota/tree/develop/crates/iota-framework) - Move system packages (0x1,
0x2,
0x3).
- [iota-network](https://github.com/iotaledger/iota/tree/develop/crates/iota-network) - Networking interfaces.
- [iota-node](https://github.com/iotaledger/iota/tree/develop/crates/iota-node) - Validator and full node software.
- [iota-protocol-config](https://github.com/iotaledger/iota/tree/develop/crates/iota-protocol-config) - On-chain system
configuration and limits.
- [iota-sdk](https://github.com/iotaledger/iota/tree/develop/crates/iota-sdk) - The IOTA Rust SDK.
- [iota-types](https://github.com/iotaledger/iota/tree/develop/crates/iota-types) - IOTA object types, such as coins and
gas.
## Branch and Network Structure
The main branches in the IOTA repository correspond to its
networks ([`devnet`](#devnet), [`testnet`](#testnet), [`mainnet`](#mainnet)) plus a `develop` branch with the most
recent changes.
### Devnet
The `devnet` branch is the latest stable build of IOTA. Choose the `devnet` branch if you want to build or test on
IOTA Devnet. If you encounter an issue or find a bug, it may already be fixed in the [`develop`](#develop) branch. To
submit a PR, you should push commits to your fork of the [`develop`](#develop) branch.
### Testnet
The `testnet` branch includes the code running on the IOTA Testnet network.
### Mainnet
The `mainnet` branch includes the code running on the IOTA Mainnet network.
### Develop
The `develop` branch includes the most recent changes and updates. Use the `develop` branch if you want to contribute to
the
IOTA project or to experiment with cutting-edge functionality. The `develop` branch might include unreleased changes and
experimental features, so use it at your own risk.# The IOTA Repository
---
## On-Chain Randomness
Generating pseudo-random values in Move is similar to solutions in other languages. A Move function can create a new instance of `RandomGenerator` and use it for generating random values of different types, for example, `generate_u128(&mut generator), generate_u8_in_range(&mut generator, 1, 6)`, or,
```move
entry fun roll_dice(r: &Random, ctx: &mut TxContext): Dice {
let mut generator = new_generator(r, ctx); // generator is a PRG
Dice { value: random::generate_u8_in_range(&mut generator, 1, 6) }
}
```
`Random` has a reserved address `0x8`. See random.move for the Move APIs for accessing randomness on IOTA.
:::note
Although `Random` is a shared object, it is inaccessible for mutable operations, and any transaction attempting to modify it fails.
:::
Having access to random numbers is only one part of designing secure applications, you should also pay careful attention to how you use that randomness.
To securely access randomness:
- Define your function as (private) `entry`.
- Prefer generating randomness using function-local `RandomGenerator`.
- Make sure that the "unhappy path" of your function does not charge more gas than the "happy path".
## Limited Resources and `Random` Dependent Flows
Keep in mind that some resources that are available for transactions are limited.
If you are not careful, an attacker can break or exploit your application by deliberately controlling the point where your function runs out of resources.
Concretely, [gas](../../about-iota/tokenomics/gas-pricing.mdx) is such a resource.
Consider the following vulnerable code:
```move
// Insecure implementation, do not use!
entry fun insecure_play(r: &Random, payment: Coin, ...) {
...
let mut generator = new_generator(r, ctx);
let win = generator.generate_bool();
if (win) { // happy flow
... cheap computation ...
} else {
... very expensive computation ...
}
}
```
Observe that the gas costs of a transaction that calls `insecure_play` depends on the value of `win`.
An attacker could call this function with a gas budget that is sufficient for the "happy flow" but not the "unhappy one", resulting in it either winning or reverting the transaction (but never losing the payment).
:::warning
The [`Random`](../../developer/references/framework/iota/random) API does not automatically prevent this kind of attack, and you must be aware of this subtlety when designing your contracts.
:::
Other limited resources per transaction that you should consider are:
- The number of new objects.
- The number of objects that can be used (including dynamic fields).
- Number of events emitted.
- Number of UIDs generated, or deleted, or transferred.
For many use cases, like when selecting a raffle winner or lottery numbers, this attack is not an issue as the code running is independent of the randomness.
However, in the cases where it can be problematic, you can consider one of the following:
- Split the logic into two functions that must be called by different transactions:
1. The first function, called by transaction `tx1`, fetches a random value and stores it in an object that is unreadable by other commands in `tx1` (for example, by transferring the object to the caller or, by storing the tx digest and checking it is different on read).
2. A second function, called by the second transaction, `tx2`, reads the stored value and completes the operation.
`tx2` might indeed fail, but now the random value is fixed and cannot be modified using repeated calls.
It is important that the inputs to the second function are fixed and cannot be modified after `tx1` (otherwise, an attacker can modify them after seeing the randomness committed by `tx1`).
It is also important to gracefully handle cases in which the second step is never completed (for example, charging a fee for the first step).
You can find an [example implementation](https://github.com/iotaledger/iota/blob/develop/examples/move/random/random_nft/sources/example.move#L121-L147) in the IOTA Repository.
- Write the function so that the happy flow consumes more gas than the unhappy one.
- Keep in mind that external functions or native ones can change in the future, potentially resulting in different costs compared to the time you conducted your tests.
- Transaction profiling via `iota-tool` can be used to profile the costs of a transaction. See [Profile a transaction](../../developer/references/cli/iota-tool.mdx#profile-a-transaction) for details.
## Use (non-public) `entry` Functions
While composition is very powerful for smart contracts, it opens the door to attacks on functions that use randomness.
Consider for example a betting game that uses randomness for rolling dice:
```move
module games::dice {
...
public enum Ticket has drop {
Lost,
Won,
}
public fun is_winner(t: &Ticket): bool {
match (t) {
Ticket::Won => true,
Ticket::Lost => false,
}
}
/// If you guess correctly the output, then you get a GuessedCorrectly object.
/// Otherwise you get nothing.
public fun play_dice(guess: u8, fee: Coin, r: &Random, ctx: &mut TxContext): Ticket {
// Pay for the turn
assert!(coin::value(&fee) == 1000000, EInvalidAmount);
transfer::public_transfer(fee, CREATOR_ADDRESS);
// Roll the dice
let mut generator = new_generator(r, ctx);
if (guess == generator.generate_u8_in_range(1, 6)) {
Ticket::Won
} else {
Ticket::Lost
}
}
...
}
```
An attacker can deploy the next function:
```move
public fun attack(guess: u8, r: &Random, ctx: &mut TxContext): Ticket {
let t = dice::play_dice(guess, r, ctx);
// revert the transaction if play_dice lost
assert!(!dice::is_winner(&t), 0);
t
}
```
The attacker can now call `attack` with a guess, and **always** revert the fee transfer if the guess is incorrect.
To protect against composition attacks, define your function as a private `entry` function so functions from other modules cannot call it.
:::tip
The Move compiler enforces this behavior by rejecting `public` functions with `Random` as an argument.
:::
## Programmable Transaction Block (Ptb) Restrictions
A similar attack to the one previously described involves PTBs _even_ when `play_dice` is defined as a private `entry` function.
For example, consider the `entry play_dice(guess: u8, fee: Coin, r: &Random, ctx: &mut TxContext): Ticket { … }` function defined earlier, the attacker can publish the function
```move
public fun attack(t: Ticket): Ticket {
assert!(!dice::is_winner(&t), 0);
t
}
```
and send a PTB with commands `play_dice(...), attack(Result(0))` where `Result(0)` is the output of the first command.
As before, the attack takes advantage of the atomic nature of PTBs and always reverts the _entire transaction_ if the
guess was incorrect, without paying the fee. Sending multiple transactions can repeat the attack, each one executed with
different randomness and reverted if the guess is incorrect.
:::tip
To protect against PTB-based composition attacks, IOTA rejects PTBs that have commands that are not `TransferObjects` or `MergeCoins` following a `MoveCall` command that uses `Random` as an input.
:::
## Instantiating `RandomGenerator`
`RandomGenerator` is secure as long as it's created by the consuming module. If passed as an argument, the caller might be able to predict the outputs of that `RandomGenerator` instance (for example, by calling `bcs::to_bytes(&generator)` and parsing its internal state).
:::tip
The Move compiler enforces this behavior by rejecting `public` functions with `RandomGenerator` as an argument.
:::
## Accessing `Random` from TypeScript
If you want to call `roll_dice(r: &Random, ctx: &mut TxContext)` in module `example`, use the following code snippet:
```typescript
const txb = new Transaction();
txb.moveCall({
target: "${PACKAGE_ID}::example::roll_dice",
arguments: [txb.object('0x8')]
});
...
```
---
## Advanced Topics
Information in the Advanced Topics section covers coding practices, useful features, and other developer-focused considerations that might arise as you continue your development journey on IOTA. The topics in this section aren't necessarily more difficult than other topics, but they include subjects you might not encounter or need to consider until you're developing more advanced solutions on the IOTA network.
## Asset Tokenization
Asset tokenization refers to the process of representing real-world assets, such as real estate, art, commodities, stocks, or other valuable assets, as digital tokens on the blockchain network. This involves converting the ownership or rights of an asset into digital tokens, which are then recorded and managed on the blockchain.
Go to [Asset Tokenization](advanced/asset-tokenization.mdx).
[//]: # ()
[//]: # (## Migrating to GraphQL )
[//]: # ()
[//]: # (See the Migrating to GraphQL guide to upgrade your smart contracts to use the GraphQL API.)
[//]: # ()
[//]: # (This guide compares JSON-RPC queries to their equivalent GraphQL counterpart. While it is possible to systematically rewrite JSON-RPC queries (for example, iota_getTotalTransactionBlocks) to their GraphQL counterparts using this guide, it is recommended that you revisit your application's query patterns to take full advantage of the flexibility that GraphQL offers in serving queries that touch multiple potentially nested endpoints (for example transactions, balances, coins), and use the following examples to get a flavor of how the two APIs express similar concepts.)
[//]: # ()
[//]: # (Go to [Migrating to GraphQL](advanced/graphql-migration.mdx).)
---
## Checkpoint Verification
On the IOTA network, checkpoints define the history of the blockchain. They are quite similar to the concept of blocks used by traditional blockchains like Bitcoin or Ethereum. The IOTA blockchain, however, forms checkpoints after transaction execution has already happened to provide a certified history of the chain, instead of being formed before execution.
Checkpoints contain:
- The cryptographic hash of the previous checkpoint.
- A list of all the transaction digests (and the corresponding transaction effects digests) that are included in the checkpoint.
- A set of signatures from a quorum (more than 2/3rds) of the validators that formed the committee at the time the checkpoint was created.
Both validators and full nodes consume checkpoints to remain synchronized with the network.
## Checkpoint verification
For full nodes and validators to trust a checkpoint, they must first verify it. Verification ensures that the checkpoint is a true checkpoint that the IOTA validator committee created.
Checkpoint verification requires two interdependent pieces:
1. Assuming that the full node (or other client) has the public keys of the validator committee that created the checkpoint, it can check the signatures on the checkpoint for validity.
Checkpoints are signed by the aggregated BLS signatures of a quorum of the committee.
If the signatures are valid, the client now knows that the checkpoint was created by the validator committee, and not by some other party.
1. By validating checkpoints, the client can determine the make-up of the committee, because the final checkpoint of each epoch contains the validator committee (including the public keys) of the next epoch.
These pieces seem to create a circular dependency issue. The client needs to know the committee to verify checkpoints, which in turn allows it to learn what the committee is for each epoch. To solve this problem, the process is bootstrapped by starting from the genesis checkpoint, which is the earliest checkpoint in an IOTA network. The genesis checkpoint contains the initial validator committee, which allows a client to verify all checkpoints in the history by using the following process:
1. The client obtains the genesis checkpoint from some trusted source.
1. The client loads the initial committee from the genesis checkpoint.
1. The client uses the state sync network or IOTA archive to obtain the next checkpoint.
1. The client verifies the signatures on the checkpoint using the current committee's public keys, and verifies that the checkpoint's previous checkpoint hash is equal to the hash of the previous checkpoint that the client validated.
1. If the checkpoint is invalid, an error is raised.
1. Otherwise, the client checks if the checkpoint is the last one of the current epoch.
- If so, load the next committee from it, and use that committee as the current committee.
- If not, return to step 3 and continue.
This allows the client to eventually verify all checkpoints up to the present time.
## What do checkpoints commit to?
After a client verifies a checkpoint, what can it do with that information?
As mentioned earlier, a checkpoint contains a list of transactions so a full node, for instance, can begin fetching and executing those transactions. Because the transactions are identified by their digest (a cryptographic hash), the client can be sure that the transactions it executes have not been altered.
Additionally, the checkpoint contains the effects digests of each transaction. The effects digest is the cryptographic hash of the `TransactionEffects`, which is itself a structure that lists all of the inputs and outputs of a transaction. It includes the digests of all objects that were written by the transaction.
This allows a full node to verify that it has obtained the same execution results as those that the validators attested to when signing the checkpoint.
By executing checkpoints, and verifying transaction outputs, a full node can build up the entire state of the IOTA network (that is, the collection of objects in the network) and trust that every byte of every object is correct.
---
## Elliptic Curve Verifiable Random Function
A verifiable random function (VRF) is a cryptographic primitive that enables you to generate a random number and provide proof that the number used a secret key for generation. Anyone can verify the proof using the public key corresponding to the secret key, so you can use it as a random number generator (RNG) that generates outputs that anyone can verify. Applications that need verifiable randomness on chain can also benefit from its use.
## VRF construction
The VRF used in the Move API in IOTA is an elliptic curve VRF (ECVRF) following the [CFRG VRF draft specifications version 15](https://datatracker.ietf.org/doc/draft-irtf-cfrg-vrf/15/). It uses [Ristretto255](https://ristretto.group) elliptic curve group construction with the SHA-512 hash function. The nonce is generated according to [RFC6979](https://www.rfc-editor.org/info/rfc6979).
Any implementation following the same specifications with suite string `iota_vrf` (see section 5 in the [VRF specs](https://datatracker.ietf.org/doc/draft-irtf-cfrg-vrf/15/)) can be used to compute VRF output and generate proofs.
The [fastcrypto](https://github.com/MystenLabs/fastcrypto) library provides a CLI tool for such an implementation and is used in the following example.
### Generate keys
From the root of the `fastcrypto` repository, run the following command to generate a key pair:
```shell
cargo run --bin ecvrf-cli keygen
```
This outputs a secret key and a public key in hex format. Both the secret and public keys are 32-byte strings:
````shell
Secret key: c0cbc5bf0b2f992fe14fee0327463c7b03d14cbbcb38ce2584d95ee0c112b40b
Public key: 928744da5ffa614d65dd1d5659a8e9dd558e68f8565946ef3d54215d90cba015
````
### Compute VRF output and proof
To compute the VRF output and proof for the input string `Hello, world!`, which is `48656c6c6f2c20776f726c6421` in hexadecimal, with the key pair generated previously, run the following command:
```shell
cargo run --bin ecvrf-cli prove --input 48656c6c6f2c20776f726c6421 --secret-key c0cbc5bf0b2f992fe14fee0327463c7b03d14cbbcb38ce2584d95ee0c112b40b
```
This should the 80-byte proof and VRF 64-byte output, both in hex format:
```shell
Proof: 18ccf8bf316f00b387fc6e7b26f2d3ddadbf5e9c66d3a30986f12b208108551f9c6da87793a857d79261338a50430074b1dbc7f8f05e492149c51313381248b4229ebdda367146dbbbf95809c7fb330d
Output: 2b7e45821d80567761e8bb3fc519efe5ad80cdb4423227289f960319bbcf6eea1aef30c023617d73f589f98272b87563c6669f82b51dafbeb5b9cf3b17c73437
```
### Verify proof
You can verify the proof and output in a smart contract using `iota::ecvrf::ecvrf_verify` from the IOTA Move framework:
```move file=/docs/examples/move/cryptography/sources/ecvrf.move
```
You can also use the CLI tool for verification:
```shell
cargo run --bin ecvrf-cli verify --output 2b7e45821d80567761e8bb3fc519efe5ad80cdb4423227289f960319bbcf6eea1aef30c023617d73f589f98272b87563c6669f82b51dafbeb5b9cf3b17c73437 --proof 18ccf8bf316f00b387fc6e7b26f2d3ddadbf5e9c66d3a30986f12b208108551f9c6da87793a857d79261338a50430074b1dbc7f8f05e492149c51313381248b4229ebdda367146dbbbf95809c7fb330d --input 48656c6c6f2c20776f726c6421 --public-key 928744da5ffa614d65dd1d5659a8e9dd558e68f8565946ef3d54215d90cba015
```
The preceding command returns the verification:
```shell
Proof verified correctly!
```
---
## Groth16
A zero-knowledge proof allows a prover to validate that a statement is true without revealing any information about the inputs. For example, a prover can validate that they know the solution to a sudoku puzzle without revealing the solution.
Zero-knowledge succinct non-interactive argument of knowledge (zk-SNARKs) are a family of zero-knowledge proofs that are non-interactive, have succinct proof size and efficient verification time. An important and widely used variant of them is pairing-based zk-SNARKs like the [Groth16](https://eprint.iacr.org/2016/260.pdf) proof system, which is one of the most efficient and widely used.
The Move API in IOTA enables you to verify any statement that can be expressed in a NP-complete language efficiently using Groth16 zk-SNARKs over either the BN254 or BLS12-381 elliptic curve constructions.
There are high-level languages for expressing these statements, such as [Circom](https://docs.circom.io), used in the following example.
Groth16 requires a trusted setup for each circuit to generate the verification key. The API is not pinning any particular verification key and each user can generate their own parameters or use an existing verification to their apps.
## Usage
The following example demonstrates how to create a Groth16 proof from a statement written in Circom and then verify it using the IOTA Move API. The API currently supports up to eight public inputs.
### Create circuit
The proof demonstrates that we know a secret input to a hash function which gives a certain public output.
```circom
pragma circom 2.1.5;
include "node_modules/circomlib/circuits/poseidon.circom";
template Main() {
component poseidon = Poseidon(1);
signal input in;
signal output digest;
poseidon.inputs[0] <== in;
digest <== poseidon.out;
}
component main = Main();
```
We use the [Poseidon hash function](https://www.poseidon-hash.info) which is a ZK-friendly hash function. Assuming that the [circom compiler has been installed](https://docs.circom.io/getting-started/installation/), the above circuit is compiled using the following command:
```shell
circom main.circom --r1cs --wasm
```
This outputs the constraints in R1CS format and the circuit in Wasm format.
### Generate proof
To generate a proof verifiable in IOTA, you need to generate a witness. This example uses Arkworks' [ark-circom](https://github.com/gakonst/ark-circom) Rust library. The code constructs a witness for the circuit and generates a proof for it for a given input. Finally, it verifies that the proof is correct.
```rust
use ark_bn254::Bn254;
use ark_circom::CircomBuilder;
use ark_circom::CircomConfig;
use ark_groth16::Groth16;
use ark_snark::SNARK;
fn main() {
// Load the WASM and R1CS for witness and proof generation
let cfg = CircomConfig::::new("main.wasm", "main.r1cs").unwrap();
// Insert our secret inputs as key value pairs. We insert a single input, namely the input to the hash function.
let mut builder = CircomBuilder::new(cfg);
builder.push_input("in", 7);
// Create an empty instance for setting it up
let circom = builder.setup();
// WARNING: The code below is just for debugging, and should instead use a verification key generated from a trusted setup.
// See for example https://docs.circom.io/getting-started/proving-circuits/#powers-of-tau.
let mut rng = rand::thread_rng();
let params =
Groth16::::generate_random_parameters_with_reduction(circom, &mut rng).unwrap();
let circom = builder.build().unwrap();
// There's only one public input, namely the hash digest.
let inputs = circom.get_public_inputs().unwrap();
// Generate the proof
let proof = Groth16::::prove(¶ms, circom, &mut rng).unwrap();
// Check that the proof is valid
let pvk = Groth16::::process_vk(¶ms.vk).unwrap();
let verified = Groth16::::verify_with_processed_vk(&pvk, &inputs, &proof).unwrap();
assert!(verified);
}
```
The proof shows that an input (7) which, when hashed with the Poseidon hash function, gives a certain output (which in this case is `inputs[0].to_string() = 7061949393491957813657776856458368574501817871421526214197139795307327923534`).
### Verification in IOTA
The API in IOTA for verifying a proof expects a special processed verification key, where only a subset of the values are used. Ideally, computation for this prepared verification key happens only once per circuit. You can perform this processing using the `iota::groth16::prepare_verifying_key` method of the IOTA Move API with a serialization of the `params.vk` value used previously.
The output of the `prepare_verifying_key` function is a vector with four byte arrays, which corresponds to the `vk_gamma_abc_g1_bytes`, `alpha_g1_beta_g2_bytes`, `gamma_g2_neg_pc_bytes`, `delta_g2_neg_pc_bytes`.
To verify a proof, you also need two more inputs, `public_inputs_bytes` and `proof_points_bytes`, which contain the public inputs and the proof respectively. These are serializations of the `inputs` and `proof` values from the previous example, which you can compute in Rust as follows:
```rust
let mut vk_bytes = Vec::new();
params.vk.serialize_compressed(&mut vk_bytes).unwrap();
let mut public_inputs_bytes = Vec::new();
for i in 0..inputs.len() { // if there is more than one public input, serialize one by one
inputs[i].serialize_compressed(&mut inputs_bytes).unwrap();
}
let mut proof_points_bytes = Vec::new();
proof.serialize_compressed(&mut proof_points_bytes).unwrap();
```
The following example smart contract prepares a verification key and verifies the corresponding proof. This example uses the BN254 elliptic curve construction, which is given as the first parameter to the `prepare_verifying_key` and `verify_groth16_proof` functions. You can use the `bls12381` function instead for BLS12-381 construction.
```move file=/docs/examples/move/cryptography/sources/goth16.move
```
---
## Hashing
A cryptographic hash function is a widely used cryptographic primitive that maps an arbitrary length input to a fixed length output, the hash value. The hash function is designed to be a one-way function, which means that it is infeasible to invert the function to find the input data from a given hash value, and to be collision resistant, which means that it is infeasible to find two different inputs that map to the same hash value.
The IOTA Move API supports the following cryptographic hash functions:
* SHA2-256 as `std::hash::sha2_256`
* SHA3-256 as `std::hash::sha3_256`
* Keccak256 as `iota::hash::keccak256`
* Blake2b-256 as `iota::hash::blake2b256`
## Usage
The SHA2-256 and SHA3-256 hash functions are available in the Move Standard Library in the `std::hash` module. The following example shows how to use the SHA2-256 hash function in a smart contract:
```move file=/docs/examples/move/cryptography/sources/hashing_std.move
```
The Keccak256 and Blake2b-256 hash functions are available through the `iota::hash` module in the IOTA Move Library. An example of how to use the Keccak256 hash function in a smart contract is shown below. Notice that here, the input to the hash function is given as a reference. This is the case for both Keccak256 and Blake2b-256.
```move file=/docs/examples/move/cryptography/sources/hashing_iota.move
```
---
## IOTA On-Chain Signatures Verification in Move
Move contracts in IOTA support verifications for several signature schemes on-chain. Not all signatures supported in on-chain verification are supported as user signature verification. See [IOTA Signatures](../transaction-auth/signatures.mdx) for valid signature schemes for transaction authorization.
This topic covers:
1. How to use [fastcrypto](https://github.com/MystenLabs/fastcrypto)'s CLI tool to create a signature of a given scheme. For testing and debugging only, DO NOT use in production.
1. Call the Move method on-chain to verification by submitting the signature, the message and the public key.
Signature schemes covered:
- Ed25519 signature (64 bytes)
- Secp256k1 non-recoverable signature (64 bytes)
- Secp256k1 recoverable signature (65 bytes)
- Secp256r1 non-recoverable signature (64 bytes)
- Secp256r1 recoverable signature (65 bytes)
- BLS G1 signature (minSig setting)
- BLS G2 signature (minPk setting)
## Usage
### Set up fastcrypto CLI binary
```shell
git clone git@github.com:MystenLabs/fastcrypto.git
cd fastcrypto/
cargo build --bin sigs-cli
```
### Sign with CLI and submit to on-chain Move method
#### Ed25519 signature (64 bytes)
1. Generate a key and sign a message.
```shell
target/debug/sigs-cli keygen --scheme ed25519 --seed 0000000000000000000000000000000000000000000000000000000000000000
Private key in hex: $SK
Public key in hex: $PK
target/debug/sigs-cli sign --scheme ed25519 --msg $MSG --secret-key $SK
Signature in hex: $SIG
Public key in hex: $PK
```
2. Call the verify method in Move. All inputs are represented in bytes in hex format:
```move
use iota::ed25519;
let msg = x"$MSG";
let pk = x"$PK";
let sig = x"$SIG";
let verify = ed25519::ed25519_verify(&sig, &pk, &msg);
assert!(verify == true, 0);
```
#### Secp256k1 non-recoverable signature (64 bytes)
1. Generate a key and sign a message.
```shell
target/debug/sigs-cli keygen --scheme secp256k1 --seed 0000000000000000000000000000000000000000000000000000000000000000
Private key in hex: $SK
Public key in hex: $PK
target/debug/sigs-cli sign --scheme secp256k1 --msg $MSG --secret-key $SK
Signature in hex: $SIG
Public key in hex: $PK
```
2. Call the verify method in Move.
```move
use iota::ecdsa_k1;
let msg = x"$MSG";
let pk = x"$PK";
let sig = x"$SIG";
// The last param 1 represents the hash function used is SHA256, the default hash function used when signing in CLI.
let verify = ecdsa_k1::secp256k1_verify(&sig, &pk, &msg, 1);
assert!(verify == true, 0);
```
#### Secp256k1 recoverable signature (65 bytes)
1. Generate a key and sign a message.
```shell
target/debug/sigs-cli keygen --scheme secp256k1-rec --seed 0000000000000000000000000000000000000000000000000000000000000000
Private key in hex: $SK
Public key in hex: $PK
target/debug/sigs-cli sign --scheme secp256k1-rec --msg $MSG --secret-key $SK
Signature in hex: $SIG
Public key in hex: $PK
```
2. Call the ecrecover method in Move and check equality.
```move
use iota::ecdsa_k1;
let msg = x"$MSG";
let pk = x"$PK";
let sig = x"$SIG";
// The last param 1 represents the hash function used is SHA256, the default hash function used when signing in CLI.
let recovered = ecdsa_k1::secp256k1_ecrecover(&sig, &msg, 1);
assert!(pk == recovered, 0);
```
#### Secp256r1 non-recoverable signature (64 bytes)
1. Generate a key and sign a message.
```shell
target/debug/sigs-cli keygen --scheme secp256r1 --seed 0000000000000000000000000000000000000000000000000000000000000000
Private key in hex: $SK
Public key in hex: $PK
target/debug/sigs-cli sign --scheme secp256r1 --msg $MSG --secret-key $SK
Signature in hex: $SIG
Public key in hex: $PK
```
2. Call the verify method in Move.
```move
use iota::ecdsa_r1;
let msg = x"$MSG";
let pk = x"$PK";
let sig = x"$SIG";
// The last param 1 represents the hash function used is SHA256, the default hash function used when signing in CLI.
let verify = ecdsa_r1::secp256r1_verify(&sig, &pk, &msg, 1);
assert!(verify == true, 0);
```
#### Secp256r1 recoverable signature (65 bytes)
1. Generate a key and sign a message.
```shell
target/debug/sigs-cli keygen --scheme secp256r1-rec --seed 0000000000000000000000000000000000000000000000000000000000000000
Private key in hex: $SK
Public key in hex: $PK
target/debug/sigs-cli sign --scheme secp256r1-rec --msg $MSG --secret-key $SK
Signature in hex: $SIG
Public key in hex: $PK
```
2. Call the ecrecover method in Move and check equality.
```move
use iota::ecdsa_r1;
let msg = x"$MSG";
let pk = x"$PK";
let sig = x"$SIG";
// The last param 1 represents the hash function used is SHA256, the default hash function used when signing in CLI.
let recovered = ecdsa_r1::secp256r1_ecrecover(&sig, &msg, 1);
assert!(pk == recovered, 0);
```
#### BLS G1 signature (48 bytes, minSig setting)
1. Generate a key and sign a message.
```shell
target/debug/sigs-cli keygen --scheme bls12381-minsig --seed 0000000000000000000000000000000000000000000000000000000000000000
Private key in hex: $SK
Public key in hex: $PK
target/debug/sigs-cli sign --scheme bls12381-minsig --msg $MSG --secret-key $SK
Signature in hex: $SIG
Public key in hex: $PK
```
2. Call the verify method in Move.
```move
use iota::bls12381;
let msg = x"$MSG";
let pk = x"$PK";
let sig = x"$SIG";
let verified = bls12381::bls12381_min_sig_verify(&sig, &pk, &msg);
assert!(verified == true, 0);
```
#### BLS G1 signature (96 bytes, minPk setting)
1. Generate a key and sign a message.
```shell
target/debug/sigs-cli keygen --scheme bls12381-minpk --seed 0000000000000000000000000000000000000000000000000000000000000000
Private key in hex: $SK
Public key in hex: $PK
target/debug/sigs-cli sign --scheme bls12381-minpk --msg $MSG --secret-key $SK
Signature in hex: $SIG
Public key in hex: $PK
```
2. Call the verify method in Move.
```move
use iota::bls12381;
let msg = x"$MSG";
let pk = x"$PK";
let sig = x"$SIG";
let verified = bls12381::bls12381_min_pk_verify(&sig, &pk, &msg);
assert!(verified == true, 0);
```
---
## Cryptography in Smart Contracts
Effective use of cryptography keeps your smart contract transactions secure on the IOTA blockchain.
## Signature verification
Move contracts in IOTA support verifications for several on-chain signature schemes. Not all signatures supported in on-chain verification are supported as user signature verification. See [Signatures](./transaction-auth/signatures.mdx) for valid signature schemes for transaction authorization.
Go to [IOTA On-Chain Signatures Verification in Move](./on-chain/signing.mdx).
## Groth16
A zero-knowledge proof is a method by which a party, known as the prover, can confirm the truthfulness of a claim without disclosing any information about the underlying data. For instance, it's possible for the prover to demonstrate they have solved a sudoku puzzle without showing the actual solution. Groth16 is one such proof you can use in your smart contracts.
Go to [Groth16](./on-chain/groth16.mdx).
## Hashing
A cryptographic hash function is a widely used cryptographic primitive that maps an arbitrary length input to a fixed length output, the hash value. The hash function is designed to be a one-way function, which means that it is infeasible to invert the function to find the input data from a given hash value, and to be collision resistant, which means that it is infeasible to find two different inputs that map to the same hash value. Use available hashing functions to provide security to your smart contracts.
Go to [Hashing](./on-chain/hashing.mdx).
## Elliptic Curve Verifiable Random Function (ECVRF)
Use ECVRFs to generate a random number and provide proof that the number used a secret key for generation. The public key corresponding to the secret key verifies the proof, so you can use it as a random number generator that generates outputs that anyone can verify. Applications that need verifiable randomness on chain can also benefit from its use.
Go to [ECVRF](./on-chain/ecvrf.mdx).
## Related links
- [Cryptography concepts](../cryptography.mdx): Before you use the guides, you might want to learn about the concepts behind the use of cryptography on IOTA.
---
## Intent Signing
In IOTA, an intent is a compact struct that serves as the domain separator for a message that a signature commits to. The data that the signature commits to is an intent message. All signatures in IOTA must commit to an intent message, instead of the message itself.
## Motivation
In previous releases, IOTA used a special `Signable` trait that attached the Rust struct name as a prefix to the serialized data. This is not ideal because it's:
* **Not compact:** The prefix `TransactionData::` is significantly larger than 1 byte.
* **Not user-friendly:** Non-Rust applications need to maintain a list of Rust-struct names.
The intent signing standard provides a compact domain separator to the data being signed for both user signatures and authority signatures. It has several benefits, including:
* The intent scope is replaced by a u8 representation instead of a Rust struct tag name string.
* In addition to the intent scope, other important domain separators can be committed as well (such as intent version and app id).
* The data itself no longer needs to implement the `Signable` trait, it just needs to implement `Serialize`.
* All signatures can adopt the same intent message structure, including both user signatures (only to commit to `TransactionData`) and authority signature (commits to all internal intent scopes such as `TransactionEffects`, `ProofOfPossession`, and `SenderSignedTransaction`).
## Structs
The `IntentMessage` struct consists of the intent and the serialized data value.
```rust
pub struct IntentMessage {
pub intent: Intent,
pub value: T,
}
```
To create an intent struct, include the `IntentScope` (what the type of the message is), `IntentVersion` (what version the network supports), and `AppId` (what application that the signature refers to).
```rust
pub struct Intent {
scope: IntentScope,
version: IntentVersion,
app_id: AppId,
}
```
To see a detailed definition for each field, see each enum definition [in the source code](https://github.com/iotaledger/iota-rust-sdk/blob/develop/crates/iota-sdk-types/src/crypto/intent.rs).
The serialization of an `Intent` is a 3-byte array where each field is represented by a byte.
The serialization of an `IntentMessage` is the 3 bytes of the intent concatenated with the BCS serialized message.
## User Signature
To create a user signature, construct an intent message first, and create the signature over the 32-byte Blake2b hash of the BCS serialized value of the intent message of the transaction data (`intent || message`).
Here is an example in Rust:
```rust
let intent = Intent::default();
let intent_msg = IntentMessage::new(intent, data);
let signature = Signature::new_secure(&intent_msg, signer);
```
Here is an example in TypeScript:
```typescript
const intentMessage = messageWithIntent('TransactionData', transactionBytes);
const signature = await this.sign(intentMessage);
```
Under the hood, the `new_secure` method in Rust and the `signData` method in TypesScript does the following:
1. Serializes the intent message as the 3-byte intent concatenated with the BCS serialized bytes of the transaction data.
1. Applies Blake2b hash to get the 32-byte digest
1. Passes the digest to the signing API for each corresponding scheme of the signer. The supported signature schemes are pure Ed25519, ECDSA Secp256k1 and ECDSA Secp256r1. See [IOTA Signatures](signatures.mdx#signature-requirements) for requirements of each scheme.
## Authority Signature
The authority signature is created using the authority key. The data that it commits to is also an intent message `intent || message`. See all available intent scopes [in the source code](https://github.com/iotaledger/iota-rust-sdk/blob/develop/crates/iota-sdk-types/src/crypto/intent.rs)
### How to Generate Proof of Possession for an Authority
When an authority request to join the network, the authority public key and its proof of possession (PoP) are required to be submitted. PoP is required to prevent [rogue key attack](https://crypto.stanford.edu/~dabo/pubs/papers/BLSmultisig.html).
The proof of possession is a BLS signature created using the authority's private key, committed over the following message: `intent || pubkey || address || epoch`. Here `intent` is serialized to `[5, 0, 0]` representing an intent with scope as "Proof of Possession", version as "V0" and app_id as "IOTA". `pubkey` is the serialized public key bytes of the authority's BLS authority key. `address` is the account address associated with the authority's account key. `epoch` is serialized to `[0, 0, 0, 0, 0, 0, 0, 0]`.
To generate a proof of possession in Rust, see implementation at `fn generate_proof_of_possession`. For test vectors, see `fn test_proof_of_possession`.
# Implementation
1. [Struct and enum definitions](https://github.com/iotaledger/iota-rust-sdk/blob/develop/crates/iota-sdk-types/src/crypto/intent.rs)
2. [Test](https://github.com/iotaledger/iota/blob/develop/crates/iota-types/src/unit_tests/intent_tests.rs)
---
## Keys and Addresses
IOTA adheres to widely accepted wallet specifications in the cryptocurrency industry, including BIP-32 (and its variation, SLIP-0010) and its variation SLIP-0010, BIP-44, and BIP-39, to facilitate key management for users. At present, IOTA supports pure Ed25519, ECDSA Secp256k1, ECDSA Secp256r1, and multisig for signed transactions.
Follow the relevant link for more information on each wallet specification:
- [BIP-32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki)
- [BIP-39](https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki)
- [BIP-44](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki)
- [SLIP-0010](https://github.com/satoshilabs/slips/blob/master/slip-0010)
## Key derivation scheme
IOTA follows SLIP-0010 for managing wallets that support the Ed25519 (EdDSA) signing scheme.
For managing wallets that support the Ed25519 (EdDSA) signing scheme, IOTA follows SLIP-0010, which enforces wallets to always derive child private keys from parent private keys using the hardened key path.
IOTA follows BIP-32 for managing wallets that support the ECDSA Secp256k1 and ECDSA Secp256r1 signing scheme.
BIP-32 defines the hierarchical deterministic wallet structure to logically associate a set of keys. Grouping keys in this manner reduces the overhead of keeping track of a large number of private keys for a user. This method also lets custodians issue distinct managed addresses for each user account under one source of control. Using BIP-32 decouples the private key derivation from the public key derivation, enabling the watch-only wallet use case, where a chain of public keys and its addresses can be derived, while the private key can be kept offline for signing.
## Key derivation path
BIP-44 further defines the five levels of the derivation path with their exact meanings:
`m / purpose' / coin_type' / account' / change / address_index`. In this structure, the slashes indicate new levels, or children, in the hierarchy.
The `purpose` level is generally set to 44, corresponding to the BIP number. In IOTA, however, the purpose level distinguishes different signing schemes: 44 is set for Ed25519, 54 for ECDSA Secp256k1 and 74 for Secp256r1. While it is non-standard to set the purpose level to a value that is not 44, it is common to use the purpose field to distinguish different signing schemes. BIP-49 and BIP-84, for example, are used to identify script types in Bitcoin. IOTA chose 54 to indicate ECDSA Secp256k1 because there is no existing BIP under 54, avoiding confusion with any Bitcoin standard.
The `coin_type` value is managed with a repository of all other cryptocurrencies. Both signature schemes use IOTA's registered coin_type, 4218 (IOTA on a telephone keypad).
The `account` level is usually used for logically separating user accounts and creating specific account categories.
It is generally accepted that, while account-based currencies define only the first three levels, UTXO-based currencies add change and address level definitions. Because IOTA's object-oriented data model is neither UTXO nor account-based (it in fact combines both), it employs all five levels for maximum compatibility.
| Scheme | Path | Comments |
| --------------- | --------------------------------------------- | ---------------------------------------------- |
| Ed25519 | `m/44'/4218'/{account}'/{change}'/{address}'` | Each level of the derivation path is hardened. |
| ECDSA Secp256k1 | `m/54'/4218'/{account}'/{change}/{address}` | The first three levels are hardened. |
| ECDSA Secp256r1 | `m/74'/4218'/{account}'/{change}/{address}` | The first three levels are hardened. |
## Mnemonics support
After IOTA defines the deterministic way to derive the master key from a seed, BIP-39 is introduced to make the seed more human-readable and memorizable using mnemonics. IOTA accepts 12, 15, 18, 21, and 24 words from the BIP-39 word list that is properly checksummed, corresponding to 128, 160, 192, 224, and 256 bits of entropy. IOTA Wallet and SDKs provide a flexible interface to sign transactions with various signing schemes.
## Address format
For deriving a 32-byte IOTA address, IOTA hashes the signature scheme flag 1-byte concatenated with public key bytes using the [BLAKE2b](https://www.blake2.net/) (256 bits output) hashing function. IOTA address currently supports pure Ed25519, Secp256k1, Secp256r1, and MultiSig with corresponding flag bytes of 0x00, 0x01, 0x02, and 0x03, respectively.
:::warning Ed25519 hashing exception
The exception to this is the Ed25519 scheme, which is the default. The BLAKE2b hash for Ed25519 public keys does not have a flag prepended before hashing unlike the other siging schemes.
:::
## Example
IOTA Wallet and SDKs provide a flexible interface to sign transactions with various signing schemes.
```typescript
const keypair = Ed25519Keypair.deriveKeypair(TEST_MNEMONIC, `m/44'/4218'/0'/0'/0'`);
const address = keypair.getPublicKey().toIotaAddress();
```
```shell
iota keytool import "TEST_MNEMONIC" ed25519 "m/44'/4218'/0'/0'/0'"
iota client new-address --key-scheme ed25519 --derivation-path "m/44'/4218'/0'/0'/0'"
```
See more test vectors for [pure Ed25519](https://github.com/iotaledger/iota/blob/f3b5fdd73da64a0df65fb4323471512b0f57ec4d/sdk/typescript/test/unit/cryptography/ed25519-keypair.test.ts) or [ECDSA Secp256k1](https://github.com/iotaledger/iota/blob/199f06d25ce85f0270a1a5a0396156bb2b83122c/sdk/typescript/test/unit/cryptography/secp256k1-keypair.test.ts).
---
## Multisig
IOTA supports multi-signature (multisig) transactions, which require multiple keys for authorization rather than a single, one-key signature. In technical terms, IOTA supports `k` out of `n` multisig transactions, where `k` is the threshold and `n` is the total weights of all participating parties. The maximum number of parties is 10. To learn more about the single key signatures that IOTA supports, see [Signatures](signatures.mdx).
Valid participating keys for multisig are Pure Ed25519, ECDSA Secp256k1, and ECDSA Secp256r1. A ([u8](https://doc.rust-lang.org/std/primitive.u8.html)) weight is set for each participating keys and the threshold can be set as [u16](https://doc.rust-lang.org/std/primitive.u16.html). If the serialized multisig contains enough valid signatures of which the sum of weights passes the threshold, IOTA considers the multisig valid and the transaction executes.
## Applications of multisig
IOTA allows you to mix and match key schemes in a single multisig account. For example, you can pick a single Ed25519 mnemonic-based key and two ECDSA secp256r1 keys to create a multisig account that always requires the Ed25519 key, but also one of the ECDSA secp256r1 keys to sign. You could use this structure for mobile secure enclave stored keys as two-factor authentication.
:::info
Currently, iPhone and high-end Android devices support only ECDSA secp256r1 enclave-stored keys.
:::
Compared to threshold signatures, a multisig account is generally more flexible and straightforward to implement and use,
without requiring complex multi-party computation (MPC) account setup ceremonies and related software, and any
dependency in threshold crypto providers. Additionally, apart from the ability to mix and match key schemes and setting
different weights for each key (which is complex in threshold cryptography), multisig accounts are
"accountable" and "transparent" by design because both participating parties and observers can see who signed each
transaction. On the other hand, threshold signatures provide the benefits of hiding the threshold policy, but also
resulting in a single signature payload, making it indistinguishable from a single-key account.

_Multisig structures supported in IOTA._
## Example workflow
The following steps demonstrate how to create a multisig transaction and then submit it against a local network using the [IOTA CLI](../../references/cli.mdx). A transaction can be the transfer of an object, the publish or upgrade of a package, the payment of IOTA, and so on. To learn how to set up a local network, see [Connect to a Local Network](/developer/getting-started/local-network.mdx).
### Step 1: Create keys
Use the following command to generate an IOTA address and key for each supported key scheme and add it to the `iota.keystore`, then list the keys.
Use `iota client` to create IOTA addresses of different key schemes.
```shell
iota client new-address --key-scheme ed25519
iota client new-address --key-scheme secp256k1
iota client new-address --key-scheme secp256r1
```
### Step 2: Add keys to IOTA keystore
Use `iota keytool` to list the signatures you created in the previous step.
```shell
iota keytool list
```
The response resembles the following, but displays actual addresses, keys, and peer IDs:
```shell
╭────────────────────────────────────────────────────────────────────────────────────────────╮
│ ╭─────────────────────────┬──────────────────────────────────────────────────────────────╮ │
│ │ alias │ │ │
│ │ iotaAddress │ │ │
│ │ publicBase64Key │ │ │
│ │ publicBase64KeyWithFlag │ │ │
│ │ keyScheme │ ed25519 │ │
│ │ flag │ 0 │ │
│ │ peerId │ │ │
│ ╰─────────────────────────┴──────────────────────────────────────────────────────────────╯ │
│ ╭─────────────────────────┬──────────────────────────────────────────────────────────────╮ │
│ │ alias │ │ │
│ │ iotaAddress │ │ │
│ │ publicBase64Key │ │ │
│ │ publicBase64KeyWithFlag │ │ │
│ │ keyScheme │ secp256k1 │ │
│ │ flag │ 1 │ │
│ │ peerId │ │ │
│ ╰─────────────────────────┴──────────────────────────────────────────────────────────────╯ │
│ ╭─────────────────────────┬──────────────────────────────────────────────────────────────╮ │
│ │ alias │ │ │
│ │ iotaAddress │ │ │
│ │ publicBase64Key │ │ │
│ │ publicBase64KeyWithFlag │ │ │
│ │ keyScheme │ secp256r1 │ │
│ │ flag │ 2 │ │
│ │ peerId │ │ │
│ ╰─────────────────────────┴──────────────────────────────────────────────────────────────╯ │
╰────────────────────────────────────────────────────────────────────────────────────────────╯
```
## Step 3: Create a multisig address
To create a multisig address, input a list of public keys to use for the multisig address and a list of their corresponding weights and the threshold (replacing `` with actual values).
```shell
iota keytool multi-sig-address --pks --weights 1 2 3 --threshold 3
```
The response resembles the following:
```
╭─────────────────┬────────────────────────────────────────────────────────────────────────────────────╮
│ multisigAddress │ │
│ multisig │ ╭────────────────────────────────────────────────────────────────────────────────╮ │
│ │ │ ╭─────────────────────────┬──────────────────────────────────────────────────╮ │ │
│ │ │ │ address │ │ │ │
│ │ │ │ publicBase64KeyWithFlag │ │ │ │
│ │ │ │ weight │ 1 │ │ │
│ │ │ ╰─────────────────────────┴──────────────────────────────────────────────────╯ │ │
│ │ │ ╭─────────────────────────┬──────────────────────────────────────────────────╮ │ │
│ │ │ │ address │ │ │ │
│ │ │ │ publicBase64KeyWithFlag │ │ │ │
│ │ │ │ weight │ 2 │ │ │
│ │ │ ╰─────────────────────────┴──────────────────────────────────────────────────╯ │ │
│ │ │ ╭─────────────────────────┬──────────────────────────────────────────────────╮ │ │
│ │ │ │ address │ │ │ │
│ │ │ │ publicBase64KeyWithFlag │ │ │ │
│ │ │ │ weight │ 3 │ │ │
│ │ │ ╰─────────────────────────┴──────────────────────────────────────────────────╯ │ │
│ │ ╰────────────────────────────────────────────────────────────────────────────────╯ │
│ threshold │ 3 │
╰─────────────────┴────────────────────────────────────────────────────────────────────────────────────╯
```
## Step 4: Send objects to a multisig address
This example requests gas from a local network using the default URL following the guidance in [Connect to a Local Network](/developer/getting-started/local-network.mdx). If following along, be sure to replace `` with the address you receive in the previous step.
```shell
curl --location --request POST 'http://127.0.0.1:9123/gas' --header 'Content-Type: application/json' --data-raw "{ \"FixedAmountRequest\": { \"recipient\": \"\" } }"
```
The response resembles the following:
```
{"transferred_gas_objects":[{"amount":200000,"id":"", ...}]}
```
## Step 5: Serialize any transaction
This section demonstrates how to use an object that belongs to a multisig address and serialize a transfer to be signed. The `tx_bytes` value can be any serialized transaction data where the sender is the multisig address. Use the `--serialize-unsigned-transaction` flag for supported commands in `iota client -h` (`publish`, `upgrade`, `call`, `transfer`, `pay`, `pay-all-iota`, `pay-iota`, `split`, `merge-coin`) to output the Base64 encoded transaction bytes.
```shell
iota client transfer --to --object-id --serialize-unsigned-transaction --sender
Raw tx_bytes to execute:
```
:::info
Use the --sender option to set the address of the (multisig) account that will be signing the transaction.
:::
## Step 6: Sign the transaction with two keys
Use the following code sample to sign the transaction with two keys in `iota.keystore`. You can do this with other tools as long as you serialize it to `flag || sig || pk`.
```shell
iota keytool sign --address --data
Raw tx_bytes to execute:
Serialized signature (`flag || sig || pk` in Base64): $SIG_1
iota keytool sign --address --data
Raw tx_bytes to execute:
Serialized signature (`flag || sig || pk` in Base64): $SIG_2
```
## Step 7: Combine individual signatures into a multisig
This sample demonstrates how to combine the two signatures:
```shell
iota keytool multi-sig-combine-partial-sig --pks --weights 1 2 3 --threshold 3 --sigs
multisig address: # Informational
multisig parsed: # Informational
multisig serialized:
```
You need only the signatures of the participating signers whose sum of weights `>=k`. You must provide all public keys and their weights, and the threshold that defined the multisig address.
## Step 8: Execute a transaction with multisig
Use `iota client` to execute a transaction using multisig:
```shell
iota client execute-signed-tx --tx-bytes --signatures
```
---
## Signatures
When a user submits a signed transaction, a serialized signature and a serialized transaction data is submitted. The serialized transaction data is the BCS serialized bytes of the struct `TransactionData` and the serialized signature is defined as a concatenation of bytes of `flag || sig || pk`.
The `flag` is a 1-byte representation corresponding to the signature scheme that the signer chooses. The following table lists each signing scheme and its corresponding flag:
| Scheme | Flag |
| --------------- | ---- |
| Ed25519 Pure | 0x00 |
| ECDSA Secp256k1 | 0x01 |
| ECDSA Secp256r1 | 0x02 |
| multisig | 0x03 |
The `sig` bytes are the compressed bytes representation of the signature instead of DER encoding. The following table lists the expected size of each format:
| Scheme | Signature |
| --------------- | ------------------------------------------ |
| Pure Ed25519 | Compressed, 64 bytes |
| ECDSA Secp256k1 | Non-recoverable, compressed, 64 bytes |
| ECDSA Secp256r1 | Non-recoverable, compressed, 64 bytes |
| multisig | BCS serialized all signatures, size varies |
The `pk` bytes are the bytes representation of the public key corresponding to the signature.
| Scheme | Public key |
| --------------- | --------------------------------------------------------- |
| Pure Ed25519 | Compressed, 32 bytes |
| ECDSA Secp256k1 | Compressed, 33 bytes |
| ECDSA Secp256r1 | Compressed, 33 bytes |
| multisig | BCS serialized all participating public keys, size varies |
## Signature requirements
The signature must commit to the hash of the intent message of the transaction data, which you can construct by appending the 3-byte intent before the BCS serialized transaction data. To learn more on what an intent is and how to construct an intent message, see [IOTA Intent Signing](intent-signing.mdx).
When invoking the signing API, you must first hash the intent message of the transaction data to 32 bytes using Blake2b. This external hashing is distinct from the hashing performed inside the signing API. To be compatible with existing standards and hardware secure modules (HSMs), the signing algorithms perform additional hashing internally. For ECDSA Secp256k1 and Secp256r1, you must use SHA-2 SHA256 as the internal hash function. For pure Ed25519, you must use SHA-512.
An accepted ECDSA secp256k1 and secp256r1 signature must follow:
1. The internal hash used by ECDSA must be SHA256 [SHA-2](https://en.wikipedia.org/wiki/SHA-2) hash of the transaction data. IOTA uses SHA256 because it is supported by [Apple](https://developer.apple.com/forums/thread/89619), HSMs, and [cloud](https://developer.apple.com/forums/thread/89619), and it is widely adopted by [Bitcoin](https://en.bitcoin.it/wiki/Elliptic_Curve_Digital_Signature_Algorithm).
1. The signature must be of length 64 bytes in the form of `[r, s]` where the first 32 bytes are `r`, the second 32 bytes are `s`.
1. The `r` value can be between `0x1` and `0xFFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE BAAEDCE6 AF48A03B BFD25E8C D0364140` (inclusive).
1. The `s` value must be in the lower half of the curve order. If the signature is too high, convert it to a lower `s` according to [BIP-0062](https://github.com/bitcoin/bips/blob/master/bip-0062.mediawiki#low-s-values-in-signatures) with the corresponding curve orders using `order - s`. For secp256k1, the curve order is `0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141`. For secp256r1, the curve order is `0xFFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551` defined in [Standards for Efficient Cryptography](https://secg.org/SEC2-Ver-1.0.pdf).
1. Ideally, the signature must be generated with deterministic nonce according to [RFC6979](https://www.rfc-editor.org/rfc/rfc6979).
An accepted pure Ed25519 signature must follow:
1. The signature must be produced according to [RFC 8032](https://www.rfc-editor.org/rfc/rfc8032.html#section-5.1.6). The internal hash used is SHA-512.
1. The signature must be valid according to [ZIP215](https://github.com/zcash/zips/blob/main/zip-0215.rst).
See a concrete example for offline signing using CLI in the [Offline Signing](../../ts-sdk/typescript/transaction-building/offline.mdx) topic.
## Authority signature
The Authority on IOTA (collection of validators) holds three distinctive keypairs:
1. [Authority key pair](#authority-key-pair)
1. [Account key pair](#account-key-pair)
1. [Network key pair](#network-key-pair)
### Authority key pair
The Authority key pair provides authority signatures on user-signed transactions if they are verified. When a stake of the authorities that provide signatures on user transactions passes the required two-thirds threshold, IOTA executes the transaction. IOTA uses the BLS12381 scheme for its fast verification on aggregated signatures for a given number of authorities. In particular, IOTA uses the minSig BLS mode, where each individual public key is 96 bytes, while the signature is 48 bytes. The latter is important as typically validators register their keys once at the beginning of each epoch and then they continuously sign transactions; thus, we optimize on minimum signature size.
As with the BLS scheme, you can aggregate independent signatures resulting in a single BLS signature payload. IOTA also accompanies the aggregated signature with a bitmap to denote which of the validators signed. This effectively reduces the authorities' signature size from (2f + 1) × `BLS_sig` size to just one `BLS_sig` payload, which in turn has significant network cost benefits resulting in compressed transaction certificates independently on the validators set size.
To counter potential rogue key attacks on BLS12381 aggregated signatures, proof of knowledge of the secret key (KOSK) is used during authority registration. When an authority requests to be added to the validator set, a proof of possession is submitted and verified. See [Intent Signing](intent-signing.mdx) on how to create a proof of possession. Unlike most standards, the IOTA proof of knowledge scheme commits to the address as well, which offers an extra protection against adversarial reuse of a validator's BLS key from another malicious validator.
### Account key pair
The account that the authority uses to receive payments on staking rewards is secured by the account key pair. IOTA uses pure Ed25519 as the signing scheme.
### Network key pair
The private key is used to perform the TLS handshake required by QUIC for validator primary and its worker network interface. The public key is used for validator peer ID. Pure Ed25519 is used as the signing scheme.
See more authority key toolings in [Validator Tool](https://github.com/iotaledger/iota/blob/f8b5ad9aaecc3c4b30a060ec5e00bdad9ba75a93/nre/validator_tool.md).
---
## Transaction Authentication
Transaction authentication features on IOTA provide security against unauthorized access to on-chain data.
## Keys and Addresses
IOTA adheres to widely accepted wallet specifications in the cryptocurrency industry, including BIP-32 (and its variation, SLIP-0010), BIP-44, and BIP-39, to facilitate key management for users. At present, IOTA supports pure Ed25519, ECDSA Secp256k1, ECDSA Secp256r1, and multisig for signed transactions.
Go to [Keys and Addresses](transaction-auth/keys-addresses.mdx).
## Signatures
Cryptographic agility is core to IOTA. The system supports multiple cryptography algorithms and primitives and can switch between them rapidly. With IOTA, you can choose the right cryptography solution for your system and implement the latest algorithms as they become available.
Go to [Signatures](transaction-auth/signatures.mdx).
## Multisig
IOTA supports multi-signature (multisig) transactions, which require multiple keys for authorization rather than a single, one-key signature.
Go to [Multisig](transaction-auth/multisig.mdx).
## Offline Signing
IOTA supports offline signing, which is signing transactions using a device not connected to an IOTA network, or in a wallet implemented in a different programming language without relying on the IOTA key store.
Go to [Offline Signing](../ts-sdk/typescript/transaction-building/offline.mdx).
## Intent Signing
In IOTA, an intent is a compact struct that serves as the domain separator for a message that a signature commits to. The data that the signature commits to is an intent message. All signatures in IOTA must commit to an intent message, instead of the message itself.
Go to [Intent Signing](transaction-auth/intent-signing.mdx).
---
## Cryptography
Cryptographic agility is core to IOTA. The system supports multiple cryptography algorithms and primitives and can switch between them rapidly. With IOTA, you can choose the right cryptography solution for your system and implement the latest algorithms as they become available.
IOTA defines its cryptography primitives, such as public key, signature, aggregated signature, and hash functions, under one unified type alias or enum wrapper that is shared across the entire repository. Making changes to these primitives affects all of an application's components. You can quickly update application cryptography and be assured of uniform security.
## Transaction Authentication
Transaction authentication features on IOTA provide security against unauthorized access to on-chain data. Transaction Authentication provides an overview of related topics.
Go to [Transaction Authentication](./cryptography/transaction-auth.mdx).
## Checkpoint Verification
Checkpoints define the history of the IOTA blockchain, similarly to how blocks define the history of traditional blockchains like Bitcoin or Ethereum.
For full nodes and validators to trust a checkpoint, they must first verify it. Verification ensures that the checkpoint is a true checkpoint that the IOTA validator committee created.
Go to [Checkpoint Verification](./cryptography/checkpoint-verification.mdx).
## Smart Contract Cryptography
Effective use of cryptography keeps your smart contract transactions secure on the IOTA blockchain.
Go to [Cryptography in Smart Contracts](./cryptography/on-chain.mdx).
## Related links
- [Cryptography guides](cryptography/on-chain.mdx): See the cryptography guides for instruction on applying these concepts.
---
## IOTA Developer Cheat Sheet
Quick reference on best practices for IOTA Network developers.
## Dev Sheet
| **Commands** | **Description** |
|-|-|
|`which iota`|to check if iota is already installed or not.|
|`iota client`|to connect to IOTA network|
|`iota client envs`|to check environments|
|`iota client new-env --alias --rpc `|to create new environment.|
|`iota client switch --env `|to switch another environment.|
|`RUST_LOG="off,iota_node=info" cargo run --bin iota-localnet start --force-regenesis --with-faucet`|to start local network.|
|`iota keytool list`|to list all the address.|
|`iota move new first_package`|to create new move package.|
|`pnpm create @iota/dapp --template react-client-dapp`| to setup React app with dApp kit|
|`cargo install --locked --git https://github.com/iotaledger/iota.git --branch --features tracing iota`|To get the latest version of CLI|
|`iota client active-address`|to get the current address.|
|`iota client -–help`|to list out all commands of iota client.|
|`iota client new-address --key-scheme `|to generate address, **Scheme** - (ed25519,secp256k1,secp256r1)|
## Move
|**Topic**|**Description**|
|-|-|
|**General**| Upgrading a package (`P` to `P'`) doesn't auto-update dependencies; update dependent packages and clients explicitly. Public function signatures can't be deleted/changed; use `public(package)` or `private` visibility unless exposing permanent library functions. It is not possible to delete `struct` types, add new fields (though you can add dynamic fields), or add new [abilities](https://move-language.github.io/move/abilities.html) via an upgrade. Introduce new types carefully—they will live forever! Use `vector`-backed collections (`vector`, `VecSet`, `VecMap`, `PriorityQueue`) with a **known** maximum size of ≤ 1000 items. Use dynamic field-backed collections (`Table`, `Bag`, `ObjectBag`, `ObjectTable`, `LinkedTable`) for any collection that allows third-party addition, larger collections, and collections of unknown size. Move objects have a maximum size of 250KB—any attempt to create a larger object leads to an aborted transaction. Ensure that your objects do not have an ever-growing `vector`-backed collection. If your function `f` needs a payment in (e.g.) IOTA from the caller, use `fun f(payment: Coin)` not `fun f(payment: &mut Coin, amount: u64)`. This is safer for callers—they know exactly how much they are paying, and do not need to trust `f` to extract the right amount. Don't micro-optimize gas usage. IOTA computation costs are rounded up to the closest _bucket_, so only very drastic changes will make a difference. In particular, if your transaction is already in the lowest cost bucket, it can't get any cheaper. Follow the [Move coding conventions](https://move-language.github.io/move/coding-conventions.html) for consistent style. |
|**Composability**| Use the `display` standard to customize how your objects show up in wallets, apps, and explorers Avoid "self-transfers"—whenever possible, instead of writing `transfer::transfer(obj, tx_context::sender(ctx))`, return `obj` from the current function. This allows a caller or programmable transaction block to use `obj`. |
|**Testing**| - Use [`iota::test_scenario`](https://github.com/iotaledger/iota/blob/develop/crates/iota-framework/packages/iota-framework/sources/test/test_scenario.move) to mimic multi-transaction, multi-sender test scenarios.
- Use the [`iota::test_utils`](https://github.com/iotaledger/iota/blob/develop/crates/iota-framework/packages/iota-framework/sources/test/test_utils.move) module for better test error messages via `assert_eq`, debug printing via `print`, and test-only destruction via `destroy`.
- Use `iota move test --coverage` to compute code coverage information for your tests, and `iota move coverage source --module ` to see uncovered lines highlighted in red. Push coverage all the way to 100% if feasible. |
## Apps
| **Topic** | **Description** |
|-|-|
| **Optimal performance** | For optimal performance and data consistency, apps should use the wallet's [`signTransactionBlock`](../developer/ts-sdk/dapp-kit/index.mdx) API to sign transactions and then submit them via [`execute_transactionBlock`](/iota-api-ref#iota_executetransactionblock) on the app's full node. This ensures immediate read-after-write consistency, as the app's full node reflects writes instantly, avoiding delays from checkpointing. |
| **Lower latency** | For lower latency, use [`executeTransactionBlock`](/iota-api-ref#iota_executetransactionblock) with `"showEffects": false` and `"showEvents": false` if your app only needs confirmation of a transaction without immediate access to its effects or events.|
| **Local cache** | Apps should implement a local cache for frequently read data rather than over-fetching from the full node. |
| **Transaction cache**| Whenever possible,use programmable transaction blocks to compose on-chain functionality instead of deploying new contracts, enabling batching and lowering gas fees. |
|**Wallet dependency**| Apps should leave gas budget, gas price, and coin selection to the wallet. This gives wallets more flexibility, and it's the wallet's responsibility to dry run a transaction to ensure it doesn't fail. |
## Signing
| **Topic** | **Description** |
|-|-|
|**Concurrent Transactions**| Avoid signing concurrent transactions involving the same owned object. Use independent objects or wait for one transaction to finish to prevent client [equivocation](./references/iota-glossary.mdx#equivocation), which can lock the objects until the epoch ends. |
|**CLI transaction**| Use the `--serialize-output` flag with any iota client command (e.g., `publish`, `call`) to generate a base64 transaction for signing. |
|**Transaction Signing**| IOTA supports several signature schemes for transaction signing, including native multisig.|
---
## Developer Information
The developer section is meant to introduce you to the Move programming language and its implementation on the IOTA network through examples, tasks, and conceptual content. This contains everything a developer needs to get started developing on top of the IOTA network.
## Getting Started
If you are completely new to Move, you should start with the aptly named Getting Started section. Topics in that section introduce you to the IOTA monorepo, guide you through installing IOTA binaries, and introduce you to some key core concepts of blockchain technology, particularly how they relate to IOTA. This sections contains everything you need to get your first dApp built and deployed.
Go to [Getting Started](getting-started/getting-started.mdx).
## Network Overview
The [Network Overview](network-overview.mdx) page gives an overview of the different networks available in the IOTA ecosystem.
## Explanations
General explanations of important concepts when developing on IOTA
Go to [Explanations](./cryptography/transaction-auth.mdx).
## How Tos
The How Tos section contains practical guides on how to perform specific tasks when developing on IOTA. Specific how tos can be found in the corresponding sections throughout the developer documentation.
General how tos can be found here.
Go to [How To](./iota-101/transactions/transactions.mdx).
## Tutorials
The Tutorials section contains step-by-step guides to help you build specific applications on IOTA. Specific tutorials can be found in the corresponding sections throughout the developer documentation.
General tutorials can be found here.
Go to [Tutorials](./tutorials/simple-token-transfer.mdx).
## References
The References section contains reference material for IOTA development. Specific references can be found in the corresponding sections throughout the developer documentation.
General references can be found here.
Go to [References](./references/references.mdx).
## Move
The Move sections contains all explanations, how tos, tutorials and references related to the Move programming language and its concepts.
Go to [Move](./advanced/introducing-move-2024.mdx).
## SDKs
The SDKs section contains all explanations, how tos, tutorials and references related to the IOTA SDKs for different programming languages.
Go to [SDKs](./iota-sdk/getting-started/rust.mdx).
## GraphQL
The GraphQL section contains all explanations, how tos, tutorials and references related to the IOTA GraphQL API.
Go to [GraphQL](./getting-started/graphql-rpc.mdx).
## CLI
The CLI section contains all explanations, how tos, tutorials and references related to the IOTA Command Line Interface (CLI).
Go to [CLI](./references/cli.mdx).
## IOTA Trust Framework
The IOTA Trust Framework section contains all explanations, how tos, tutorials and references related to the components of the IOTA Trust Framework.
Go to [IOTA Trust Framework](./iota-trust-framework.mdx).
## Migrating from IOTA Stardust
IOTA Stardust becomes IOTA Rebased, and with it a lot of changes. Most assets are just available on the IOTA network without any manual work but for integrations and in some situations you might need to migrate. This section covers the details of the migration and how you can prepare your integration to be IOTA compatible.
Go to [Migrating from IOTA Stardust](stardust/stardust-migration.mdx).
## Account Abstraction in IOTA
The Account Abstraction section contains all explanations, how tos, tutorials and references related to the feature allows users to use smart contracts as their accounts.
Go to [Account Abstraction](account-abstraction.mdx).
## Developer Cheat Sheet
The cheat sheet is a compact overview of solutions for common problems and contains information on how to avoid common pitfalls for IOTA Move developers. This page contains important information that might get lost in the quantity of content available. Use this often-updated page to see around corners when starting a Move project or to refresh your memory on important concepts to be mindful of.
Go to the [Developer Cheat Sheet](dev-cheat-sheet.mdx).
## Solidity/EVM Smart contracts
Everything you need to know about our Layer 2 EVM Support, including working with the IOTA EVM chains.
Go to [EVM Smart Contracts](./iota-evm/iota-evm.mdx).
---
## Creating an ERC-721-like NFT
## How this works in Solidity / EVM
NFTs (Non-Fungible-Tokens) are a popular building block commonly used in the EVM ecosystem. The most widely used standard on EVM-based chains is the ERC-721 standard, which allows a smart contract to mint and transfer NFTs with some basic metadata. These standard NFTs can be used on many different platforms in a common way to be viewed, traded, and used in other ways.
Here's an example of a typical ERC-721 NFT built with Solidity on an EVM chain:
```solidity title="contracts/MyNFT.sol"
pragma solidity ^0.8.3;
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
contract MyNFT is ERC721, Ownable {
using Counters for Counters.Counter;
Counters.Counter private _tokenIds;
constructor() ERC721("MyNFT", "MNFT") {}
function mintNFT(address recipient, string memory tokenURI) public onlyOwner returns (uint256) {
_tokenIds.increment();
uint256 newItemId = _tokenIds.current();
_mint(recipient, newItemId);
_setTokenURI(newItemId, tokenURI);
return newItemId;
}
}
```
In this example, we can see that we are using the widely accepted and trusted [OpenZeppelin](https://www.openzeppelin.com/contracts) library to abstract some of the logic surrounding an ERC721 away. The contract inherits from `Ownable` and `ERC721`, making it compatible with the standard and 'owned', giving the owner some extra powers (in this case, to call the `mintNFT` function). The ERC721 is created with the constructor, and the `mintNFT` function creates a new ERC721 NFT for us and assigns it to the provided address. It also takes the `tokenURI` argument which is supposed to contain a URL to a JSON file containing some metadata about this NFT (this is typically not on-chain). All created NFTs are stored within the state of this contract in a mapping where the ID of the NFT points towards its owner and the `tokenURI` for more information about the specific NFT.
A lot of logic here is abstracted away, but every bit of logic can be overwritten - similar to the ERC-20 example. There's little enforcement of anything, which could lead to undesired situations. Also, using off-chain metadata means that if that data becomes unavailable, that data is lost, which is undesirable. There is no enforcement of the TokenURI contents either, meaning you can't rely on the contents being valid for what you wish to use the NFT for.
## How to NFT with IOTA Move
IOTA Move is based on objects instead of a global storage like EVM. Objects in IOTA Move can be owned, non-fungible, and unique - the exact properties of an NFT! This makes creating NFTs in IOTA Move very trivial, given that everything is already an NFT by default. An example of a very simplified NFT in IOTA Move:
```move file=/docs/examples/move/evm-to-move/sources/nft.move
```
This is just a simplified NFT that anyone can mint, with just a name in it as metadata. It can freely be transferred and burned, and the metadata can be directly accessed through the object from another contract. Given that this is just a normal object being created, there's little to add to this code example. It's straightforward if you know the basics of working with objects in IOTA.
### Using Object Display
The framework has a built-in feature to represent objects with templates that can be easily used for off-chain use. This allows you to save the most important data like IDs in your objects and construct, for example, a templated URL and Image URL inside a JSON object out of that without needing to host a JSON file off-chain. These templates can also be modified later if things change, making this setup much more decentralized and future-proof than using the standard `tokenURI` in an ERC-721 implementation linking to a JSON file. You can learn more about using Object Display [in the documentation](../standards/display.mdx).
## Differences, pitfalls, pros and cons
To sum up the most important differences between the two approaches:
| Solidity/EVM | IOTA Move |
| ---------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
| NFTs as a contract implementing a standard | Every object is an NFT by default! |
| All state within the same contract | State within the NFT objects that can be transferred to anyone, with an off-chain useable representation possible with `Object Display`. |
| Token logic is usually abstracted in externally imported libraries | Object logic for using and transferring objects (and thus NFTs) is part of the standard framework and is always the same. |
| NFTs can only be found if you have the smart contract address of that NFT | All NFTs are available in your wallet/account, given that they are sent to you as objects. |
| Non-enforced standard functionality (you can implement the ERC-721 functions as you please, including in for users' undesired ways) | Enforced standard functionality for objects with customizability where needed. |
NFTs in Move are clearly a big improvement over the afterthought counterparts in the EVM/Solidity ecosystem. There are more assurances and better usability when it comes to asset management.
---
## Creating an ERC-20-like token
## How this works in Solidity / EVM
One of the most commonly used building blocks in Solidity/EVM is a contract implementing the [ERC-20 token standard](https://ethereum.org/en/developers/docs/standards/tokens/erc-20/). The ERC-20 Token standard is for fungible tokens, allowing anyone to deploy their tokens on a chain that works with other dApps expecting them. There's little magic going on here; a token is just a regular smart contract with certain standardized functionality implemented (like a function to get the token's name, symbol, decimals, and functionality to transfer tokens to other addresses). The deployed token contract keeps track of all balances, so if you hold an ERC-20 token, that actually means that a mapping inside that token contract keeps track of how many of those tokens belong to your address.
A typical ERC-20 token in Solidity looks a bit like this:
```solidity title="contracts/ExampleCoin.sol"
pragma solidity ^0.8.3;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
contract ExampleCoin is ERC20 {
constructor() ERC20("ExampleCoin", "EXAMPLE") {
_mint(msg.sender, 10000 * 10 ** decimals());
}
}
```
The version pragma on the first line indicates what version of the Solidity compiler should be used for this contract. Different versions have different properties, which have to be taken into account. For example, versions before 0.8 need additional checks or helper libraries (SafeMath) when doing calculations to avoid causing any overflows. This is no longer required with 0.8+.
This contract inherits its ERC20 properties from a third party, the ERC20.sol library from OpenZeppelin, which is broadly used, battle-hardened, tested, proven reliable, and considered safe to use. The contract's constructor is overwritten to provide the token basics like Token name and Symbol according to the ERC20 standard. The contract mints 10,000 tokens with the standard amount of 18 decimals and puts them in the name of the publisher of this smart contract.
Overall, it looks like a simple contract, but it has some downsides. By importing external code, the complexity of the contract is abstracted. Still, you unquestioningly trust the library you are importing, which could be risky. Because the token itself is just an interpretation of a contract and not actually a token like the native asset (like, for example, ETH on Ethereum), it can't be used in the same manner as a normal native asset, meaning you need two implementations to deal with tokens and workarounds like wrapping native tokens to work around that. This also prevents the easy discovery of tokens you own, given you need to query a specific contract to find out your balance, so if you need to know which address this contract resides in, you are out of luck. Then there's also the option to `approve()` other addresses to use your token (for example, when you interact with a Decentralised Exchange), which is highly criticized for its implementation and what that means for the security of end users.
## How would this work in IOTA Move?
IOTA Move takes another approach when it comes to tokens. A standard, built-in module called `Coin` allows for the creation of and interaction with tokens. Unlike with EVM, the `Coin` implementation is used for every unrestricted fungible token by default, including the chain native asset (`IOTA`). This means that unlike ERC-20, a custom `Coin` is on the same level as the `IOTA` token implementation; they are both simply `Coin` instances - no need for a `wIOTA` here.
IOTA Move takes a radically different approach regarding tokens in terms of ownership and storage. Unlike Solidity, where balances are stored in the state of the contract, IOTA Move works with objects; The more it's being used, the more objects there will be. First, there is the `Coin` object itself. A `Coin` represents a transferable balance of a specific type of token as a (owned) object. You can transfer and receive coins like any other transferable object; however, if you need to transfer a smaller amount than the amount contained within the `Coin`, you need to split that amount into another `Coin` object, which you can transfer.
The initial creation of `Coin` takes place by minting these coins. This is usually done in a smart contract (module) in IOTA Move and looks like this:
```move file=/docs/examples/move/evm-to-move/sources/token.move
```
There's a lot to unpack here; let's look at it piece by piece. In IOTA Move, there is no 'compiler version' defined within the module itself, like in Solidity.
A `module` (`exampletoken`) is defined as part of the `examples` package (modules always reside in packages; a package can have one or more modules in one file or spread out over several files). Within the `module,` we first alias the functionality we wish to use from other modules with `use.` If you don't do this, you would have to explicitly call other modules through their full package path, which would be very verbose and cumbersome. We import an `option` module from the `std` package and some modules from the `iota` package, the 'std::option' module is implicitly imported in every module, and you don't need to add an import. The `std` and `iota` names are actually mappings as well to other modules defined in the `Move.toml` file of the package as described in the [documentation](../getting-started/create-a-package.mdx).
After the aliases, we see an empty struct defined:
```move file=/docs/examples/move/evm-to-move/sources/token.move#L5
```
This is the definition of the so-called [One-Time-Witness](../iota-101/move-overview/one-time-witness.mdx). Together with the `init` function definition, this ensures that this `Coin` will only be created once and never more on this chain.
The `init` function is called automatically when a package is published for every module. The One-Time-Witness and a `TxContext` object containing more information about the function call itself, like the address deploying the package (sender), are passed automatically.
Instead of using inheritance (which is not a thing in Move), the static `coin::create_currency` function is called from the aliased coin package to create a new token. Instead of returning a `Coin`, it returns two other objects: A `TreasuryCap` and a `Metadata` object. The first has the functionality to mint new `Coin` objects of this type, and the second stores the `Metadata` of the newly created token as provided. Typically, the `TreasuryCap` is sent back to the deployer of the package, where the `Metadata` object is typically frozen (publicly accessible but read-only), Which can also be seen in this example.
After publishing this package, the `init` functionality is called, and we now have some metadata published and a `TreasuryCap` object, which we received. We can use this `TreasuryCap` with the functionality in the `Coin` module to mint and burn tokens, such as using the command line tools or an SDK. In this example, we use the CLI to mint five new tokens and transfer them to a new address:
```bash
./iota client call --function mint_and_transfer --module coin --package 0x...... --args 0x...... 5 "0x...receiver..." --type-args $0x......::exampletoken::EXAMPLETOKEN
```
An important thing to note here is that unlike with ERC-20, a `Coin` has some properties that hold true for every `Coin` type, including the ability to freely transfer `Coin` objects without limitation (except [Regulated Coins](../standards/coin.mdx#regulated-coins) which can block transfers on a per-address base). You can't simply add limiting logic to your module like you can with an ERC-20 contract. Still, you would need to wrap the `Coin` in another module that does hold these constraints to implement this logic.
### Using `CoinManager`
The standard implementation of using `Coin`, `TreasuryCap`, and `Metadata` is pretty straightforward but also a bit bare-bones regarding functionality. For example, adding additional metadata besides the standard fields is impossible. Querying the total supply is only possible for the holder of the `TreasuryCap` and not public info. There is no way to limit the maximum supply of a given coin transparently. To address this and make this possible in a standardized way, we also provide a so-called `CoinManager` implementation which takes over the ownership of the `TreasuryCap` and uses it to make the above possible, all from within a single `CoinManager` object.
We recommend new tokens to abstract the management of the token with the `CoinManager` to provide a more transparent and trustworthy token while retaining administrative power and gaining usable functionality. You can do this by simply creating a `CoinManager` within the `init` function of your module, creating your token by passing in the non-transferred/frozen `TreasuryCap` and `Metadata` objects:
```move title="examples/Exampletoken.move"
use iota::coin_manager;
fun init(witness: EXAMPLETOKEN, ctx: &mut TxContext) {
let (treasurycap, metadata) = coin::create_currency(
witness,
6, // decimals
b"EXAMPLE", // symbol
b"Example Coin", // name
b"Just an example", // description
option::none(), // icon URL
ctx
);
// Creating the Manager, transferring ownership of the `TreasuryCap` to it
let (newtreasurycap, metacap, mut manager) = coin_manager::new(treasurycap, metadata, ctx);
// Limiting the maximum supply to `100`
newtreasurycap.enforce_maximum_supply(&mut manager, 100);
// Returning a new `CoinManagerTreasuryCap` to the creator of the `Coin`
transfer::public_transfer(newtreasurycap, ctx.sender());
// Returning a new `CoinManagerMetadataCap` to the creator of the `Coin`
transfer::public_transfer(metacap, ctx.sender());
// Publicly sharing the `CoinManager` object for convenient usage by anyone interested
transfer::public_share_object(manager);
}
```
### Using Closed-Loop tokens
While the `CoinManager` can limit and expand upon the management capabilities of a `Coin` type, the same rules for using a `Coin` still apply: unrestricted freedom to transfer tokens. If you need to limit this, you can either wrap the `Coin` instances in another object that adds limitations, or you can use the Closed-Loop `Token` standard, which does this in a comprehensive and standardized way. You can read more about how Closed-Loop tokens work in [the documentation](../standards/closed-loop-token.mdx).
## Differences, pitfalls, pros and cons
To sum up the most important differences between the two approaches:
| Solidity/EVM | IOTA Move |
| --------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Tokens as a contract | Tokens as (owned) objects |
| All state within the same contract | State spread out over various objects (`TreasuryCap`, `Metadata`, and various `Coin` objects) |
| Native token and ERC-20 are implemented differently | Both the chain native asset and custom tokens are `Coin` objects and work the same. |
| Token logic is usually abstracted in externally imported libraries | Token logic is part of the `iota-framework` `Coin` module |
| Admin functionality like minting is implemented in the contract itself and is fully customizable. | Admin functionality is standardized using a `TreasuryCap`, which can be used, transferred, or burned predictably. |
| Token balances can only be found if you have the smart contract address of the tokens you want to know the balance for | All tokens are known and available in your wallet, given they are transferred to you as objects. |
| Modifications can all take place within the smart contract itself | Modification to logic, with things like restricting if a `Coin` can be transferred, needs a different approach where the `Coin` is wrapped inside another object that limits the standard functionality of `Coin` based on conditions defined in that wrapper object. |
| Non-enforced standard functionality (you can implement the ERC-20 functions as you please, including in for users undesired ways) | Enforced standard functionality (every `Coin` can be used in the same way and under the same assumptions) |
While the Solidity/EVM approach is easy to work with and modify from a developer's perspective, it does have its downsides from an end-user perspective. You can not simply assume every ERC-20 token can be transferred as you expected without thoroughly reading and understanding the source code of those smart contracts, which is something most people can't do or don't do, given how time-consuming this is. This can lead to things like getting taxed for transfers (part of the transfer could go to the project deploying, for example), being blocked from doing a transfer (either with a malicious token or through a regulated framework), or simply losing all your tokens because they can be moved based on the logic implemented in the token contract. With the standard `Coin` implementation, this is not the case. You can assume that if you hold a `Coin`, you can always freely transfer it without any further limitations, as long as it's a `Coin` object. The logic is fixed, documented, and well-known.
---
## From Solidity/EVM to Move
Solidity and the Ethereum Virtual Machine (EVM) have been at the core of smart contract development for some years now. Complete ecosystems have been built around it, mainly by bringing the composable building blocks to it to facilitate Decentralised Finance (DeFi). Move is a pretty new contender in the space, and while certainly not the first attempt to take the place of Solidity it does do a lot of things right that will help developers, projects and end-users to set a new standard when it comes to smart contracts, be it in safety, usability or feature-wise.
If this sounds good to you you are in the right place. This guide will take you through to process of practically applying IOTA Move from a Solidity developer perspective. Let's get started!
---
## Tooling and APIs
## Tooling for EVM/Solidity
EVM has been around for a while and has built a comprehensive library of tools and utilities to interact with the network and contracts. We can categorize the most important tools in various sections and provide the equivalent for IOTA Move in the next section.
### Building, testing, interacting, and deploying
There have been various tools in the past to deal with the developer process of building, testing, interacting with, and deploying smart contracts. While you can do everything on a low level as well, interacting with the JSON/RPC API and compiling with `solc` is very cumbersome, so some abstractions have been built to make this easier. While there are several options, the most used tool today is [Hardhat](https://hardhat.org). Hardhat is a command-line toolkit for EVM development based on TypeScript. It allows you to create new projects, build them, test them with TypeScript tests, run scripts against them (to deploy or interact with these projects), and more. It has a comprehensive set of plugins to get more out of it, such as verifying smart contracts against block explorers or estimating gas prices for the contract you are developing. It's a mature toolkit that comes in very handy for every dApp developer. You can do some of this as well with the web-based [Remix](https://remix.ethereum.org) - It's more user-friendly for beginners, but it has limited capabilities.
### SDKs
Deploying and testing a contract from the command line is one thing, but having a dApp interact with smart contracts is another. In order to do this without doing very cumbersome manual JSON-RPC calls, you need an SDK to abstract this complexity. This is where [web3.js](https://web3js.org) and [ethers.js](https://ethers.org) come in. Both are targeted towards JS/TS usage and have similar functionality, but usage depends on developer preference. These are the most important SDKs, given most dApp interactions take place using a web browser. There are various other SDKs available for all kinds of languages. There likely is one available for your desired language of choice. Interaction with your contracts depends on using so-called `ABI`'s, which describe the functions and arguments that can be called on your contract. These are generated and provided to you during compilation by, for example, Hardhat.
### Wallets
There are wallets in all sizes and shapes for the EVM ecosystem. The most used and most popular one (but not without its flaws) is [Metamask](https://metamask.io), available as a web browser plugin or mobile application. Metamask is easily integrated directly with web3 dApps, allowing quick and easy interaction between the dApp and your wallet. Newer alternatives have been gaining some traction, but the common denominator is that the popular ones all support easy dApp integration. WalletConnect is another tool in the wallet category that conveniently connects wallets to dApps through a common protocol to avoid the need for a different implementation for each dApp for each wallet. A popular EVM-based product to manage multi-sig wallets is [Safe](https://safe.global/) (previously Gnosis safe), which allows multi-part approval of transfers and commands where each individual uses its own signing method (through Metamask, Ledger, or another wallet through WalletConnect) and if a majority is reached the transfer/command is executed.
### APIs
The most commonly used API within the EVM ecosystem is the JSON-RPC API exposed by the node you are connecting to. This API is often available in both HTTP and WebSocket form, and the methods exposed can differ slightly depending on the node implementation used.
### Editors
Solidity is supported by many editors who are aware of the Solidity syntax and support functionality like syntax checks and linting. While any editor can be used to create Solidity smart contracts, [VSCode](https://code.visualstudio.com) seems to be quite popular when combined with [the Hardhat plugin](https://hardhat.org/hardhat-vscode/docs/overview). This combination allows you to use a modern, Hardhat-aware editor that supports autocompletion, inline code validation, quick go-to functionality, and more.
## Tooling for IOTA Move
### Building, testing, interacting, and deploying
Unlike with EVM, where open-source third parties create the most used tooling, the tooling to do the most important interactions with an IOTA Move-based chain and smart contracts is actually part of the IOTA Move core. The most essential tool available is the `iota` CLI utility, which offers functionality similar to Hardhat. The CLI utility allows you to create new projects, build, test (using Move code, not TypeScript like with Hardhat), and deploy them. Next to that, the CLI tool is also used to interact with the chain(s) it is connected to with access to owned objects and the possibility to call arbitrary smart contract functionality without needing an ABI. While the CLI doesn't have all the functionality Hardhat has, it does function very well. It provides everything you need to get started creating Move code.
### SDKs
IOTA Move comes with a convenient [Rust](../../developer/iota-sdk/getting-started/rust.mdx) and [TypeScript SDK](../../developer/ts-sdk/typescript/index.mdx) right out of the box as part of the IOTA Move core. Next to that, a dApp toolkit is also offered by default, which provides several React components to more easily integrate your IOTA Move contract interaction within your dApp. While TypeScript covers most dApp requirements for an SDK, there might not be an SDK available for your language of choice at the moment. However, You can use one of the APIs directly on a lower level.
### Wallets
IOTA Move has an official [Browser Extension Wallet](./../../users/iota-wallet/getting-started.mdx) supporting direct dApp interaction similar to MetaMask. While the wallet ecosystem is very young, we encourage other wallets to join our efforts. Any new browser-extension-based wallets utilizing the [Wallet Standard](https://github.com/wallet-standard/wallet-standard/) can be used directly with any dApp made for IOTA Move instead of needing a custom integration.
### APIs
IOTA Move comes with a comprehensive JSON-RPC API, similar to the ones offered for EVM. It supports various commands, including commands prefixed with `iotax_`, which take advantage of the Indexer to query the requested data. In addition, a newer, more flexible GraphQL-based API is offered, allowing you to create more efficient, complex queries.
## Editors
Like with Solidity and Hardhat, you can write IOTA Move code in any editor, in combination with the CLI utilities, But the recommended editor to get the most out of the experience is VSCode as well in combination with the [Move](https://marketplace.visualstudio.com/items?itemName=iotaledger.iota-move) extension. This will add language support for Move to VSCode, allowing you to instantly see any mistakes made with inline code validation, go-to support, and more, offering a similar editor experience to the one for EVM.
## Conclusion
IOTA Move is quite new compared to the EVM ecosystem, and this is reflected in the amount of tooling available. The tooling available, though, is often offered as part of the core software, is of high quality, and offers everything you need to develop, interact with, and manage your dApps successfully.
---
## IOTA Exchange Integration Guide
This topic describes how to integrate IOTA, the token native to the IOTA network, into a cryptocurrency exchange. The specific requirements and processes to implement an integration vary between exchanges. Rather than provide a step-by-step guide, this topic provides information about the primary tasks necessary to complete an integration. After the guidance about how to configure an integration, you can also find information and code samples related to staking on the IOTA network.
## Local testing
You can develop and test your integration using a local development server. It will spin up a local network with some test nodes, an indexer, and a faucet. You can find detailed instructions in the [local development guide](./getting-started/local-network.mdx).
## Configure an IOTA Full node
You can set up and configure a [IOTA full node](../operator/full-node/overview.mdx) using Docker or directly from source code in the IOTA GitHub repository.
## Set up IOTA addresses
IOTA addresses do not require on-chain initialization, you can spend from an address if it corresponds to your private key. You can derive a 32-byte IOTA address by hashing the signature scheme flag byte concatenated with public key bytes `flag || pubkey` using the [BLAKE2b](https://www.blake2.net/) (256 bits output) hashing function. The flag is only appended if it's not the default `0x00` flag.
Currently, IOTA address supports these signature schemes: pure Ed25519, Secp256k1, Secp256r1 and multisig. The corresponding flag bytes are 0x00, 0x01, 0x02, 0x03 respectively.
:::info Default Signature Scheme
The default signature scheme is ED25519 (flag `0x00`). For this option, you only need to hash the `pubkey`, without prepending the `flag`. So, for flag `0x00` it's a hash of `pubkey`. For every other signature scheme, it's `flag || pubkey`. This is done to retain backward compatibility with addresses used on a previous version of the protocol.
:::
### Derive An ED25519 Address
The following code sample demonstrates how to derive an ED25519 (default) IOTA address in Rust:
```rust file=/docs/examples/rust/exchange/derive-address.rs#L6-L11
```
:::info SDK
If you are using the IOTA SDK already you can also use the type alias for iota_types instead:
```rust
iota_sdk::types::crypto::DefaultHash::default();
```
:::
### Derive An `Secp256k1` Address
This example uses a alternative `Secp256k1` signature scheme:
```rust file=/docs/examples/rust/exchange/derive-address.rs#L14-L22
```
### Generate an ED25519 Address With the Typescript SDK
This example generates a new address with the TypeScript SDK:
```ts file=/docs/examples/typescript/src/exchange/derive-address.ts
```
## Displaying addresses
IOTA supports both addresses with and without a `0x` prefix. We recommend that you always include the `0x` prefix in API calls and when you display user addresses.
:::warning
In previous versions of the protocol, we defaulted to a Bech32 human-readable representation of addresses. This representation (recognizable by addresses starting with `iota1`) is no longer available in this new version of the protocol and should no longer be used.
:::
## Track balance changes for an address
You can track balance changes by calling `iotax_getBalance` at predefined intervals. This call returns the total balance for an address. If no argument for coin type is passed, the IOTA token balance is returned. You can track changes in the total balance for an address between subsequent `iotax_getBalance` requests.
### Using cURL
The following bash example demonstrates how to use `iotax_getBalance` for address `0x849d63687330447431a2e76fecca4f3c10f6884ebaa9909674123c6c662612a3`. If you use a network other than Devnet, replace the value for `rpc` with the URL to the appropriate full node.
```bash
rpc="https://api.devnet.iota.cafe:443"
address="0x849d63687330447431a2e76fecca4f3c10f6884ebaa9909674123c6c662612a3"
data="{\"jsonrpc\": \"2.0\", \"method\": \"iotax_getBalance\", \"id\": 1, \"params\": [\"$address\"]}"
curl -X POST -H 'Content-type: application/json' --data-raw "$data" $rpc
```
The response is a JSON object that includes the `totalBalance` for the address:
```json
{
"jsonrpc":"2.0",
"result":{
"coinType":"0x2::iota::IOTA",
"coinObjectCount":40,
"totalBalance":10000000000
},
"id":1
}
```
### Using Rust
The following example demonstrates using `iotax_getBalance` in Rust:
```rust file=/docs/examples/rust/exchange/get-balance.rs
```
### Using TypeScript
This example does the same with TypeScript:
```ts file=/docs/examples/typescript/src/exchange/get-balance.ts
```
:::info Event Tracking
It's also possible to use event tracking to monitor addresses for incoming transactions. For more information on how events work and how to use them see the ["Using Events"](./iota-101/using-events.mdx) guide.
:::
## Blocks vs Checkpoints and Finality
IOTA is a DAG-based blockchain and uses checkpoints for node synchronization and global transaction ordering. Checkpoints differ from blocks in the following ways:
- IOTA creates checkpoints and adds finalized transactions. Note that transactions are finalized even before they are included in a checkpoint.
- Checkpoints do not fork, roll back, or reorganize.
- IOTA creates one checkpoint about every 200-250 milliseconds.
For more information about confirming finality, see the [Verifying Finality](../about-iota/iota-architecture/transaction-lifecycle.mdx#verifying-finality) section in the IOTA Architecture documentation.
### Checkpoint API operations
IOTA Checkpoint API operations include:
- [iota_getCheckpoint](/iota-api-ref#iota_getcheckpoint) - Retrieves the specified checkpoint.
- [iota_getLatestCheckpointSequenceNumber](/iota-api-ref#iota_getlatestcheckpointsequencenumber) - Retrieves the sequence number of the most recently executed checkpoint.
- [iota_getCheckpoints](/iota-api-ref#iota_getcheckpoints) - Retrieves a paginated list of checkpoints that occurred during the specified interval. Pending a future release.
## IOTA balance transfer
To transfer a specific amount of IOTA between addresses, you need an IOTA token object with that specific value. In IOTA, everything is an object, including IOTA tokens. The amount of IOTA in each IOTA token object varies. For example, an address could own 3 IOTA tokens with different values: one of 0.1 IOTA, a second of 1.0 IOTA, and a third with 0.005 IOTA. The total balance for the address equals the sum of the values of the individual IOTA token objects, in this case, 1.105 IOTA.
You can merge and split IOTA token objects to create token objects with specific values. To create an IOTA token worth .6 IOTA, split the token worth 1 IOTA into two token objects worth .6 IOTA and .4 IOTA.
To transfer a specific amount of IOTA, you need an IOTA token worth that specific amount. To get an IOTA token with that specific value, you might need to split or merge existing IOTA tokens. IOTA supports several methods to accomplish this, including some that do not require you to manually split or merge coins.
Keep in mind that to execute a transaction, including a normal transfer, you need to provide some IOTA for gas as well. This can not be the same IOTA object as the one you are trying to transfer. The [SDKs](../developer/references/iota-sdks.mdx) can automatically find another owned IOTA Coin object to use for gas if you don't manually select one. If you only have a single IOTA coin object, you might need to split some off first to have an object to transfer and an object to pay for gas (these can not be the same).
## IOTA API operations for transfers
:::warning
While it's possible to directly call the JSON-RPC API to integrate, we highly recommend using on of our [SDKs](../developer/references/iota-sdks.mdx) instead. This will abstract away boilerplate complexity, makes integration easier, and avoids common mistakes.
:::
IOTA supports the following API operations related to transferring IOTA between addresses:
- [unsafe_transferObject](/iota-api-ref#unsafe_transferobject)
Because IOTA tokens are objects, you can transfer IOTA tokens just like any other object. This method requires a gas token. For transferring tokens there are better alternatives, as listed below.
- [unsafe_payAllIota](/iota-api-ref#unsafe_payalliota)
This method accepts an array of IOTA token IDs. It merges all existing tokens into one, deducts the gas fee, then sends the merged token to the recipient address.
The method is especially useful if you want to transfer all IOTA from an address. To merge together all coins for an address, set the recipient as the same address. This is a native IOTA method so is not considered a transaction in IOTA.
- [unsafe_payIota](/iota-api-ref#unsafe_payiota)
This operation accepts an array of IOTA token IDs, an array of amounts, and an array of recipient addresses.
The amounts and recipients array map one to one. Even if you use only one recipient address, you must include it for each amount in the amount array.
The operation merges all of the tokens provided into one token object and settles the gas fees. It then splits the token according to the amounts in the amounts array and sends the first token to the first recipient, the second token to the second recipient, and so on. Any remaining IOTA on the token stays in the source address.
The benefits of this method include: no gas fees for merging or splitting tokens, and the abstracted token merge and split. The `unsafe_payIota` operation is a native function, so the merge and split operations are not considered IOTA transactions. The gas fees for them match typical transactions on IOTA. You can use this operation to split coins in your own address by setting the recipient as your own address. Note that the total value of the input coins must be greater than the total value of the amounts to send.
- [unsafe_pay](/iota-api-ref#unsafe_pay)
This method is similar to `unsafe_payIota`, but it accepts any kind of coin or token instead of only IOTA. You must include an IOTA gas token, and all of the coins or tokens must be the same type.
- [unsafe_transferIota](/iota-api-ref#unsafe_transferiota)
This method accepts only one IOTA token object and an amount to send to the recipient. It uses the same token for gas fees, so the amount to transfer must be strictly less than the value of the IOTA token used.
## Signing transactions
Refer to [IOTA Signatures](./cryptography/transaction-auth/signatures.mdx) for more details on signature validity requirements.
---
## Build and Test Packages
Once you have [created a package](create-a-package.mdx) and [added a module](create-a-module.mdx), you can build and test your package locally to ensure it's working as expected before [publishing it](publish.mdx).
## Building your package
You can use the `iota move build` command to build Move packages in the working directory, `first_package` in this case.
```shell
iota move build
```
If your build fails, you can use the [IOTA Client's](../../developer/references/cli.mdx) error message to troubleshoot any errors and [debug](debug.mdx) your code.
If your build is successful, the IOTA client will return the following:
```shell
UPDATING GIT DEPENDENCY https://github.com/iotaledger/iota.git
INCLUDING DEPENDENCY IOTA
INCLUDING DEPENDENCY MoveStdlib
BUILDING first_package
```
## Test a Package
You can use the Move testing framework to write unit tests for your IOTA package. IOTA includes support for the Move testing framework.
### Test Syntax
You should add unit tests in their corresponding [test file](create-a-module.mdx). In Move, test functions are identified by the following:
* They are [`public`](create-a-module.mdx#public-functions) functions.
* They have no parameters.
* They have no return values.
You can use the following command in the package root to run any unit tests you have created.
```shell
iota move test
```
If you haven't added any tests, you should see the following output.
```shell
INCLUDING DEPENDENCY Iota
INCLUDING DEPENDENCY MoveStdlib
BUILDING first_package
Running Move unit tests
Test result: OK. Total tests: 0; passed: 0; failed: 0
```
### Add Tests
You can add your first unit test by copying the following public test function and adding it to the `first_package` file.
```move file=/examples/move/first_package/sources/first_package.move#L109-L127
```
The unit test function `test_sword()` will:
1. Create a dummy instance of the `TxContext` struct and assign it to `ctx`.
2. Create a sword object that uses `ctx` to create a unique identifier (`id`), and assign `42` to the `magic` parameter, and `7` to `strength`.
3. Call the `magic` and `strength` [accessor functions](create-a-module.mdx#accessor-functions) to verify that they return correct values.
The function passes the dummy context, `ctx`, to the `object::new` function as a mutable reference argument (`&mut`), but passes `sword` to its accessor functions as a read-only reference argument, `&sword`.
Now that you have a test function, run the test command again:
```shell
iota move test
```
### Debugging Tests
If you run the `iota move test` command, you might receive the following error message instead of the test results:
```
error[E06001]: unused value without 'drop'
┌─ sources/first_package.move:55:65
│
4 │ public struct Sword has key, store {
│ ----- To satisfy the constraint, the 'drop' ability would need to be added here
·
48 │ let sword = Sword {
│ ----- The local variable 'sword' still contains a value. The value does not have the 'drop' ability and must be consumed before the function returns
│ ╭─────────────────────'
49 │ │ id: object::new(&mut ctx),
50 │ │ magic: 42,
51 │ │ strength: 7,
52 │ │ };
│ ╰─────────' The type 'my_first_package::first_package::Sword' does not have the ability 'drop'
· │
55 │ assert!(magic(&sword) == 42 && strength(&sword) == 7, 1);
│
```
The compilation error provides all the necessary information to help you [debug](debug.mdx) your module.
Move has many features to ensure your code is safe. In this case, the `Sword` struct represents a game asset that digitally mimics a real-world item. Much like a real sword, it cannot simply disappear. Since the `Sword` struct doesn't have the [`drop`](create-a-module.mdx#drop) ability, it has to be consumed before the function returns. However, since the `sword` mimics a real-world item, you don't want to allow it to disappear.
Instead, you can fix the compilation error by adequately disposing of the `sword`. Add the following after the function's `!assert` call to transfer the `sword` to a freshly created dummy address:
```move file=/examples/move/first_package/sources/first_package.move#L124-L126
```
Run the test command again. Now the output shows a single successful test has run:
```shell
INCLUDING DEPENDENCY Iota
INCLUDING DEPENDENCY MoveStdlib
BUILDING my_first_package
Running Move unit tests
[ PASS ] 0x0::first_package::test_sword
Test result: OK. Total tests: 1; passed: 1; failed: 0
```
:::tip TIP
Use a filter string to run only a matching subset of the unit tests. With a filter string provided, the `iota move test` checks the fully qualified (`::::`) name for a match.
:::
### Run a Subset of Tests
You can run a subset of the tests in your package that match a given string by adding said string at the end of the `iota move test` command:
```shell
iota move test sword
```
`iota move test` will check the fully qualified name (`::::`) for matches. The previous command runs all tests whose name contains `sword`.
### More Options
You can use the following command to see all the available options for the test command:
```shell
iota move test -h
```
:::tip Cheat Sheet
- Use [`iota::test_scenario`](https://github.com/iotaledger/iota/blob/develop/crates/iota-framework/packages/iota-framework/sources/test/test_scenario.move) to mimic multi-transaction, multi-sender test scenarios.
- Use the [`iota::test_utils`](https://github.com/iotaledger/iota/blob/develop/crates/iota-framework/packages/iota-framework/sources/test/test_utils.move) module for better test error messages via `assert_eq`, debug printing via `print`, and test-only destruction via `destroy`.
- Use `iota move test --coverage` to compute code coverage information for your tests, and `iota move coverage source --module ` to see uncovered lines highlighted in red. Push coverage all the way to 100% if feasible.
:::
## IOTA-specific testing
Although you can test a great deal of your contract using the default Move testing framework, you should make sure that you also test code that is specific to IOTA.
### Testing Transactions
Move calls in IOTA are encapsulated in [transactions](../iota-101/transactions/transactions.mdx). You can use the [`iota::test_scenario`](https://github.com/iotaledger/iota/blob/develop/crates/iota-framework/packages/iota-framework/sources/test/test_scenario.move) to test the interactions between multiple transactions within a single test. For example, you could create an object with one transaction and transfer it to another.
The `test_scenario` module allows you to emulate a series of IOTA transactions. You can even assign a different user to each transaction.
#### Instantiate a Scenario
You can use the `test_scenario::begin` function to create an instance of `Scenario`.
The `test_scenario::begin` function takes an address as an argument, which will be used as the user executing the transaction.
#### Add More Transactions
The `Scenario` instance will emulate the IOTA object storage with an object pool for every address. Once you have [`instantiated the Scenario`](#instantiate-a-scenario) with the first transaction, you can use the `test_scenario::next_tx` function to execute subsequent transactions. You will need to pass the current `Scenario` instance as the first argument, as well as an address for the test user sending the transaction.
You should update the `first_package.move` file to include entry functions callable from IOTA that implement `sword` creation and transfer. You can add these after the accessor functions.
```move file=/examples/move/first_package/sources/first_package.move#L68-L85
```
With this code, you have enabled creating and transferring a `sword`. Since these functions use IOTA's `TxContext` and `Transfer`, you should use the `test_scenario`'s multi-transaction capability to test these properly. You should add the following test to the `first_package.move` file:
```move file=/examples/move/first_package/sources/first_package.move#L95-L199
```
### Configuration Object Creation
The `create_config` function allows creating reusable configuration objects that can be shared across transactions:
```move file=/examples/move/first_package/sources/first_package.move#L87-L93
```
Let's break it down by steps so you understand how the `test_scenario` helpers work in a realistic multi-transaction flow:
### 1. Create User Addresses
First, define three test addresses to represent different users in your scenario: an admin: ADMIN, an initial sword owner: ALICE, and a final sword owner: BOB.
```move file=/examples/move/first_package/sources/first_package.move#L95-L107
```
### 2. Start the Scenario
Create a Scenario by calling `test_scenario::begin()`. Pass the `admin` address as the sender of the first transaction.
You can then call the `init` function to simulate module initialization logic during the first transaction.
```move file=/examples/move/first_package/sources/first_package.move#L131-L137
```
### 3. Admin Creates a Sword and Transfers It
After the module is initialized, the `admin` runs a transaction to create a new sword.
Use `test_scenario::next_tx` to advance to the next transaction in the scenario and execute it as the `admin`.
In this example, the `admin` uses the `new_sword` function to create a sword using a `Forge` object and then transfers it to the `initial_owner`.
```move file=/examples/move/first_package/sources/first_package.move#L167-L175
```
### 4. Initial Owner Transfers the Sword
Next, the `initial_owner` retrieves the sword using `take_from_sender`.
They then transfer the sword to the `final_owner`.
This works because `test_scenario` keeps track of objects created and transferred in earlier transactions.
```move file=/examples/move/first_package/sources/first_package.move#L177-L184
```
:::info Transaction Effects
In `test_scenario`, transaction effects (such as creating or transferring an object) are only available to retrieve in the **next** transaction.
For example, if the second transaction in a scenario created a `sword` and transferred it to the administrator's address, it would only become available for retrieval from the administrator's address (via `test_scenario`, `take_from_sender`, or `take_from_address`) in the third transaction.
If needed, you can also use `take_from_address` to fetch an object from a specific address instead of the current sender:
```move
let sword = test_scenario::take_from_address(scenario, initial_owner);
```
:::
### 5. Final Owner Verifies and Cleans Up
In the final transaction, the `final_owner` retrieves the sword to verify its properties.
When finished, return the sword to the object pool or destroy it to keep the test state clean.
```move file=/examples/move/first_package/sources/first_package.move#L186-L197
```
### Using `iota::test_utils`
The `iota::test_utils` module provides useful helpers for assertions and cleanup.
This makes your test checks easier to read and maintain.
#### Key Functions:
`assert_eq(t1: T, t2: T)`
Fails the test if t1 and t2 are not equal.
`assert_same_elems(v1: vector, v2: vector)`
Checks that two vectors contain the same elements, regardless of order.
`destroy(x: T)`
Destroys an object when you no longer need it.
#### Example:
```move file=/examples/move/first_package/sources/first_package.move#L200-L218
```
### Example: Complete Multi-Transaction Move Contract And Test coverage
Putting it all together, the full `first_package::my_module` Contract And Test coverage
function looks like this:
Includes test_scenario and test_utils modules:-
```move file=/examples/move/first_package/sources/first_package.move#L1-L364
```
### Run All Tests
1.
```shell
iota move build
```
2.
```shell
iota move test
```
Output of the test command:
```shell
INCLUDING DEPENDENCY Iota
INCLUDING DEPENDENCY MoveStdlib
BUILDING first_package
Running Move unit tests
[ PASS ] first_package::my_module::test_address_operations
[ PASS ] first_package::my_module::test_assert_utils
[ PASS ] first_package::my_module::test_immutable_objects
[ PASS ] first_package::my_module::test_module_init
[ PASS ] first_package::my_module::test_receiving_tickets
[ PASS ] first_package::my_module::test_scenario_advanced
[ PASS ] first_package::my_module::test_sword
[ PASS ] first_package::my_module::test_sword_transactions
Test result: OK. Total tests: 8; passed: 8; failed: 0
```
## References:
- [`test_scenario` source](https://github.com/iotaledger/iota/blob/develop/crates/iota-framework/packages/iota-framework/sources/test/test_scenario.move)
- [`test_utils` source](https://github.com/iotaledger/iota/blob/develop/crates/iota-framework/packages/iota-framework/sources/test/test_utils.move)
---
## Client App with IOTA TypeScript SDK
You can use this guide to set up a React application with dApp Kit. dApp Kit allows you to connect to wallets and query
data from IOTA RPC nodes. You can also quickly scaffold a new app with all the steps in this exercise already
implemented by running the following command in a terminal:
:::info
You must use the pnpm or yarn package managers to create IOTA project scaffolds. Follow the [pnpm install](https://pnpm.io/installation) or [yarn install](https://classic.yarnpkg.com/lang/en/docs/install/#mac-stable) instructions, if needed.
:::
```bash
pnpm create @iota/dapp --template react-client-dapp
```
```bash
yarn create @iota/dapp --template react-client-dapp
```
## What is the IOTA TypeScript SDK?
The [IOTA TypeScript SDK](../../developer/ts-sdk/typescript/index.mdx) (`@iota/iota-sdk`) provides the essential
functionality needed to interact with the IOTA
ecosystem from TypeScript. It's versatile enough to be used in any TypeScript or JavaScript project, including web apps,
Node.js applications, or mobile apps developed with tools like React Native that support TypeScript.
## What is dApp Kit?
[dApp Kit](../../developer/ts-sdk/dapp-kit/index.mdx) (`@iota/dapp-kit`) is a collection of React hooks, components,
and utilities designed to simplify building
decentralized applications (dApps) on the IOTA network.
## Installing Dependencies
To begin, you need a React application. The following instructions apply to any React app, so you can also add dApp Kit
to an existing React app. If you're starting a new project, you can use [Vite](https://vitejs.dev/) to scaffold a new
React app.
Run the following command in your terminal, select React as the framework, and then choose one of the TypeScript
templates:
```bash npm2yarn
npm init vite
```
Now that you have a React app, you can install the necessary dependencies to use dApp Kit:
```bash npm2yarn
npm install @iota/iota-sdk @iota/dapp-kit @tanstack/react-query
```
:::info Local version of the SDK
If you'd like to use a locally compiled version of the SDK you can follow the instructions in the [Local Development](local-network.mdx#test-with-the-iota-typescript-sdk) section.
:::
## Setting Up Provider Components
To use all the features of dApp Kit, wrap your app with several `Provider` components.
Open the root component that renders your app (the default location used by the Vite template is `src/main.tsx`) and
integrate or replace the current code with the following.
### `QueryClientProvider`
The first `Provider` to set up is the `QueryClientProvider` from `@tanstack/react-query`. This `Provider` manages
request state for various hooks in dApp Kit. If you're already using `@tanstack/react-query`, dApp Kit can share the
same `QueryClient` instance.
```ts
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
const queryClient = new QueryClient();
ReactDOM.createRoot(document.getElementById('root')!).render(
,
);
```
### `IotaClientProvider`
Next, set up the `IotaClientProvider`. This `Provider` delivers an `IotaClient` instance from `@iota/iota.js` to all the
hooks in dApp Kit. This provider manages which network dApp Kit connects to and can accept configurations for multiple
networks. In this exercise, you'll connect to `devnet`.
```ts
import { IotaClientProvider } from '@iota/dapp-kit';
import { getFullnodeUrl } from '@iota/iota-sdk/client';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
const queryClient = new QueryClient();
const networks = {
devnet: { url: getFullnodeUrl('devnet') },
testnet: { url: getFullnodeUrl('testnet') },
};
ReactDOM.createRoot(document.getElementById('root')!).render(
,
);
```
### `WalletProvider`
Finally, set up the `WalletProvider` from `@iota/dapp-kit`, and import styles for the `dapp-kit` components.
```ts
import '@iota/dapp-kit/dist/index.css';
import { IotaClientProvider, WalletProvider } from '@iota/dapp-kit';
import { getFullnodeUrl } from '@iota/iota-sdk/client';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
const queryClient = new QueryClient();
const networks = {
devnet: { url: getFullnodeUrl('devnet') },
testnet: { url: getFullnodeUrl('testnet') },
};
ReactDOM.createRoot(document.getElementById('root')!).render(
,
);
```
## Connecting to a Wallet
Once you've set [up all the `Providers`](#setting-up-provider-components), you can use dApp Kit hooks and components. To
allow users to connect their wallets to your dApp, add a `ConnectButton`.
```ts
import { ConnectButton } from '@iota/dapp-kit';
function App() {
return (
);
}
```
The `ConnectButton` component displays a button that opens a modal on click, enabling users to connect their wallet.
Once connected, it displays their address and provides the option to disconnect.
## Getting the Connected Wallet Address
Now that you have a way for users to connect their wallets, you can start using the `useCurrentAccount` hook to get
details about the connected wallet account.
```ts
import { ConnectButton, useCurrentAccount } from '@iota/dapp-kit';
function App() {
return (
);
}
function ConnectedAccount() {
const account = useCurrentAccount();
if (!account) {
return null;
}
return Connected to {account.address};
}
```
## Querying Data from IOTA RPC Nodes
Now that you have the account connected, you can query for objects that the connected account owns:
```ts
import { useCurrentAccount, useIotaClientQuery } from '@iota/dapp-kit';
function ConnectedAccount() {
const account = useCurrentAccount();
if (!account) {
return null;
}
return (
Connected to {account.address};
);
}
function OwnedObjects({ address }: { address: string }) {
const { data } = useIotaClientQuery('getOwnedObjects', {
owner: address,
});
if (!data) {
return null;
}
return (
{data.data.map((object) => (
{object.data?.objectId}
))}
);
}
```
Now you have a dApp connected to wallets that can query data from RPC nodes.
---
## Connect to an IOTA Network
:::info
The [Network Overview](/developer/network-overview) section lists all the networks available in the IOTA ecosystem.
:::
## IOTA CLI
IOTA provides the [IOTA command line interface (CLI)](/developer/references/cli/client.mdx) to interact with [IOTA networks](#iota-networks), it does the following and more:
- Create and manage your private keys
- Call and publish Move modules
- Compile and test Move modules
- Create and execute programmable transaction blocks ([PTBs](../../developer/references/cli/ptb.mdx))
- Interact with testnet/devnet faucets
You can use the [CLI](iota-environment.mdx#iota-cli) or [SDKs](iota-environment.mdx#iota-sdks) to send transactions and
read requests from using the [JSON-RPC](../references/iota-api/json-rpc-format.mdx) and the following
endpoint: `https://api..iota.cafe:443`.
## Environment Set Up
First, [Install IOTA](install-iota.mdx). After you install IOTA, [request IOTA test tokens](get-coins.mdx) for the
network you are using. If connected to Localnet, use cURL to request tokens from
your [local faucet](local-network.mdx#use-the-local-faucet).
To check whether IOTA is already installed, run the following command:
```shell
which iota
```
If IOTA is installed, the command returns the path to the IOTA binary. If IOTA is not installed, it
returns `iota not found`.
:::tip Release Info;
See the [IOTA Releases](https://github.com/iotaledger/iota/releases) page to view the changes in each IOTA release.
:::
## Connect Your CLI to a Network
You can connect to an IOTA network using the following command that will start
the [IOTA CLI Client](../references/cli/client.mdx):
```bash
iota client
```
### First Run
If this is the first time you run the command, you will be prompted to configure the client.
#### 1. Create a client config (`client.yaml`)
```
Select a default network [mainnet|testnet|devnet|localnet], or enter a custom IOTA full node server URL (defaults to testnet if not specified):
```
If you want to connect to the [Testnet](#testnet), you can simply press `Enter`.
If not, specify your desired node URL. If you choose to add a custom URL, you should also add an alias for ease of
access:
```bash
Environment alias for [] :
```
#### 2. Generate Keys and Address
```
Select key scheme to generate keypair (0 for ed25519, 1 for secp256k1, 2: for secp256r1):
```
Finally, you will be prompted to select the key scheme you want to use. After this, you will receive a message that
states the selected key-scheme, the generated address and your secret recovery phrase.
:::tip Signature scheme selection
If you are unsure which scheme to use just go with the default ed25519 scheme (option 0).
:::
```bash
Generated new keypair for address with scheme "ed25519" [0xb9c83a8b40d3263c9ba40d551514fbac1f8c12e98a4005a0dac072d3549c2442]
Secret Recovery Phrase : [hat become demise beyond history wood stage add nice list jaguar legend]
```
## Add a Network Environment
The [IOTA CLI Client](../../developer/references/cli/client.mdx) allows you to add any number of network environments.
### Check the Current Network ENVs
You can easily check the currently configured environments using the following command, which will output the
environment `alias` and URL, as well as indicate the currently active environment:
```bash
iota client envs
```
The command outputs the available environment aliases, with `(active)` denoting the currently active network.
```sh
localnet => http://0.0.0.0:9000 (active)
testnet => https://api.testnet.iota.cafe
```
You can add a new environment using the `iota client new` command. You should specify an `alias` and `rpc` URL, for
example:
```bash
iota client new-env --alias local --rpc http://0.0.0.0:9000
```
### Switch Network Environment
You can switch the current environment using the following command:
```bash
iota client switch --env
```
* Where `` is one of your currently set environments.
You can use the following networks to develop on IOTA. If you are still developing your application, you should use the
Devnet or Testnet, as these networks provide convenient faucets for test tokens.
## IOTA Networks
### Devnet
The latest stable release. As such, it has the latest features that were tested in the `develop` branch of the
repository.
:::danger Data persistence is not guaranteed on the Devnet
Devnet data is wiped regularly as part of scheduled software updates.
:::
:::info Devnet node validators
The IOTA Devnet networks consist of four validator nodes operated by the IOTA Foundation.
:::
### Testnet
Once a release has been battle-tested in the Devnet, it moves to the Testnet. You can use this network to
test your software in real-world conditions.
:::info Testnet node validators
The IOTA Testnet consist of a decentralized set of validator nodes similar to the mainnet.
:::
### Mainnet
The fully operational production network, with data persistence and where tokens have real value.
:::tip Local Networks
You can also spin up a [local IOTA network](local-network.mdx) for local development.
:::
---
## Create a Move Module
A [package](create-a-package.mdx)'s utility is defined by its modules. A module contains the logic for your package. You can create any number of modules per package. To add a module, create a `.move` file in the `sources` directory. For this guide, create a file called `first_package.move` and add the following content:
```move
module first_package::first_package {
}
```
And now let's add some code:
:::tip Comments in `.move` files
In `.move` files, use double slashes (`//`) to denote a comment.
:::
```move file=/examples/move/first_package/sources/first_package.move#L7-L41
```
## Module Name
The first line of the module defines the module's name and the package it belongs to. In this case, `first_package` belongs to [`first_package`](create-a-package.mdx).
## Imports
Move's [object model](../iota-101/objects/object-model.mdx) allows for code reuse. You can use types and functions declared in other modules, even if they belong to different packages.
In this example, the module imports from the `object`, `transfer`, and `tx_context` modules from the `iota` package, which was defined as a [package dependency](create-a-package.mdx#dependencies). The module does not need to import them explicitly, because the compiler provides these `use` statements by default.
## Struct Declarations
Structs define the data structures your module can create, store, and destroy.
### Abilities
You can add abilities to any struct using the `has` keyword.
#### `key`
The `key` ability allows you to store and transfer a struct.
#### `store`
The `store` ability allows the struct to be stored in structs with the `key` ability. The `store` ability allows the value to be wrapped in an object. A type with the `key` ability can be stored at top-level and be directly owned by an account or address.
#### `copy`
The `copy` ability allows the struct to be copied. If a type has the `copy` ability, it should likely have the `drop` ability too, as the `drop` ability is required to clean up resources when the instance is no longer needed.
#### `drop`
The `drop` ability allows the struct to be dropped or discarded. In Move, all assets must be handled with appropriate care. If you attempt to ignore or discard a struct without the `drop` ability, your code will not compile.
### Module Initializer
A module initializer is a special function invoked exactly once when the module is published. It must have the following properties:
- The function name must be `init`.
- The parameter list must end with either `&mut TxContext` or `&TxContext`.
- The function should have no return values.
- It must be a private function.
Keep in mind that if you [upgrade your package](../iota-101/move-overview/package-upgrades/upgrade.mdx), the initializer will not be called again.
### Entry Functions
Add the `entry` modifier to functions you want to call from a [programmable transaction block](../iota-101/transactions/ptb/programmable-transaction-blocks). All parameters passed to the function must be inputs to the transaction block, not results from other transactions in the block, nor can they be modified by previous transactions in the block. These functions can only return types with the `drop` ability.
### Public Functions
`public` functions can be called from a [programmable transaction block](../iota-101/transactions/ptb/programmable-transaction-blocks) or another module.
#### Accessor Functions
Accessor functions are `public` functions that allow the fields of the module's structs to be read from other modules.
---
## Create a Move Package
Once you have [installed IOTA](install-iota.mdx), you are ready to create your first IOTA
Move [package](../iota-101/move-overview/package-upgrades/introduction.mdx). In IOTA, packages are the way to organize
the [modules](create-a-module.mdx) that make up your smart contract program. When you publish a package to any IOTA
network, it will be assigned an address you can use to interact with the package by
issuing [transactions](../iota-101/transactions/transactions.mdx).
Use the following command to create a standard package:
```shell
iota move new first_package
```
The command will create and populate the `first_package` directory with a skeleton for an IOTA Move project,
consisting of the following files and directories:
## `Move.toml`
The `Move.toml` file is the package's manifest. It describes the package and its dependencies.
:::tip Comments in `.toml` files
In `.toml` files, use the hash mark (`#`) to denote a comment.
:::
```toml file=/examples/move/first_package/Move.toml
```
:::tip Using a local version of IOTA
For local testnet development and testing it is recommended to use the local dependency of the `Iota` framework for faster and more reliable builds. See the commented line in the example above as an example pointing towards your local checkout of the `iota` repository.
:::
### Package
The `[package]` section describes the package. By default, the `iota move new` command populates only the `name` value
of the metadata.
- `name`: The package name when it is imported.
- `version`: The package version. It can be used in release management.
- `edition`: The edition of the Move language; currently, the only valid value is `2024`.
### Dependencies
The `[dependencies]` section specifies the dependencies of the project. The dependency specification can be a git
repository URL or a path to the local directory.
```toml file=/examples/move/first_package/Move.toml#L10-L15
```
Packages also import addresses from other packages. For example, the `Iota` dependency adds the `std` and `iota` addresses
to the project. These addresses can be used in the code as aliases for the addresses.
### Resolving Version Conflicts with `override`
If you have two dependencies that use different versions of the same package, you can override the dependency in
the `[dependencies]` section. To do so, add the `override` field to the dependency. The version specified in
the `[dependencies]` section will be used instead of the one specified in the dependency itself.
```toml file=/examples/move/first_package/Move.toml#L17-L19
```
### Dev-dependencies
You can also add a `[dev-dependencies]` section to the manifest to override dependencies in the dev and test modes. For
example, if you want to use a different version of the IOTA package in dev mode, you can add a custom dependency
specification to the `[dev-dependencies]` section.
### Addresses
The `[addresses]` section is used to add aliases for the addresses you use in your package. You can add any address in
this section, and then use its alias in the code instead of the actual address. For example, if you
add `alice = "0xA11CE"` to this section, you can use `alice` as `0xA11CE` in the code.
If you created your package with the `iota client new` command, this section includes a `0x0` address for your package. You do not need to update this as [package addresses are automatically managed](../iota-101/move-overview/package-upgrades/automated-address-management.mdx).
### Dev-addresses
Much like the `[dev-dependencies]` section, you can also define `[dev-addresses]` to override the addresses you defined
in the `[addresses]` section for test and dev modes.
:::note Override Only
You cannot introduce new aliases in this section, only override the ones you defined in [`[addresses]`](#addresses).
:::
## TOML Styles
The TOML format supports two styles for tables: inline and multiline. The examples above use the inline style, but it is
also possible to use the multiline style. You wouldn't want to use it for the `[package]` section, but it can be useful
for the dependencies.
```toml
[dependencies]
iota = { override = true, git = "", subdir = "crates/iota-framework/packages/iota-framework", rev = "framework/testnet" }
MyPackage = { local = "../my-package" }
```
```toml
[dependencies.iota]
override = true
git = "https://github.com/iotaledger/iota.git"
subdir = "crates/iota-framework/packages/iota-framework"
rev = "framework/testnet"
[dependencies.MyPackage]
local = "../my-package"
```
---
## Debugging
Move does not currently have a built-in debugger. However, you can leverage the `std::debug` module to print various values directly to the console. This approach helps you observe and understand the behavior and logic of your modules. Start by importing the debug module into your source file:
```move
use std::debug;
```
To print a variable `v`, irrespective of its type, use the following code:
```move
debug::print(&v);
```
If `v` is already a reference, you can use:
```move
debug::print(v);
```
Additionally, the debug module offers a function to display the current stack trace:
```move
debug::print_stack_trace();
```
Moreover, if an abort or assertion fails, the stack trace at that failure point is automatically printed.
## Implementing Debug in `first_package`
To demonstrate the use of the `std::debug` module, update your `first_package` by integrating debug statements. Specifically, modify the `new_sword` function to output the `forge` value both before and after incrementing `swords_created`. Incorporate a `print_stack_trace` as well, resulting in the following function:
```move
/// Constructor for creating swords.
public fun new_sword(forge: &mut Forge, magic: u64, strength: u64, ctx: &mut TxContext): Sword {
debug::print(forge);
// Increment the `swords_created` counter.
forge.swords_created = forge.swords_created + 1;
debug::print(forge);
debug::print_stack_trace();
// Create a sword.
Sword {
id: object::new(ctx),
magic: magic,
strength: strength,
}
}
```
To view the output, execute the module's tests:
```shell
$ iota move test test_sword_transactions
```
This will display the expected results as the test calls the `new_sword` function:
```shell
INCLUDING DEPENDENCY Iota
INCLUDING DEPENDENCY MoveStdlib
BUILDING my_first_package
Running Move unit tests
[debug] 0x0::first_package::Forge {
id: 0x2::object::UID {
id: 0x2::object::ID {
bytes: @
}
},
swords_created: 0
}
[debug] 0x0::first_package::Forge {
id: 0x2::object::UID {
id: 0x2::object::ID {
bytes: @
}
},
swords_created: 1
}
Call Stack:
[0] 0000000000000000000000000000000000000000000000000000000000000000::first_package::test_sword_transactions
Code:
[24] LdU64(7)
[25] CopyLoc(5)
[26] Call(13)
> [27] Call(6)
[28] CopyLoc(4)
[29] CallGeneric(2)
[30] CopyLoc(5)
Locals:
[0] -
[1] -
[2] 000000000000000000000000000000000000000000000000000000000000face
[3] { { { } }, 1 }
[4] 000000000000000000000000000000000000000000000000000000000000cafe
[5] (&) { 1, { 000000000000000000000000000000000000000000000000000000000000babe, [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 0, 0, 0 } }
[6] { 1, { 000000000000000000000000000000000000000000000000000000000000babe, [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 0, 0, 0 } }
[7] -
Operand Stack:
[ PASS ] 0x0::first_package::test_sword_transactions
Test result: OK. Total tests: 1; passed: 1; failed: 0
```
---
## Create an Address
import { useCurrentAccount } from '@iota/dapp-kit';
export function CurrentAddress({ fallbackValue }) {
const account = useCurrentAccount();
const address = account ? account.address : fallbackValue;
return {address};
}
## What's an Account?
In IOTA, users are not identified by email or personal information but by an account and its
associated [address](#whats-an-address). The account is generated from a private key, which could be
derived from a mnemonic. Accounts can own any type of [object](../iota-101/objects/object-model.mdx) and send
transactions.
## What's an Address?
An address is a way to uniquely and anonymously identify an [account](#whats-an-account)
or [package](../iota-101/move-overview/package-upgrades/introduction.mdx). In the same way your email or ID number is
unique, addresses have to be unique as they are your account's identifier to send and receive transactions. You
can [create any number of addresses](#create-an-iota-address), all of which will be unique.
### Address Structure
In IOTA, an address is 64 characters (32 bytes) long and is often encoded as a case-insensitive hexadecimal string prefixed with `0x` prefix. For example, this is a valid IOTA
address: .
:::tip Connect Wallet
If you connect your wallet, you will see your current address above.
:::
:::tip IOTA Explorer
You can use the [IOTA network explorer](https://explorer.iota.org/) to find more information about this address and the
objects it owns.
:::
:::warning Legacy address format
In IOTA Stardust we used a different address standard by default (Bech32, starting with `iota1`). To read more about this change check out the [address details migration page](../stardust/addresses.mdx).
:::
### Reserved Addresses
In IOTA, there are reserved addresses that identify standard packages and objects. Reserved
addresses are typically simple values that are easy to remember and type. For example, the address of the Standard Library is `0x1`. Addresses shorter than 32 bytes are padded with zeros to the left.
```move
0x1 = 0x0000000000000000000000000000000000000000000000000000000000000001
```
Here are some examples of reserved addresses:
- `0x1` - address of the IOTA Move Standard Library (alias `std`)
- `0x2` - address of the IOTA Framework (alias `iota`)
- `0x6` - address of the system `Clock` object
:::tip Keys and Addresses
[Learn how an IOTA address is derived from private keys](../cryptography/transaction-auth/keys-addresses.mdx).
:::
## Create an IOTA address
IOTA provides multiple ways to obtain an IOTA address. The following are the two most common.
:::note Supported Address Types
IOTA supports multiple signature schemes for account generation. The currently supported curves
are `ed25519`, `secp256k1`, and `secp256r1`.
:::
### IOTA Wallet
The simplest way to generate an IOTA address is using the [IOTA Wallet Chrome browser extension](https://chromewebstore.google.com/detail/iota-wallet/iidjkmdceolghepehaaddojmnjnkkija).
After you install the extension, there are several ways to create an address.
Open the Chrome IOTA Wallet browser extension and then:
- Click **More Options** → **Create a new passphrase account**. Then, follow the on-screen instructions.
:::tip Connect Wallet
Your current address: .
:::
For more information on the IOTA Wallet and how to keep it secure, see
the [IOTA Wallet documentation](../../users/iota-wallet/getting-started.mdx).
### Command Line Interface
#### Your first address
When you start the CLI for the first time, it will prompt you to set up a local wallet, which naturally has an address,
so it can receive and send funds.
:::danger Recovery phrase
Please write down the recovery phrase associated with your address and keep it in a safe place.
:::
#### Generate Address
You can use the [IOTA Client CLI](../../developer/references/cli/client.mdx) to generate any number of addresses by using
the `iota client new-address`.
:::info Keyscheme
By default `ed25519` is used to generate the address. You can specify the keyscheme with the `--keyscheme` flag.
Possible values are:
- `ed25519`
- `secp256k1`
- `secp256r1`
:::
#### List Addresses
You can list all the addresses associated with your local wallet with
the [IOTA Keytool CLI](../../developer/references/cli/keytool.mdx) by running the following command:
```bash
iota keytool list
```
:::danger Private Keys
The private keys associated with the IOTA addresses are stored locally on the machine where the CLI is installed in
the `~/.iota/iota_config/iota.keystore` file. Anyone who can access that file can take control of your account, so you
should not share it with anyone.
:::
---
## Get Test Tokens
import {Networks} from '@site/src/components/constant'
import FaucetButton from '@site/src/components/FaucetButton';
# Get Test Tokens
You can use the IOTA faucet to get free test IOTAs to pay for [gas](../../about-iota/tokenomics/gas-pricing.mdx) on the IOTA Devnet and Testnet networks. These test tokens have no real-world value.
## Using the IOTA CLI
You can use the [IOTA CLI client](../../developer/references/cli/client.mdx) to request tokens for your [address](get-address.mdx) by using the `iota client faucet` command. By default, the command will use the active network and address, but you can specify any values for these using the following parameters:
- `--address` argument to provide a specific address (or its alias),
- `--url` argument to provide a custom faucet endpoint.
## Request test tokens through wallet
You can request test tokens within IOTA Wallet.
:::tip Connect Wallet
Connect your wallet to request testnet tokens.
:::
## Using cURL
You can use the following cURL command to request tokens directly from the faucet server:
```
curl --location --request POST 'https://faucet.testnet.iota.cafe/gas' \
--header 'Content-Type: application/json' \
--data-raw '{
"FixedAmountRequest": {
"recipient": ""
}
}'
```
:::tip Test tokens on a local network
If you're working with a local network, replace {Networks.iota_testnet.faucet} with the appropriate value based on which package runs your network:
- `iota-faucet`: `http://127.0.0.1:5003/gas`
- `iota-localnet start`: `http://127.0.0.1:9123/gas`
You can also get tokens from your [local faucet](local-network.mdx#use-the-local-faucet).
:::
## Using the TypeScript SDK
You can also access the faucet using the IOTA TypeScript-SDK, as shown in the example below:
```typescript
import { getFaucetHost, requestIotaFromFaucetV1 } from '@iota/iota-sdk/faucet';
// get tokens from the Devnet faucet server
await requestIotaFromFaucetV1({
// connect to Devnet
host: getFaucetHost('devnet'),
recipient: '',
});
```
---
## Getting Started
IOTA offers Move smart contracts on layer 1, complementing [IOTA EVM](../../about-iota/about-iota.mdx#iota-evm) on layer 2.
The guides in this section will guide you as you start your IOTA journey. We recommend that you start
by [setting up your development environment](iota-environment.mdx), and then move on
to [install IOTA](install-iota.mdx).
## GraphQL queries
Use the GraphQL service for IOTA RPC to interact with on-chain data.
Go to [Query IOTA RPC with GraphQL](graphql-rpc.mdx).
## What's Next?
If you are already familiar with the basics, you can try the following sections:
- [Create a Move Package](create-a-package.mdx): Learn by writing, building, and publishing a simple dApp.
- [IOTA 101](../iota-101/iota-101.mdx): Get an overview of
the [Move concepts](../iota-101/move-overview/move-overview.mdx) you'll use as a foundation to
build [create coins, tokens](../iota-101/create-coin/create-coin.mdx) and [NFTs](../iota-101/nft/create-nft.mdx) using the
Move's [Object Model](../iota-101/objects/object-model.mdx).
- [From Solidity/EVM to Move](../evm-to-move/evm-to-move.mdx): If you're an experienced Solidity developer, check out
the key differences between developing on Move.
- Learn Move with the [IOTA Capture the Flag](../iota-move-ctf/introduction.mdx) challenges.
- [Cryptography](../cryptography.mdx): Leverage multiple cryptographic algorithms to
create secure and flexible smart contracts applications.
---
## Querying IOTA RPC with GraphQL
The quickest way to access the GraphQL service for IOTA RPC is through the online IDE that provides a complete toolbox for fetching data and executing transactions on the network. The online IDE provides features such as auto-completion (use Ctrl+Space or just start typing), built-in documentation (Book icon, top-left), multi-tabs, and more.
The online IDE is available for [Devnet](https://graphql.devnet.iota.cafe) and [Testnet](https://graphql.testnet.iota.cafe). This guide contains various queries that you can try directly in the IDE.
:::info
- Any existing addresses/object IDs in these examples refer to `testnet` data only.
- Both [devnet](https://graphql.devnet.iota.cafe) and [testnet](https://graphql.testnet.iota.cafe) services are rate-limited to keep network throughput optimized.
:::
For more details about some concepts used in the examples below, please see the [GraphQL concepts](../graphql-rpc.mdx) page, and consult the [reference](../../developer/references/iota-graphql.mdx) for full documentation on the supported schema.
## Discovering the schema
GraphQL introspection exposes the schema supported by the RPC service. The IDE's "Docs" pane (Book icon, top-left) and Search dialog (Cmd+K on macOS or Ctrl+K on Windows and Linux) offer a way to browse introspection output interactively.
The [official documentation](https://graphql.org/learn/introspection/) provides an overview on introspection, and how to interact with it programmatically.
## Finding the reference gas price for latest epoch
```graphql
query {
epoch {
referenceGasPrice
}
}
```
## Finding information about a specific historical epoch
This example finds the total stake rewards, the reference gas price, the number of checkpoints and the total gas fees for epoch 100. Note that in the query, the `id` argument is optional, and defaults to the latest epoch.
```graphql
query {
epoch(id: 100) # note that id is optional, and without it, latest epoch is returned
{
epochId
totalStakeRewards
referenceGasPrice
totalCheckpoints
totalGasFees
totalStakeSubsidies
storageFund {
totalObjectStorageRebates
nonRefundableBalance
}
}
}
```
## Finding a transaction block by its digest
This example gets a transaction block by its digest and shows information such as the gas sponsor's address, the gas price, the gas budget, and effects from executing that transaction block.
```graphql
query {
transactionBlock(digest: "FdKFgsQ9iRrxW6b1dh9WPGuNuaJWMXHJn1wqBQSqVqK2") {
gasInput {
gasSponsor {
address
}
gasPrice
gasBudget
}
effects {
status
timestamp
checkpoint {
sequenceNumber
}
epoch {
epochId
referenceGasPrice
}
}
}
}
```
## Finding the last ten transactions that are not a system transaction
```graphql
query {
transactionBlocks(last: 10, filter: {kind: PROGRAMMABLE_TX}) {
nodes {
digest
kind {
__typename
}
}
}
}
```
## Finding all transactions that touched a given object
This example finds all the transactions that touched (modified/transferred/deleted) a given object. This is useful for when we want to trace the flow of a Coin/StakeIOTA/NFT.
:::info
This example uses GraphQL [variables](../graphql-rpc.mdx#variables) and [pagination](../graphql-rpc.mdx#pagination). When using the online IDE, copy the variables JSON to the "Variables" window, below the main editor.
:::
```graphql
query ($objectID: IotaAddress!) {
transactionBlocks(filter: {changedObject: $objectID}) {
nodes {
sender {
address
}
digest
effects {
objectChanges {
nodes {
address
}
}
}
}
}
}
```
**Variables**:
```json
{
"objectID": "0x11c6ae8432156527fc2e12e05ac7db79f2e972510a823a4ef2e670f27ad7b52f"
}
```
## Filtering transaction blocks by a function
This example finds the last ten transaction blocks that called the `public_transfer` function, (as a move call transaction command).
:::info
This example makes usage of the filter `last`, which indicates that the user only wants the last ten transaction blocks known to the service.
:::
```graphql
{
transactionBlocks(
last: 10,
filter: {
function: "0x2::transfer::public_transfer"
}
) {
nodes { digest }
}
}
```
## Finding transaction balance changes
This example finds the balance changes of all the transactions where a given address called a staking-related function. This is useful when you want to get your staking or unstaking history.
```graphql
query ($address: IotaAddress!) {
transactionBlocks(filter: {
function: "0x3::iota_system::request_add_stake"
signAddress: $address
}) {
nodes {
digest
effects {
balanceChanges {
nodes {
owner {
address
}
amount
}
}
}
}
}
}
```
**Variables**:
```json
{
"address": "0xa9ad44383140a07cc9ea62d185c12c4d9ef9c6a8fd2f47e16316229815862d23"
}
```
## Fetching a dynamic field on an object
:::info
This example uses aliases and [fragments](../graphql-rpc.mdx#fragments).
:::
```graphql
query DynamicField {
object(
address: "0xb57fba584a700a5bcb40991e1b2e6bf68b0f3896d767a0da92e69de73de226ac"
) {
dynamicField(
name: {
type: "0x2::kiosk::Listing",
bcs: "NLArx1UJguOUYmXgNG8Pv8KbKXLjWtCi6i0Yeq1VhfwA",
}
) {
...DynamicFieldSelect
}
}
}
fragment DynamicFieldSelect on DynamicField {
name {
...MoveValueFields
}
value {
...DynamicFieldValueSelection
}
}
fragment DynamicFieldValueSelection on DynamicFieldValue {
__typename
... on MoveValue {
...MoveValueFields
}
... on MoveObject {
contents {
...MoveValueFields
}
}
}
fragment MoveValueFields on MoveValue {
type {
repr
}
data
bcs
}
```
## Fetching all dynamic fields on an object
This query can be used to paginate over the dynamic fields of an object. This works even when the object in question is [wrapped](../iota-101/objects/object-ownership/wrapped.mdx), by using the owner query, so can be used for iterating over the elements of on-chain data structures, like [Tables and Bags](../iota-101/objects/dynamic-fields/tables-bags.mdx).
:::info
This example uses [fragments](../graphql-rpc.mdx#fragments) and [variables](../graphql-rpc.mdx#variables).
:::
```graphql
query ($id: IotaAddress!) {
owner(address: $id) {
dynamicFields {
nodes {
name { ...Value }
value {
__typename
... on MoveValue {
...Value
}
... on MoveObject {
contents {
...Value
}
}
}
}
}
}
}
fragment Value on MoveValue {
type {
repr
}
json
}
```
## Paginating checkpoints forward, five at a time
```graphql
query ($after: String) {
checkpoints(first: 5, after: $after) {
pageInfo {
hasNextPage
endCursor
}
nodes {
digest
timestamp
}
}
}
```
Sets up a paginated query, starting at the genesis checkpoint, reading five checkpoints at a time, in increasing order of sequence number. The value of `pageInfo.hasNextPage` determines whether there is another page to be read, and the value of `pageInfo.endCursor` is fed back in as the cursor to read `$after`.
:::info
This example uses GraphQL [variables](../graphql-rpc.mdx#variables) and [pagination](../graphql-rpc.mdx#pagination).
:::
## Paginating checkpoints backwards, five at a time
```graphql
query ($before: String) {
checkpoints(last: 5, before: $before) {
pageInfo {
hasPreviousPage
startCursor
}
nodes {
digest
timestamp
}
}
}
```
Sets up a paginated query, starting at the latest indexed checkpoint, reading five checkpoints at a time, in decreasing order of sequence number. The value of `pageInfo.hasPreviousPage` determines whether there is another page to be read, and the value of `pageInfo.startCursor` is fed back in as the cursor to read `$before`.
:::info
This example uses GraphQL [variables](../graphql-rpc.mdx#variables) and [pagination](../graphql-rpc.mdx#pagination).
:::
## Executing a transaction
Transaction execution takes in two arguments, `txBytes` and `signatures`. `txBytes` is the serialized unsigned transaction data, which can be generated when using the IOTA CLI's `client call` [command](../../developer/references/cli/client.mdx), to call a Move function by passing the `--serialize-unsigned-transaction` flag. The `signatures` can be generated using IOTA CLI's [keytool](../../developer/references/cli/keytool.mdx) command `iota keytool sign`. More information on IOTA CLI can be found [here](../../developer/references/cli).
```graphql
mutation ($tx: String!, $sigs: [String!]!) {
executeTransactionBlock(txBytes: $tx, signatures: $sigs) {
errors
effects {
status
epoch {
startTimestamp
}
gasEffects {
gasSummary {
computationCost
}
}
}
}
}
```
**Variables**:
```json
{
"tx": "AAACACAZXApmrHgzTs3FGDyXWka+wmMCy2IwOdKLmTWHb5PnFQEASlCnLAw4qfzLF3unH9or5/L7YpOlReaSEWfoEwhTqpavSxAAAAAAACCUFUCOn8ljIxcG9O+CA1bzqjunqr4DLDSzSoNCkUvu2AEBAQEBAAEAALNQHmLi4jgC5MuwwmiMvZEeV5kuyh+waCS60voE7fpzAa3v/tOFuqDvQ+bjBpKTfjyL+6yIg+5eC3dKReVwghH/rksQAAAAAAAgxtZtKhXTr1zeFAo1JzEqVKn9J1H74ddbCJNVZGo2I1izUB5i4uI4AuTLsMJojL2RHleZLsofsGgkutL6BO36c+gDAAAAAAAAQEIPAAAAAAAA",
"sigs": [
"AB4ZihXxUMSs9Ju5Cstuuf/hvbTvvycuRk2TMuagLYNJgQuAeXmKyJF9DAXUtL8spIsHrDQgemn4NmojcNl8HQ3JFqhnaTC8gMX4fy/rGgqgL6CDcbikawUUjC4zlkflwg=="
]
}
```
## Other examples
You can find other examples in the [repository](https://github.com/iotaledger/iota/tree/develop/crates/iota-graphql-rpc/examples).
## Related links
- [GraphQL migration](../advanced/graphql-migration.mdx): Migrating to GraphQL guides you through migrating IOTA RPC projects from JSON-RPC to GraphQL.
- [GraphQL concepts](../graphql-rpc.mdx): GraphQL for IOTA RPC examines the elements of GraphQL that you should know to get the most from the service.
- [GraphQL reference](../../developer/references/iota-graphql.mdx): Auto-generated GraphQL reference for IOTA RPC.
---
## Install IOTA
In order to deploy your contracts and interact with the chains some tooling is required. IOTA has an excellent command-line tool that can be used for the most common tasks.
The simplest way to get up and running with IOTA is to [install the binary](#install-from-binaries) from the latest
release available in the [IOTA GitHub Repository](https://github.com/iotaledger/iota/). Make sure to download
the version that matches the network you want to work on.
You can also use the
convenient [docker images in the repository](https://github.com/iotaledger/iota/tree/develop/docker) to run your own
local network.
If you require full control over the installation sources and process, you can
always [build the binaries yourself from source](#install-from-source).
## Supported operating systems
IOTA supports the following operating systems:
- Linux - Ubuntu version 20.04 (Bionic Beaver) or later
- macOS - macOS Monterey or later
- Microsoft Windows - Windows 10 or later
## Install Using a Package Manager
You can use [Homebrew](https://brew.sh/) on macOS, Linux, or Windows Subsystem for Linux to install `iota`:
```bash
brew install iotaledger/tap/iota
```
## Install From Binaries
You can find a set of binaries for most operating systems with
each [IOTA release](https://github.com/iotaledger/iota/releases) that you can use to install IOTA. We recommend using
the latest stable release for the network you are working on.
1. Go to https://github.com/iotaledger/iota/releases.

1. Click the release tagged **Latest** to open the release's page.
1. In the **Assets** section of the release, select the .tgz compressed file that corresponds to your operating system.
1. Extract all files from the .tgz file into the preferred location on your system. These instructions assume you extract the files into a `iota` folder at the user root of your system for demonstration purposes. Replace references to this location in subsequent steps if you choose a different directory.
1. Once you have downloaded and extracted the `.tgz` file that matches your operating system, you should open the folder
and install the necessary binaries. You should start with the main IOTA binary:
| Name | Description |
| --------------------- | ----------------------------------------------------------- |
| `iota` | Main IOTA binary. |
| `iota-data-ingestion` | Capture full node data for indexer to store in a database. |
| `iota-faucet` | Local faucet to mint coins on local network. |
| `iota-graphql-rpc` | GraphQL service for IOTA RPC. |
| `iota-indexer` | An indexer for a local IOTA network. |
| `iota-localnet` | Start and manage IOTA local networks. |
| `iota-node` | Run a local node. |
| `iota-tool` | Provides low-level utilities for debugging and maintenance. |
| `move-analyzer` | Language Server Protocol implementation. |
1. Add the folder containing the extracted files to your `PATH` variable. To do so, you can update your `~/.bashrc` to include the location of the `IOTA` binaries. If using the suggested location, you type `export PATH=$PATH:~/iota` and press Enter.
1. Start a new terminal session or type `source ~/.bashrc` to load the new `PATH` value.
1. Go to https://github.com/iotaledger/iota/releases.

1. Click the release tagged **Latest** to open the release's page.
1. In the **Assets** section of the release, select the .tgz compressed file that corresponds to your operating system.
1. Extract all files from the .tgz file into the preferred location on your system. These instructions assume you extract the files into a `iota` folder at the user root of your system. Replace references to this location in subsequent steps if you choose a different directory.
1. Once you have downloaded and extracted the `.tgz` file that matches your operating system, you should open the folder
and install the necessary binaries. You should start with the main IOTA binary:
| Name | Description |
| --------------------- | ----------------------------------------------------------- |
| `iota` | Main IOTA binary. |
| `iota-data-ingestion` | Capture full node data for indexer to store in a database. |
| `iota-faucet` | Local faucet to mint coins on local network. |
| `iota-graphql-rpc` | GraphQL service for IOTA RPC. |
| `iota-indexer` | An indexer for a local IOTA network. |
| `iota-localnet` | Start and manage IOTA local networks. |
| `iota-node` | Run a local node. |
| `iota-tool` | Provides low-level utilities for debugging and maintenance. |
| `move-analyzer` | Language Server Protocol implementation. |
1. Add the folder containing the extracted files to your `PATH` variable. To do so, you can update your `~/.zshrc` or `~/.bashrc` to include the location of the IOTA binaries. If using the suggested location, you type `export PATH=$PATH:~/iota` and press Enter.
1. Start a new terminal session or type `source ~/.zshrc` (or `.bashrc`) to load the new `PATH` value.
1. If running the binaries for the first time, you might receive an error from MacOS that prevents the binaries from running. If you receive this error, close the dialog and type `xattr -d com.apple.quarantine ~/iota/*` in your terminal and press Enter (be sure to adjust the path if different).
1. Go to https://github.com/iotaledger/iota/releases.

1. Click the release tagged **Latest** to open the release's page.
1. In the **Assets** section of the release, select the .tgz compressed file that corresponds to your operating system.
1. Extract all files from the .tgz file into the preferred location on your system. These instructions assume you extract the files into a `iota` folder at the root of your C drive. Replace references to this location in subsequent steps if you choose a different directory.
:::info
Older versions of Windows do not natively support .tgz files, but you can use a free app like [7Zip](https://7-zip.org/) to extract them.
:::
1. Navigate to the expanded folder. You should have the following extracted files
| Name | Description |
| --------------------- | ----------------------------------------------------------- |
| `iota` | Main IOTA binary. |
| `iota-data-ingestion` | Capture full node data for indexer to store in a database. |
| `iota-faucet` | Local faucet to mint coins on local network. |
| `iota-graphql-rpc` | GraphQL service for IOTA RPC. |
| `iota-indexer` | An indexer for a local IOTA network. |
| `iota-localnet` | Start and manage IOTA local networks. |
| `iota-node` | Run a local node. |
| `iota-tool` | Provides low-level utilities for debugging and maintenance. |
| `move-analyzer` | Language Server Protocol implementation. |
1. Add the folder containing the extracted files to your `PATH` variable. There are several ways to get to the setting depending on your version of Windows. One way that works on all versions of Windows is to type `sysdm.cpl` in a console to open the System Properties window. Under the **Advanced** tab, click the **Environment Variables...** button.
1. In the Environment Variables window, select the `Path` variable and click the **Edit...** button.
1. In the Edit environment variable window, click **New** and add the path to your expanded folder. Using the example path, this would be `C:\iota`.
1. Click **OK**.
:::info
Running binaries other than `iota` might require installing prerequisites itemized in the following section.
:::
### Test
You can quickly test if you have successfully installed the binaries by running the following command:
```bash
iota
```
It should output a message stating the currently installed IOTA version and some helpful commands.
## Install From Source
You can use this section to install the Rust crates (packages) to interact with IOTA networks, including the IOTA CLI,
from source.
:::tip
You can also download the [source code](../advanced/iota-repository.mdx) to access files locally.
:::
### Prerequisites
Please ensure you install the following before attempting to install IOTA from source.
#### Rust and Cargo
##### Install
Like most Rust projects, IOTA uses Cargo as a package manager. You can find detailed instructions
on how to install Rust and Cargo for your OS in
the [official Rust Documentation](https://www.rust-lang.org/tools/install)
You can use the following command to install Rust and Cargo on macOS or Linux:
```bash
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
```
##### Update
Since IOTA uses the latest version of Cargo to build and manage dependencies, you may need
to [update](https://www.rust-lang.org/tools/install). The recommended update method is using `rustup`, as shown below:
```bash
rustup update stable
```
#### Additional Prerequisites by Operating System
Select the appropriate tab to view the requirements for your system.
The prerequisites needed for the Linux operating system include:
- cURL
- Rust and Cargo
- Git CLI
- CMake
- GCC
- libssl-dev
- libclang-dev
- build-essential
:::info
The Linux instructions assume a distribution that uses the APT package manager. You might need to adjust the
instructions to use other package managers.
:::
Install the prerequisites listed in this section. Use the following command to update `apt-get`:
```bash
sudo apt-get update
```
##### All Linux prerequisites
Reference the relevant sections that follow to install each prerequisite individually, or run the following to install
them all at once:
```bash
sudo apt-get install curl git-all cmake gcc libssl-dev pkg-config libclang-dev build-essential
```
:::info
If you plan to build `iota-indexer` or run `iota-localnet` with the `indexer` feature, you also need `libpq-dev`:
```bash
sudo apt-get install libpq-dev
```
:::
##### cURL
Install cURL with the following command:
```bash
sudo apt-get install curl
```
Verify that cURL is installed correctly with the following command:
```bash
curl --version
```
##### Git CLI
Run the following command to install Git, including the [Git CLI](https://cli.github.com/):
```bash
sudo apt-get install git-all
```
For more information, see [Install Git on Linux](https://github.com/git-guides/install-git#install-git-on-linux) on the
GitHub website.
##### CMake
Use the following command to install CMake.
```bash
sudo apt-get install cmake
```
To customize the installation, see [Installing CMake](https://cmake.org/install/) on the CMake website.
##### GCC
Use the following command to install the GNU Compiler Collection, `gcc`:
```bash
sudo apt-get install gcc
```
##### libssl-dev
Use the following command to install `libssl-dev`:
```bash
sudo apt-get install libssl-dev
```
If the version of Linux you use doesn't support `libssl-dev,` find an equivalent package for it on
the [ROS Index](https://index.ros.org/d/libssl-dev/).
(Optional) If you have OpenSSL, you might also need also to install `pkg-config`:
```bash
sudo apt-get install pkg-config
```
##### libclang-dev
Use the following command to install `libclang-dev`:
```bash
sudo apt-get install libclang-dev
```
If the version of Linux you use doesn't support `libclang-dev`, find an equivalent package for it on
the [ROS Index](https://index.ros.org/d/libclang-dev/).
##### build-essential
Use the following command to install `build-essential`:
```bash
sudo apt-get install build-essential
```
The prerequisites needed for the macOS operating system include:
- Rust and Cargo
- Homebrew
- cURL
- CMake
- Git CLI
MacOS includes a version of cURL that you can use to install Homebrew. Use Homebrew to install other tools, including a
newer
version of cURL.
##### Homebrew
Use the following command to install [Homebrew](https://brew.sh/):
```bash
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
```
:::info
You do not need to install anything else if you installed IOTA with [Homebrew](#homebrew).
:::
##### All macOS prerequisites
With Homebrew installed, you can install individual prerequisites from the following sections or install them all at
once with this command:
```bash
brew install curl cmake git
```
:::info
If you plan to build `iota-indexer` or run `iota-localnet` with the `indexer` feature, you also need `libpq`:
```bash
brew install libpq
```
:::
##### cURL
Use the following command to update the default [cURL](https://curl.se) on macOS:
```bash
brew install curl
```
##### CMake
Use the following command to install CMake:
```bash
brew install cmake
```
To customize the installation, see [Installing CMake](https://cmake.org/install/) on the CMake website.
##### Git CLI
Use the following command to install Git:
```bash
brew install git
```
After installing Git, download and install the [Git command line interface](https://git-scm.com/download/).
The prerequisites needed for the Windows 11 operating system include:
- cURL
- Rust and Cargo
- Git CLI
- CMake
- C++ build tools
- LLVM compiler
##### cURL
Windows 11 ships with an installed Microsoft version of [cURL](https://curl.se/windows/microsoft.html). If you
want to use the curl project version instead, download and install it
from [https://curl.se/windows/](https://curl.se/windows/).
##### Git CLI
Download and install the [Git command line interface](https://git-scm.com/download/).
##### CMake
Download and install [CMake](https://cmake.org/download/) from the CMake website.
##### Protocol Buffers
Download [Protocol Buffers](https://github.com/protocolbuffers/protobuf/releases) (protoc-xx.x-win32.zip or
protoc-xx.x-win64.zip) and add the \bin directory to your Windows PATH environment variable.
##### Additional tools for Windows
IOTA requires the following additional tools for computers running Windows:
- For Windows on ARM64 only - [Visual Studio 2022 Preview](https://visualstudio.microsoft.com/vs/preview/).
- [C++ build tools](https://visualstudio.microsoft.com/downloads/) is required to [install Rust](#rust-and-cargo).
- The [LLVM Compiler Infrastructure](https://releases.llvm.org/). Look for a file with a name similar to
LLVM-15.0.7-win64.exe for 64-bit Windows or LLVM-15.0.7-win32.exe for 32-bit Windows.
### Install IOTA Binaries From Source
Run the following command to install IOTA binaries from the `testnet` branch:
```shell
cargo install --locked --git https://github.com/iotaledger/iota.git --branch testnet iota
```
:::info Alternative releases
Replace `testnet` with another branch if needed when working on anything besides the testnet. Common options would be `develop` for the absolute latest version, `devnet` and `mainnet`.
See the [repository details](../advanced/iota-repository.mdx) for more information on commonly used branches.
:::
The installation process can take a while to complete. You can monitor the installation progress in the terminal. If you encounter an error, install the latest version of all prerequisites and try the command again.
To update to the latest stable version of Rust:
```shell
rustup update stable
```
The command installs IOTA components in the `~/.cargo/bin` folder.
#### Additional Binaries
The `iota` binary provides client commands for interacting with the network. If you need to run a local network for development, install the `iota-localnet` binary separately:
```shell
cargo install --locked --git https://github.com/iotaledger/iota.git --branch testnet iota-localnet
```
To also enable the local indexer and GraphQL server, build with the `indexer` feature:
```shell
cargo install --locked --git https://github.com/iotaledger/iota.git --branch testnet --features indexer iota-localnet
```
:::info Requirement: PostgreSQL
Building `iota-localnet` with the `indexer` feature requires PostgreSQL to be installed on your system.
```bash
sudo apt-get install -y libpq-dev
```
```bash
brew install libpq
```
You can use Chocolatey to install PostgreSQL:
```bash
choco install postgresql
```
:::
For advanced tools like transaction replay, genesis ceremony, and fire drill, install `iota-tool`:
```shell
cargo install --locked --git https://github.com/iotaledger/iota.git --branch testnet iota-tool
```
### Upgrade IOTA Binaries
If you previously installed the IOTA binaries, you can update them to the most recent release with the same command you
used to install them:
```shell
cargo install --locked --git https://github.com/iotaledger/iota.git --branch testnet iota
```
---
## VSCode Move Extension
import MoveAnalyzer from '../../../../external-crates/move/crates/move-analyzer/editors/code/README.md';
---
## Before You Start
It's a good idea to look at the toolbox before you start building. This section will give you a quick overview
of the most important tools to get started:
* How you can interact with IOTA Nodes using the [CLI](#iota-cli) or the [available SDKs](#iota-sdks).
* IDEs and plugins.
## Interact with IOTA
### IOTA CLI
The [IOTA CLI](../../developer/references/cli.mdx) provides a handy interface you can use to perform all sorts of operations with
IOTA nodes.
### IOTA SDKs
IOTA provides two official SDKs that you can use to interact with the IOTA network from your dApp:
* [Typescript SDK](../../developer/ts-sdk/typescript/index.mdx)
* [Rust SDK](../../developer/iota-sdk/getting-started/rust.mdx)
## Move IDEs and plugins
We recommend that you use the [Visual Studio Code](https://code.visualstudio.com/) IDE with the [IOTA Move](https://marketplace.visualstudio.com/items?itemName=iotaledger.iota-move) extension installed.
---
## Local Development
You can create a local IOTA network to develop and test your dApps with the latest changes in the IOTA repository. You
can set it up using the `iota-localnet` binary with the `iota-localnet start` subcommand, which can start a local IOTA network
consisting of 4 IOTA validators with indexer and a test token faucet.
## Prerequisites
You should [install the IOTA CLI tool](install-iota.mdx) to interact with the local node.
## Start a Local Network
If you installed IOTA using [a package manager](install-iota#install-using-a-package-manager) or by downloading the
[binaries](install-iota.mdx#install-from-binaries) from the [IOTA GitHub repository](https://github.com/iotaledger/iota/), you can start a local network by
running the following command:
```bash
RUST_LOG="off,iota_node=info" iota-localnet start --force-regenesis --with-faucet
```
If you want to [build IOTA from source](install-iota.mdx#install-iota-binaries-from-source), you can start a local network by running the following command from your `iota` root folder:
```bash
RUST_LOG="off,iota_node=info" cargo run --bin iota-localnet start --force-regenesis --with-faucet
```
The command will start a local network with a test token faucet. The `RUST_LOG`=`off,iota_node=info` turns off logging for all
components except `iota-node`. If you want to see more detailed logs, you can remove `RUST_LOG` from the command.
:::danger No persistence
Data on the local network does not persist when the `--force-regenesis` flag is
used.
To persist data use the `--network.config` flag instead.
```bash
iota-localnet start --network.config persisted-localnet --with-faucet --committee-size 2 --epoch-duration-ms 60000
```
:::
## Customize a Local Network
You can add the following additional parameters to the [start command](#start-a-local-network) to customize your
network:
* `--epoch-duration-ms `: Change epoch duration from the default one minute to your desired value.
* `--with-faucet=`: Change the port where the IOTA faucet starts.
* `--fullnode-rpc-port `: Change the port where the Full-node RPC server starts.
:::tip Validator Help
Use `iota-localnet start --help` to see these options in your console.
:::
The network binds the same ports on every run, listed under [Ports](../references/cli/localnet.mdx#ports).
## Interact With Your Local Node
### Using cURL
You can use cURL to send JSON requests to your local node. The following example will retrieve the total transaction
count from your local network:
```bash
curl --location --request POST 'http://127.0.0.1:9000' \
--header 'Content-Type: application/json' \
--data-raw '{
"jsonrpc": "2.0",
"id": 1,
"method": "iota_getTotalTransactionBlocks",
"params": []
}'
```
If successful, the response resembles the following:
```json
{
"jsonrpc": "2.0",
"result": 168,
"id": 1
}
```
### Using the IOTA Client CLI
#### Create a local env
The IOTA Client CLI is compatible with all IOTA networks. You only need to specify the RPC URL by passing
the `--rpc ` parameter. We recommend that you also assign an alias to the network by passing
the `--alias ` parameter so you can easily access this env in the future.
```shell
iota client new-env --alias local --rpc http://127.0.0.1:9000
```
#### Connect to the local env
After [creating the env](#create-a-local-env), you can use the `switch` command to set it as the current active
environment:
```
iota client switch --env local
```
You can check the current active environment with the following command, which should return the environment alias you
assigned:
```bash
iota client active-env
```
#### Show the current active address
The IOTA Client CLI will default to the active address if you don't specify an address. You can use the following
command to show the current active address on your local network.
```
iota client active-address
```
:::tip Get All Addresses
You can also use the `iota client addresses` command to see all the addresses on your local network.
:::
#### Use the local faucet
Even though it's a local network, transactions still require [gas](../../about-iota/tokenomics/gas-pricing.mdx). You can use
You can use the `iota client faucet` command to get coins from your local faucet. Keep in mind that it may take up to
one minute
to complete your request. You can check if your coins have arrived using the `iota client gas` command.
:::info Faucet Help
The `faucet` command uses the active address and the active network environment by default. If you need to pass in a
different address or faucet server URL, check the `help` menu. If you're using a different network than a local
or public one, you must pass the URL to the faucet server.
:::
:::note IOTA Wallet
To send coins to an
IOTA Wallet that is connected to your local network. See [Set up a local IOTA Wallet](#set-up-a-local-iota-wallet). You can use
the address for the local IOTA Wallet with the faucet.
:::
#### Check the gas coin objects for the active address
After you [get coins from the faucet](#use-the-local-faucet), you can use the following command to view the coin objects
for the address:
```shell
iota client gas
```
The response resembles the following, but with different IDs:
```shell
╭────────────────────────────────────────────────────────────────────┬────────────╮
│ gasCoinId │ gasBalance │
├────────────────────────────────────────────────────────────────────┼────────────┤
│ 0x1d790713c1c3441a307782597c088f11230c47e609af2cec97f393123ea4de45 │ 200000000 │
│ 0x20c1d5ad2e8693953fca09fd2fec0fbc52a787e0a0f77725220d36a09a5b312d │ 200000000 │
│ [...] │ │
╰────────────────────────────────────────────────────────────────────┴────────────╯
```
:::tip explorer
In order to use the explorer locally users can use the deployed explorer and set another endpoint like this: [https://explorer.iota.org/?network=http%3A%2F%2F127.0.0.1%3A9000](https://explorer.iota.org/?network=http%3A%2F%2F127.0.0.1%3A9000) or manually provide a Custom RPC URL on the [Explorer](https://explorer.iota.org/) page in the top right corner.
:::
:::warning HTTPS only
The [IOTA Explorer](https://explorer.iota.org) requires a secure HTTPS connection. If your local network doesn't support HTTPS, consider [running your own instance of the Explorer](https://github.com/iotaledger/iota/tree/develop/apps/explorer#iota-explorer).
:::
## Install IOTA Wallet Locally
The IOTA Wallet is a Chrome extension you can use for manual tests with your local network.
### Prerequisites
* [Node.js 20+](https://nodejs.org/en/download/package-manager)
* [pnpm](https://pnpm.io/installation)
* [Rust 1.82+ nightly](https://www.rust-lang.org/tools/install), with target `wasm32-unknown-unknown`
* [docker-compose](https://docs.docker.com/compose/install/) (and docker daemon running)
### Install Dependencies
After you install `pnpm`, you should run the following command from the root folder of IOTA to install the necessary dependencies:
```shell
pnpm install
```
### Build
After the installation completes, run the following command to build the IOTA Wallet:
```shell
pnpm turbo build
```
### Set Up a Local IOTA Wallet
You can use a local IOTA Wallet to test with your local network.
#### Configure the Wallet
Before you start the IOTA Wallet app, update its default environment to point to your local network. First,
make a copy of `iota/apps/wallet/configs/environment/.env.defaults` and rename it to `.env` in the same directory. In
your `.env` file, edit the first line to read `API_ENV=local` and then save the file.
Run the following command from the `iota` root folder to start the IOTA Wallet on your local network:
```bash
pnpm wallet build
```
### Add a Local IOTA Wallet to Chrome
After you build your local version of IOTA Wallet, you can add the extension to Chrome:
1. Open a Chrome browser to `chrome://extensions`.
2. Click the **Developer mode** toggle to enable if it's not already on.
3. Click the **Load unpacked** button and select your `apps/wallet/dist` directory in your local copy of the [IOTA repository](../advanced/iota-repository.mdx).
Consult the IOTA
Wallet [Readme](https://github.com/iotaledger/iota/blob/develop/apps/wallet/README.md#install-the-extension-to-chrome) for
more information on working with a locally built wallet on Chrome is needed.
## Generate example data
Use the TypeScript SDK to add example data to your network.
:::note
Before running the command, you must complete the `[Prerequisites for Building Apps locally](../getting-started/install-iota#prerequisites)` section.
:::
Run the following command from the `iota` root folder:
```bash
pnpm --filter @iota/iota-sdk test:e2e
```
For additional information about example data for testing, see [https://github.com/iotaledger/iota/tree/develop/sdk/typescript#testing](https://github.com/iotaledger/iota/tree/develop/sdk/typescript#testing).
## Troubleshooting
| Error Message | Solution |
| -------------------------------------------------- | ------------------------------------------------------------------------------------------ |
| Retrying requesting from the faucet: Retry failed: fetch is not defined | Update or switch to Node.js version 20+. |
| Error: tsx must be loaded with --import instead of --loader | Update or switch to Node.js version 20+. |
## Test with the IOTA TypeScript SDK
The published version of the IOTA TypeScript SDK might be an earlier version than the version of IOTA you installed for
your local network. To make sure you're using the latest version of the SDK, use a local built version of SDK.
In your local checkout of the [IOTA repository](../advanced/iota-repository.mdx) make sure you are using the same branch as the network you are developing against. Run
```bash
pnpm install && pnpm build
```
to compile the SDK.
To use the local built SDK in your project go to your project folder and execute
```bash
pnpm add /sdk/typescript
```
and the locally compiled version of `@iota/iota-sdk` package will be installed for your application.
---
## Move Trace Debugging
import MoveAnalyzer from '../../../../external-crates/move/crates/move-analyzer/trace-debug/README.md';
---
## Introduction to Oracles in Blockchain
Smart contracts are powerful tools in the blockchain ecosystem, enabling automated, self-executing agreements based on
predefined conditions. However, one of their fundamental limitations is that they operate in a sandboxed environment.
This isolation ensures that smart contracts produce the same results every time they run, maintaining the deterministic
nature essential for blockchain's integrity and trust. But this also means smart contracts cannot directly access
or interact with external data or systems.
## Bridging the Gap with Oracles
Oracles serve as a critical bridge in this scenario, connecting the isolated world of smart contracts with external data
sources. They play a pivotal role in expanding the functionality of smart contracts by providing them
with real-world information. Oracles fetch data from various external sources, like internet APIs, real-world sensors,
and other data feeds, and then relay this information to the smart contracts on the blockchain.
### Ensuring Idempotent Results
The key challenge for oracles in the blockchain context is to provide data with enough specificity and reliability to
guarantee idempotent results - the property that a smart contract will produce the same outcome every time it's executed
under the same conditions. This consistency is crucial for maintaining trust and predictability in the blockchain
environment.
Oracles achieve this by sourcing data from reliable and verified external sources and using consensus mechanisms or
multiple data points to validate the information's accuracy. This process ensures that the data provided to the smart
contracts is relevant and timely, maintaining the integrity and deterministic nature of the blockchain
operations.
## Oracle Provider in IOTA Ecosystem
### Pyth
The Pyth Network delivers real-time financial market data across multiple blockchains and can be used in off-chain applications.
Pyth gets contributions from over 90 publishers, including several exchanges. It offers comprehensive and accurate price
feeds for asset classes such as US equities, commodities, and cryptocurrencies. Its price feeds get updates
multiple times per second, ensuring they are current and reliable.
:::tip
You can learn more about Pyth Oracles in their [official documentation](https://docs.pyth.network/documentation).
:::
### IOTA Testnet
For details, refer to the [Pyth Network IOTA Price Feed Contract Address](https://docs.pyth.network/price-feeds/contract-addresses/iota#iota-testnet) in the official documentation.
#### Example Code
For detailed code example on how to use real-time Pyth data in IOTA applications, refer to the Pyth Network [How to Use Real-Time Data in IOTA Contracts documentation](https://docs.pyth.network/price-feeds/use-real-time-data/iota#install-pyth-sdk).
---
## Publish a Package
import PublishMovePackageButton from '@site/src/components/PublishMovePackageButton';
import sword_example from '../../../../examples/move/first_package/bytecode.json';
# Publish a Package
After you have successfully [created](create-a-package.mdx) and [tested](build-test.mdx) your package, the next step is to publish it so you can start using its functions on the IOTA network. When you publish a package, it becomes a permanent and immutable public object on the IOTA network.
## Publishing Your Package
To publish your package, use the IOTA client's `publish` command. Execute this command from your package's root directory, and include the `--gas-budget` parameter to set the maximum gas you're willing to spend on this transaction. If the transaction requires more gas than your budget, it will fail.
```shell
iota client publish
```
:::info Connect Wallet
You can connect your wallet to publish your package using its bytecode and the IOTA dApp Kit. You will see the objects directly in your wallet instead of the terminal output.
:::
Once the transaction succeeds, you will receive a response similar to the following, detailing the transaction data, effects, and any changes to objects and balances:
```
╭─────────────────────────────────────────────────────────────────────╮
│ Object Changes │
├─────────────────────────────────────────────────────────────────────┤
│ Created Objects: │
│ ... │
| |
│ Mutated Objects: │
│ ... │
| |
│ Published Objects: │
│ ┌── │
│ │ PackageID: │
│ │ Version: 1 │
│ │ Digest: │
│ │ Modules: first_package │
│ └── │
╰─────────────────────────────────────────────────────────────────────╯
```
The **Object Changes** section includes information about the package you just published, under **Published Objects**. Your actual `PackageID` will appear as an address, like `0x123...ABC`.
### Understanding Your Address's Object List
If this is your first time publishing a package, your active address should now hold three objects:
1. **Coin**: A `Coin` object that you obtained from the [Testnet faucet](get-coins.mdx).
2. **Forge**: The `Forge` created when you published this package. The `init` function was executed during the publishing process, creating the `Forge` and assigning it to you (the sender).
3. **UpgradeCap**: An `UpgradeCap` associated with the package. This object is used if you need to [upgrade your package](../iota-101/move-overview/package-upgrades/upgrade.mdx) or destroy it to make the package immutable.
```mermaid
flowchart TB
subgraph IOTA Blockchain
direction TB
address --> Forge
address --> UpgradeCap
address --> Coin
end
```
You can retrieve the complete list of objects associated with your address using the `iota client objects` command:
```shell
iota client objects
╭───────────────────────────────────────────────────────────────────────────────────────╮
│ ╭────────────┬──────────────────────────────────────────────────────────────────────╮ │
│ │ objectId │ │ │
│ │ version │ 3 │ │
│ │ digest │ │ │
│ │ objectType │ ::first_package::Forge │ │
│ ╰────────────┴──────────────────────────────────────────────────────────────────────╯ │
│ ╭────────────┬──────────────────────────────────────────────────────────────────────╮ │
│ │ objectId │ │ │
│ │ version │ 3 │ │
│ │ digest │ │ │
│ │ objectType │ 0x0000..0002::coin::Coin │ │
│ ╰────────────┴──────────────────────────────────────────────────────────────────────╯ │
│ ╭────────────┬──────────────────────────────────────────────────────────────────────╮ │
│ │ objectId │ │ │
│ │ version │ 3 │ │
│ │ digest │ │ │
│ │ objectType │ 0x0000..0002::package::UpgradeCap │ │
│ ╰────────────┴──────────────────────────────────────────────────────────────────────╯ │
╰───────────────────────────────────────────────────────────────────────────────────────╯
```
### Accessing Your Package
After successfully publishing the package, you can use the `iota client call` command to execute individual functions or create sophisticated [programmable transaction blocks](../iota-101/transactions/ptb/programmable-transaction-blocks) that group multiple commands into a single, cost-effective transaction with the `iota client ptb` command.
```mermaid
flowchart TB
first_package["first_package::new_sword(&Forge, strength, magic)"]
IOTA_client["IOTA client"]
subgraph IOTA Blockchain
first_package
first_package --Sword--> address
end
IOTA_client --"PTB"--> first_package
```
#### Programmable Transaction Example
The following example demonstrates how to call the `new_sword` function from your package to create a new `Sword` and then transfer it to a specified address.
```shell
$ iota client ptb \
--assign forge @ \
--assign to_address @ \
--move-call ::first_package::new_sword forge 3 3 \
--assign sword \
--transfer-objects "[sword]" to_address \
--gas-budget 100000000
```
:::info
You can pass literal addresses and objects IDs by prefixing them with '@'. This is needed to distinguish a hexadecimal value from an address in some situations.
For addresses that are in your local wallet, you can use their alias instead (passing them without '@', for example, --transfer-objects my_alias).
:::
Note how the command uses `--assign` to define variables for ``, ``, and ``. This approach helps maintain clarity in your PTBs. Ensure you replace ``, ``, and `` with the actual `objectId` of the `Forge` object, the recipient's address (your address, for instance), and the `packageID`, respectively.
After executing the transaction, verify the status of the `Sword` object using the `iota client objects` command again. If you set your address as the ``, you should now see a total of four objects:
```
╭───────────────────────────────────────────────────────────────────────────────────────╮
│ ╭────────────┬──────────────────────────────────────────────────────────────────────╮ │
│ │ objectId │ │ │
│ │ version │ 4 │ │
│ │ digest │ │ │
│ │ objectType │ ::first_package::Forge │ │
│ ╰────────────┴──────────────────────────────────────────────────────────────────────╯ │
│ ╭────────────┬──────────────────────────────────────────────────────────────────────╮ │
│ │ objectId │ │ │
│ │ version │ 4 │ │
│ │ digest │ │ │
│ │ objectType │ 0x0000..0002::coin::Coin │ │
│ ╰────────────┴──────────────────────────────────────────────────────────────────────╯ │
│ ╭────────────┬──────────────────────────────────────────────────────────────────────╮ │
│ │ objectId │ │ │
│ │ version │ 4 │ │
│ │ digest │ │ │
│ │ objectType │ ::first_package::Sword │ │
│ ╰────────────┴──────────────────────────────────────────────────────────────────────╯ │
│ ╭────────────┬──────────────────────────────────────────────────────────────────────╮ │
│ │ objectId │ │ │
│ │ version │ 3 │ │
│ │ digest │ │ │
│ │ objectType │ 0x0000..0002::package::UpgradeCap │ │
│ ╰────────────┴──────────────────────────────────────────────────────────────────────╯ │
╰───────────────────────────────────────────────────────────────────────────────────────╯
```
Congratulations! You have successfully published a package to the IOTA network and modified the blockchain state using a programmable transaction block.
---
## GraphQL for the IOTA RPC
This section explains some of the common concepts when working with GraphQL, such as altering behavior using HTTP headers, re-using query snippets with variables and fragments, consuming paginated queries, and understanding and working within the limits enforced by the service.
Jump to the following sections for more details:
- [Headers](#headers)
- [Variables](#variables)
- [Fragments](#fragments)
- [Pagination](#pagination)
- [Limits](#limits)
For more details on GraphQL fundamentals, see the introductory documentation from [GraphQL](https://graphql.org/learn/) and [GitHub](https://docs.github.com/en/graphql/guides/introduction-to-graphql).
## Headers
The service accepts the following optional headers:
- `x-iota-rpc-version` to specify which RPC version to use (currently only one version is supported),
- `x-iota-rpc-show-usage` returns the response with extra query complexity information.
By default, each request returns the service's version in the response header: `x-iota-rpc-version`.
```bash
curl -i -X POST https://graphql.testnet.iota.cafe \
--header 'x-iota-rpc-show-usage: true' \
--header 'Content-Type: application/json' \
--data '{
"query": "query { epoch { referenceGasPrice } }"
}'
```
The response for the previous request looks similar to the following:
```bash
HTTP/2 200
content-type: application/json
content-length: 159
x-iota-rpc-version: 2024.1.0
date: Tue, 30 Jan 2024 23:50:43 GMT
via: 1.1 google
alt-svc: h3=":443"; ma=2592000,h3-29=":443"; ma=2592000
{
"data": {
"epoch": {
"referenceGasPrice": "1000"
}
},
"extensions": {
"usage": {
"inputNodes": 2,
"outputNodes": 2,
"depth": 2,
"variables": 0,
"fragments": 0,
"queryPayload": 37
}
}
}
```
## Variables
Variables offer a way to introduce dynamic inputs to a re-usable/static query. Declare variables in the parameters to a `query` or `mutation`, using the `$` symbol and its type (in this example `Int`), which must be a `scalar`, `enum`, or `input` type. In the query body, refer to it by its name (prefixed with the `$` symbol).
If you declare a variable but don't use it or define it (supply a value) in the query, the query fails to execute.
To learn more, read the GraphQL documentation on [Variables](https://graphql.org/learn/queries/#variables).
In the following example, a variable supplies the ID of the epoch being queried.
```graphql
query ($epochID: Int) {
epoch(id: $epochID) {
referenceGasPrice
}
}
```
**Variables**:
```json
{
"epochID": 100
}
```
### In the IDE
When using the online IDE, supply variables as a JSON object to the query in the **Variables** pane at the bottom of the main editing window. You receive a warning if you supply a variable but don't declare it.
### In requests
When making a request to the GraphQL service (for example, using `curl`), pass the query and variables as two fields of a single JSON object:
```bash
curl -X POST https://graphql.testnet.iota.cafe \
--header 'Content-Type: application/json' \
--data '{
"query": "query ($epochID: Int) { epoch(id: $epochID) { referenceGasPrice } }",
"variables": { "epochID": 100 }
}'
```
## Fragments
Fragments are reusable units that you can include in queries as needed. To learn more, consult the official GraphQL [documentation](https://graphql.org/learn/queries/#fragments). The following example uses fragments to factor out a reusable snippet representing a Move value.
```graphql
query DynamicField {
object(
address: "0xb57fba584a700a5bcb40991e1b2e6bf68b0f3896d767a0da92e69de73de226ac"
) {
dynamicField(
name: {
type: "0x2::kiosk::Listing",
bcs: "NLArx1UJguOUYmXgNG8Pv8KbKXLjWtCi6i0Yeq1VhfwA",
}
) {
...DynamicFieldSelect
}
}
}
fragment DynamicFieldSelect on DynamicField {
name {
...MoveValueFields
}
value {
...DynamicFieldValueSelection
}
}
fragment DynamicFieldValueSelection on DynamicFieldValue {
__typename
... on MoveValue {
...MoveValueFields
}
... on MoveObject {
contents {
...MoveValueFields
}
}
}
fragment MoveValueFields on MoveValue {
type {
repr
}
data
bcs
}
```
## Pagination
GraphQL supports queries that fetch multiple kinds of data, potentially nested. For example, the following query retrieves the first 20 transaction blocks (along with the digest, the sender's address, the gas object used to pay for the transaction, the gas price, and the gas budget) after a specific transaction block at epoch `97`.
```graphql
query {
epoch(id: 97) {
transactionBlocks(first: 10) {
pageInfo {
hasNextPage
endCursor
}
nodes {
digest
sender {
address
}
effects {
gasEffects {
gasObject {
address
}
}
}
gasInput {
gasPrice
gasBudget
}
}
}
}
}
```
If there are too many transactions to return in a single response, the service applies a [limit](#limits) on the maximum page size for variable size responses (like the `transactionBlock` query) and you must fetch further results through [pagination](https://graphql.org/learn/pagination/).
### Connections
Fields that return a paginated response accept at least the following optional parameters:
- `first`, a limit on page size that is met by dropping excess results from the end.
- `after`, a cursor that bounds the results from below, exclusively.
- `last`, a limit on page size that is met by dropping excess results from the start.
- `before`, a cursor that bounds the results from above, exclusively.
They also return a type that conforms to the [GraphQL Cursor Connections Specification](https://relay.dev/graphql/connections.htm), meaning its name ends in `Connection`, and it contains at least the following fields:
- `pageInfo`, of type PageInfo, which indicates whether there are more pages before or after the page returned.
- `nodes`, the content of the paginated response, as a list of the type being paginated (`TransactionBlock` in the previous example).
- `edges`, similar to `nodes` but associating each node with its [cursor](#cursors).
### Cursors
Cursors are opaque identifiers for paginated results. The only valid source for a cursor parameter (like `after` and `before`) is a cursor field from a previous paginated response (like `PageInfo.startCursor`, `PageInfo.endCursor`, or `Edge.cursor`). The underlying format of the cursor is an implementation detail, and is not guaranteed to remain fixed across versions of the GraphQL service, so do not rely on it -- generating cursors out of thin air is not expected or supported.
Cursors are used to bound results from below (with `after`) and above (with `before`). In both cases, the bound is exclusive, meaning it does not include the result that the cursor points to in the bounded region.
#### Consistency
Cursors also guarantee **consistent** pagination. If the first paginated query reads the state of the network at checkpoint `X`, then a future call to fetch the next page of results using the cursors returned by the first query continues to read from the network at checkpoint `X`, even if data for future checkpoints is now available.
This property requires that cursors that are used together (for example when supplying an `after` and `before` bound) are fixed on the same checkpoint, otherwise the query produces an error.
#### Available range
The GraphQL service does not support consistent pagination for arbitrarily old cursors. A cursor can grow stale, if the checkpoint it is from is no longer in the **available range**. You can query the upper- and lower-bounds of that range as follows:
```graphql
{
availableRange {
first { sequenceNumber }
last { sequenceNumber }
}
}
```
The results are the first and last checkpoint for which pagination continues to work and produce a consistent result. At the time of writing the available range offers a 5- to 15-minute buffer period to finish pagination.
### Page limits
After results are bounded using cursors, a page size limit is applied using the `first` and `last` parameters. The service requires these parameters to be less than or equal to the max page size [limit](#limits), and if you provide neither, it selects a default. In addition to setting a limit, `first` and `last` control where excess elements are discarded from. For example, if there are `10` potential results -- `R0`, `R1`, ..., `R9` -- after cursor bounds have been applied, then
- a limit of `first: 3` would select `R0`, `R1`, `R2`, and
- a limit of `last: 3` would select `R7`, `R8`, `R9`.
:::info
It is an error to apply both a `first` and a `last` limit.
:::
### Examples
To see these principles put into practice, consult the examples for [paginating forwards](getting-started/graphql-rpc.mdx#paginating-checkpoints-forward-five-at-a-time) and [paginating backwards](getting-started/graphql-rpc.mdx#paginating-checkpoints-backwards-five-at-a-time) in the getting started guide.
## Limits
The GraphQL service for IOTA RPC is rate-limited on all available instances to keep network throughput optimized and to protect against excessive or abusive calls to the service.
### Rate limits
Queries are rate-limited at the number of attempts per minute to ensure high availability of the service to all users.
### Query limits
In addition to rate limits, queries are also validated against a number of rules on their complexity, such as the number of nodes, the depth of the query, or their payload size. Query the `serviceConfig` field to retrieve these limits. An example of how to query for some of the available limits follows:
```graphql
{
serviceConfig {
maxQueryDepth
maxQueryNodes
maxOutputNodes
maxDbQueryCost
defaultPageSize
maxPageSize
requestTimeoutMs
maxQueryPayloadSize
maxTypeArgumentDepth
maxTypeArgumentWidth
maxTypeNodes
maxMoveValueDepth
}
}
```
## Related links
- [GraphQL quick-start](getting-started/graphql-rpc.mdx): Querying IOTA RPC with GraphQL gets you started using GraphQL to query the IOTA RPC for on-chain data.
- [GraphQL migration](advanced/graphql-migration.mdx): Migrating to GraphQL guides you through migrating IOTA RPC projects from JSON-RPC to GraphQL.
- [GraphQL reference](../developer/references/iota-graphql.mdx): Auto-generated GraphQL reference for IOTA RPC.
---
## Access On-Chain Time
# Accessing On-Chain Time in IOTA
When you need to access network-based time for your transactions on IOTA, you have several options:
- **Near Real-Time Measurement**: Use the immutable reference of time provided by the [`Clock`](../../developer/references/framework/iota/clock.mdx) module in Move. This value updates with every network checkpoint.
- **Epoch Start Time**: Use the [`epoch_timestamp_ms`](../../developer/references/framework/iota/tx_context.mdx#iota_tx_context_epoch_timestamp_ms) function to capture the precise moment the current epoch started.
## Using the `iota::clock::Clock` Module
To access a prompt timestamp, you can pass a read-only reference of [`iota::clock::Clock`](../../developer/references/framework/iota/clock.mdx) as an entry function parameter in your transactions.
An instance of `Clock` is provided at the address `0x6`, and no new instances can be created.
Use the [`timestamp_ms`](../../developer/references/framework/iota/clock.mdx#iota_clock_timestamp_ms) function from the `iota::clock` module to extract a Unix timestamp in milliseconds.
```move file=/crates/iota-framework/packages/iota-framework/sources/clock.move#L29-L33
```
### Example: Emitting an Event with a Timestamp
The following example demonstrates an entry function that emits an event containing a timestamp from the `Clock`:
```move file=/examples/move/basics/sources/clock.move#L5-L15
```
To call the previous entry function, pass `0x6` as the address for the `Clock` parameter:
```shell
iota client call --package --module 'clock' --function 'access' --args '0x6'
```
:::note Clock
The `Clock` timestamp changes at the rate the network generates checkpoints, which is currently **every 0.2 to 0.25 seconds**.
:::
Successive calls to `iota::clock::timestamp_ms` within the same transaction will always produce the same result because transactions are considered to take effect instantly.
However, timestamps from `Clock` are monotonic across transactions that touch the same shared objects, meaning successive transactions see a greater or equal timestamp compared to their predecessors.
### Transaction Requirements
- **Consensus Requirement**: Any transaction that requires access to a `Clock` must go through consensus because the only available instance is a shared object.
- **Immutable Reference**: Transactions that use the clock must accept it as an **immutable reference** (`&Clock`), not as a mutable reference or value. This prevents contention, as transactions that access the `Clock` can only read it.
Validators will refuse to sign transactions that do not meet this requirement, and packages that include entry functions accepting a `Clock` or `&mut Clock` will fail to publish.
### Testing `Clock`-Dependent Code
The following functions allow you to test `Clock`-dependent code by manually creating a `Clock` object and manipulating its timestamp. This is possible only in test code:
```move file=/crates/iota-framework/packages/iota-framework/sources/clock.move#L65-L93
```
Here's a basic test that creates a `Clock`, increments it, and then checks its value:
```move file=/crates/iota-framework/packages/iota-framework/tests/clock_tests.move#L6-L22
```
## Using Epoch Timestamps
If you don't need a near real-time measurement,
you can use the [`epoch_timestamp_ms`](../../developer/references/framework/iota/tx_context.mdx#iota_tx_context_epoch_timestamp_ms) function
from the [`iota::tx_context`](../../developer/references/framework/iota/tx_context.mdx) module to access the timestamp for the start of the
current epoch. This function works for all transactions, including those that do not go through consensus:
```move file=/crates/iota-framework/packages/iota-framework/sources/tx_context.move#L54-L56
```
The function returns the point in time when the current epoch started, as a Unix timestamp in milliseconds (`u64`).
This value changes roughly **once every 24 hours** when the epoch changes.
### Testing Epoch-Sensitive Code
Tests based on [`iota::test_scenario`] can use `later_epoch` to exercise time-sensitive code that uses `epoch_timestamp_ms`:
```move file=/crates/iota-framework/packages/iota-framework/sources/test/test_scenario.move#L141-L148
```
The `later_epoch` function behaves like `iota::test_scenario::next_epoch` (finishes the current transaction and epoch in the test scenario)
but also increments the timestamp by `delta_ms` milliseconds to simulate the passage of time.
---
## Creating Coins and Tokens
Coins and tokens in IOTA are similar concepts, often used interchangeably,
but there are subtle differences in their implementation.
To understand these differences, refer to the standard documentation for [Closed-Loop Token](../../standards/closed-loop-token.mdx) and [Coin](../../standards/coin.mdx).
## Publishing a Coin
Publishing a coin on IOTA is almost as straightforward as publishing a new type.
The key difference is the requirement of a [one-time witness](../move-overview/one-time-witness.mdx) when creating a coin.
```move file=/examples/move/coin/sources/my_coin.move
```
The [`Coin`](../../references/framework/iota/coin.mdx) is a generic coin implementation in IOTA.
By accessing the [`TreasuryCap`](../../references/framework/iota/coin.mdx#struct-treasurycap),
you gain control over minting and burning coins.
You can send further transactions directly to `iota::coin::Coin` using the `TreasuryCap` object for authorization.
## Extending the Coin Module
To extend the coin module, add a `mint` function.
This function utilizes the [`mint`](../../references/framework/iota/coin.mdx#iota_coin_mint) method from the `Coin` module
to create a coin and transfer it to a specified address.
## IOTA CLI
### Minting Coins
After publishing the coin module to the IOTA network,
you can mint coins and send them to an address using the `iota client call` command.
For more details on the command-line interface, see [IOTA CLI](../../references/cli.mdx).
```shell
iota client call --function mint --module mycoin --package --args
```
Upon successful execution, the console displays output including a **Balance Changes** section:
```shell
...
Owner: Account Address ( )
CoinType: ::mycoin::MYCOIN
Amount:
...
```
## Implementing a Deny List
If you need to restrict specific addresses from accessing your coin, consider implementing a [`DenyList`](./regulated.mdx#managing-the-deny-list).
## Creating a Regulated Coin
To deny specific addresses from holding your coin,
use the [`create_regulated_currency`](../../references/framework/iota/coin.mdx#iota_coin_create_regulated_currency_v1) function instead of [`create_currency`](../../references/framework/iota/coin.mdx#iota_coin_create_currency).
Internally, `create_regulated_currency` calls `create_currency` to create the coin
and also produces a [`DenyCap`](../../references/framework/iota/coin.mdx#struct-denycapv1) object.
This object allows you to manage the deny list in a `DenyList` object.
The process is similar to the previous example but includes transferring the `DenyCap` object to the module publisher.
## Creating Tokens
Tokens reuse the [`TreasuryCap`](../../references/framework/iota/coin.mdx#struct-denycapv1) defined in the `iota::coin` module
and follow the same initialization process.
The `coin::create_currency` function ensures the uniqueness of the `TreasuryCap` and enforces the creation of a `CoinMetadata` object.
You can mint and burn tokens using functions similar to those for coins, both requiring the `TreasuryCap`:
- [`token::mint`](../../references/framework/iota/token.mdx#iota_token_mint) — Mint a token.
- [`token::burn`](../../references/framework/iota/token.mdx#iota_token_burn) — Burn a token.
For complete details on working with tokens, refer to the [Closed-Loop Token](../../standards/closed-loop-token.mdx) standard.
## Additional Examples
Explore these topics for practical examples of coin and token creation:
- [Migrate to CoinManager](migrate-to-coin-manager.mdx): Learn about IOTA's unique [`CoinManager`](../../references/framework/iota/coin_manager.mdx), and how it simplify managing your [Coins](../../references/framework/iota/coin.mdx).
- [Regulated Coin and Deny List](regulated.mdx): Learn how to create a regulated coin and manage the deny list.
- [Loyalty Token](loyalty.mdx): Discover how to create a token to reward user loyalty.
- [In-Game Token](in-game-token.mdx): Understand how to create tokens usable within a mobile game.
---
## Creating In-Game Currency
You can use the IOTA [Closed-Loop Token](../../standards/closed-loop-token.mdx) standard
to develop in-game currencies like gems or diamonds commonly found in mobile games.
These tokens can be awarded to players for their actions or made available for purchase.
While minted on the IOTA network, players can only use these tokens within the game's ecosystem.
Typically, such tokens are non-transferable and are minted in predefined quantities to maintain scarcity and balance within the game.
## Setting Up the GEM Currency
In the following example creates an in-game currency called `GEM`, representing a specific amount of IOTA.
Players can purchase fungible `GEMs` using IOTA, which they can then spend within the game.
### Example Overview
The IOTA repository includes a [basic example of creating an in-game currency]https://github.com/iotaledger/iota/tree/develop/examples/move/token.
The Move modules responsible for establishing the game's economy are located in the [`gems.move`](https://github.com/iotaledger/iota/blob/develop/examples/move/token/sources/gems.move) source file.
### The `examples::sword` Module
The [`examples::sword` module](https://github.com/iotaledger/iota/blob/develop/examples/move/token/sources/gems.move#L8) defines an in-game object, a `sword`,
which holds value within the game.
This module assigns a `GEM` value to the sword and includes the logic for trading `GEMs` to acquire a sword.
```move file=/examples/move/token/sources/gems.move#L8-L32
```
### The `examples::gem` Module
The [`examples::gem` module](https://github.com/iotaledger/iota/blob/develop/examples/move/token/sources/gems.move#L36) is responsible
for creating the `GEM` in-game currency.
Players spend IOTA to purchase `GEMs`, which they can trade for swords or other in-game items.
The module defines three tiers of `GEM` packages—small, medium, and large—each representing different in-game values.
Constants within the module specify both the value and the quantity of GEMs in each package.
```move file=/examples/move/token/sources/gems.move#L73-L69
```
#### Initializing the GEM Currency
The `init` function in the module uses `coin::create_currency` to create the GEM currency. This function runs only once upon module publication. It sets the policies for the in-game currency, freezes the coin's metadata, and transfers the policy capability to the package publisher.
```move file=/examples/move/token/sources/gems.move#L76-L100
```
#### Purchasing GEMs
The module handles the purchase of `GEMs` through the `buy_gems` function.
```move file=/examples/move/token/sources/gems.move#L104-L125
```
## Viewing the Complete Module Code
For a comprehensive understanding, you can view the complete code of the `gems.move` module below.
Click to expand the full module code
```move file=/examples/move/token/sources/gems.move
```
---
## Creating Loyalty Token
You can use the IOTA [Closed-Loop Token](../../standards/closed-loop-token.mdx) standard
to create [tokens](../../references/framework/iota/token.mdx) that are valid only within a specific service.
For example, an airline might grant tokens to frequent flyers that they can use to purchase tickets or upgrades.
In this guide, you'll learn how to create a loyalty token that users can use to make purchases in a digital gift shop.
## Overview
The following example demonstrates how to create a loyalty token using the Closed-Loop Token standard.
As the administrator, you would send `LOYALTY` tokens to your service's users as a reward for their loyalty.
The example includes a `GiftShop` where holders can spend `LOYALTY` tokens to buy `Gift` items.
## Module: `examples::loyalty`
The `examples::loyalty` module, found in the `loyalty.move` source file, contains the code to create the loyalty token.
The module defines a [one-time witness (OTW)](../move-overview/one-time-witness.mdx)
that creates the coin named `LOYALTY`.
This coin possesses only the `drop` ability and has no fields.
These characteristics ensure the `LOYALTY` type has a single instance.
```move file=/examples/move/token/sources/loyalty.move#L22-L23
```
### Initialization Function
The module's [`init` function](../move-overview/init.mdx) uses the `LOYALTY` OTW to create the token.
Remember that all `init` functions run only once at the package publish event.
The initializer function calls [`create_currency`](../../references/framework/iota/coin.mdx#iota_coin_create_currency)
using the `LOYALTY` type defined earlier.
It also sets up a policy by sending both the [policy capability](../../references/framework/iota/token.mdx#struct-tokenpolicycap)
and the [treasury capability](../../references/framework/iota/coin.mdx#struct-treasurycap) to the address associated with the publish event.
The holder of these transferable capabilities can mint new `LOYALTY` tokens and modify their policies.
```move file=/examples/move/token/sources/loyalty.move#L37-L63
```
### Minting Function: `reward_user`
The `reward_user` function allows the holder of the `TreasuryCap`
to mint new loyalty tokens and send them to specified addresses.
It uses the [`token::mint`](../../references/framework/iota/token.mdx#iota_token_mint) function
to create the tokens and [`token::transfer`](../../references/framework/iota/token.mdx#iota_token_transfer) to deliver them to the intended recipients.
```move file=/examples/move/token/sources/loyalty.move#L71-L81
```
#### Redeeming Tokens: `buy_a_gift`
Finally, the module includes a `buy_a_gift` function to handle the redemption of `LOYALTY` tokens for `Gift` items.
This function ensures that the gift's price matches the number of loyalty tokens spent.
It uses the [`token::spend`](../../references/framework/iota/token.mdx#iota_token_spend) function to manage the treasury bookkeeping.
```move file=/examples/move/token/sources/loyalty.move#L85-L100
```
## Full Source Code
For a complete view of the module, you can review the full source code below.
Click to view the complete source code
```move file=/examples/move/token/sources/loyalty.move
```
---
## Migrating a Coin to Coin Manager
The previous articles in this section showcase how to create a [`Coin`](../../references/framework/iota/coin.mdx) object with different constructors. Namely, [`create_currency`](create-coin.mdx) and [`create_regulated_currency`](regulated.mdx).
This article will show how an existing `Coin` object can be migrated to [`CoinManager`](../../references/framework/iota/coin_manager.mdx). By doing so, the `Coin` deployer and its end-users will gain [extra-functionalities](../../standards/coin-manager.mdx). Generally, we recommend initially creating a `Coin` via `CoinManager` to avoid the need for migration later on. However, if you have an existing `Coin` and wish to migrate it to `CoinManager`, this article will guide you through the process.
### Pre-requisites
- [Installed IOTA CLI](../../getting-started/install-iota.mdx)
- [Created an address and received Testnet funds](../../getting-started/get-coins.mdx)
### 1. Create a Simple Coin
First, we will create a simple coin to be migrated [`CoinManager`](../../references/framework/iota/coin_manager.mdx).
1. Create a new empty package called `my_coin`:
``` bash
iota move new my_coin
```
2. In `my_coin.move`, paste this simple move `Coin` module:
```move
module my_coin::my_coin {
use iota::coin::{Self, TreasuryCap};
/// The type identifier of coin. The coin will have a type
/// tag of kind: `Coin`
/// Make sure that the name of the type matches the module's name.
public struct MY_COIN has drop {}
/// Module initializer is called once on module publish. A treasury
/// cap is sent to the publisher, who then controls minting and burning
fun init(witness: MY_COIN, ctx: &mut TxContext) {
let (treasury, metadata) = coin::create_currency(witness, 6, b"MYCOIN", b"", b"", option::none(), ctx);
transfer::public_freeze_object(metadata);
transfer::public_transfer(treasury, tx_context::sender(ctx))
}
public fun mint(
treasury_cap: &mut TreasuryCap,
amount: u64,
recipient: address,
ctx: &mut TxContext,
) {
let coin = coin::mint(treasury_cap, amount, ctx);
transfer::public_transfer(coin, recipient)
}
}
```
3. Deploy the `my_coin` package by running the following command:
```bash
iota client publish --gas-budget 100000000
```
4. The console will respond with the transaction effects. You should pay attention to the created objects to retrieve the object IDs:
Transaction Output
```bash
╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ Object Changes │
├───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Created Objects: │
│ ┌── │
│ │ ObjectID: │
│ │ Sender: │
│ │ Owner: Account Address ( ) │
│ │ ObjectType: 0x2::package::UpgradeCap │
│ │ Version: │
│ │ Digest: │
│ └── │
│ ┌── │
│ │ ObjectID: │
│ │ Sender: │
│ │ Owner: Immutable │
│ │ ObjectType: 0x2::coin::CoinMetadata<::my_coin::MY_COIN> │
│ │ Version: │
│ │ Digest: │
│ └── │
│ ┌── │
│ │ ObjectID: │
│ │ Sender: │
│ │ Owner: Account Address ( ) │
│ │ ObjectType: 0x2::coin::TreasuryCap<::my_coin::MY_COIN> │
│ │ Version: │
│ │ Digest: │
│ └── │
│ Mutated Objects: │
│ ┌── │
│ │ ObjectID: │
│ │ Sender: │
│ │ Owner: Account Address ( ) │
│ │ ObjectType: 0x2::coin::Coin<0x2::iota::IOTA> │
│ │ Version: 11155 │
│ │ Digest: │
│ └── │
│ Published Objects: │
│ ┌── │
│ │ PackageID: │
│ │ Version: 1 │
│ │ Digest: │
│ │ Modules: my_coin │
│ └── │
╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
```
## 2. Create a Coin Manager
1. In the root folder, create a new package `my_coin_manager`:
```bash
iota move new my_coin_manager
```
2. In the created `my_coin_manager.move`, paste the following module:
```move
module my_coin_manager::my_coin_manager{
use iota::coin_manager;
use iota::coin::{CoinMetadata, TreasuryCap};
/// Phantom parameter T can only be initialized in the `create_guardian`
/// function. But the types passed here must have `drop`.
public struct Guardian has key, store {
id: UID
}
/// This type is the witness resource and is intended to be used only once.
public struct MY_COIN_MANAGER has drop {}
/// The first argument of this function is an actual instance of the
/// type T with `drop` ability. It is dropped as soon as received.
public fun create_guardian(
_witness: T, ctx: &mut TxContext
): Guardian {
Guardian { id: object::new(ctx) }
}
/// Module initializer is the best way to ensure that the
/// code is called only once. With `Witness` pattern it is
/// often the best practice.
fun init(witness: MY_COIN_MANAGER, ctx: &mut TxContext) {
transfer::transfer(
create_guardian(witness, ctx),
tx_context::sender(ctx)
)
}
#[allow(lint(self_transfer, share_owned))]
public fun migrate_to_manager (otw:Guardian ,cap: TreasuryCap, meta: &CoinMetadata, ctx: &mut TxContext) {
transfer::public_freeze_object(otw);
let (cm_treasury_cap, manager) = coin_manager::new_with_immutable_metadata(cap, meta, ctx);
// Transfer the `CoinManagerTreasuryCap` to the creator of the `Coin`.
transfer::public_transfer(cm_treasury_cap, ctx.sender());
// Publicly share the `CoinManager` object for convenient usage by anyone interested.
transfer::public_share_object(manager);
}
```
Let's go quickly over it before publishing:
What you want to achieve is creating a single instance of `CoinManager`. The most straightforward way to do it is in [`init()`](../move-overview/init.mdx), which is assured to be run only once.
If you were creating a `CoinManager` from scratch, that would be relatively simple, as the init function would look like this:
```move
fun init(witness: MY_COIN_MANAGER, ctx: &mut TxContext) {
// Create a `Coin` type and have it managed.
let (cm_treasury_cap, cm_meta_cap, manager) = coin_manager::create(
witness,
0,
b"MYCOIN",
b"My Coin",
b"There are only 100, never any more.",
option::none(),
ctx,
);
// Transfer the `CoinTreasuryCap` to the creator of the `Coin`.
transfer::public_transfer(coin_treasury_cap, ctx.sender());
// Transfer the `CoinMetadataCap` to the creator of the `Coin`.
transfer::public_transfer(coin_meta_cap, ctx.sender());
// Publicly share the `CoinManager` object for convenient usage by anyone interested.
transfer::public_share_object(manager);
transfer::public_share_object(manager);
}
```
However, since you are migrating from a `Coin`, you will use another constructor for `CoinManager`: [`CoinManager::new_with_immutable_metadata(cap,meta,ctx)`](../../references/framework/iota/coin_manager.mdx#iota_coin_manager_new_with_immutable_metadata) if the metadata is already frozen, and [`CoinManager::new(cap,meta,ctx)`](../../references/framework/iota/coin_manager.mdx#iota_coin_manager_new) if the metadata is mutable.
In that case, `init` would have to take two extra parameters: the [`Coin`'s `CoinMetadata`](../../references/framework/iota/coin.mdx#struct-coinmetadata) object and the [`TreasuryCap`](../../references/framework/iota/coin.mdx#struct-treasurycap) object. IOTA's Move only allows `TxContext` and an optional Witness. There is no means to pass in the extra argument.
You can use the [`One Time Witness Pattern`](../../iota-101/move-overview/one-time-witness.mdx) to resolve this.
You can use the `init` function to ensure that only one instance of `Guardian` is created. After that, you can pass Guardian to `migrate_to_coin_manager` and freeze it to ensure the call succeeds only once.
Now, you should publish the `CoinManager`:
```bash
iota client publish --gas-budget 100000000
```
If you check the console, you will see the created objects:
Transaction Output
```bash
╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ Object Changes │
├─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Created Objects: │
│ ┌── │
│ │ ObjectID: │
│ │ Sender: │
│ │ Owner: Account Address ( ) │
│ │ ObjectType: 0x2::package::UpgradeCap │
│ │ Version: │
│ │ Digest: │
│ └── │
│ ┌── │
│ │ ObjectID: │
│ │ Sender: │
│ │ Owner: Account Address ( ) │
│ │ ObjectType: ::my_coin_manager::Guardian<::my_coin_manager::my_coin_manager> │
│ │ Version: │
│ │ Digest: │
│ └── │
│ Mutated Objects: │
│ ┌── │
│ │ ObjectID: │
│ │ Sender: │
│ │ Owner: Account Address ( ) │
│ │ ObjectType: 0x2::coin::Coin<0x2::iota::IOTA> │
│ │ Version: │
│ │ Digest: │
│ └── │
│ Published Objects: │
│ ┌── │
│ │ PackageID: │
│ │ Version: 1 │
│ │ Digest: │
│ │ Modules: my_coin_manager │
│ └── │
╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
```
When publishing this module, you will get the `Guardian` object's ID. You should then pass this object to the `migrate_to_manager` function alongside the `Coin`'s `TreasuryCap` and `CoinMetadata` objects.
```bash
iota client call \
--package \
--module my_coin_manager \
--function migrate_to_manager \
--gas-budget 100000000 \
--type-args \
::my_coin::MY_COIN \
::my_coin_manager::MY_COIN_MANAGER \
--args \
\
\
```
The first time you run the command, the output should look similar to the following:
Transaction Output
```bash
╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ Object Changes │
├─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Created Objects: │
│ ┌── │
│ │ ObjectID: │
│ │ Sender: │
│ │ Owner: Account Address ( ) │
│ │ ObjectType: 0x2::coin_manager::CoinManagerTreasuryCap │
│ │ Version: │
│ │ Digest: │
│ └── │
│ ┌── │
│ │ ObjectID: │
│ │ Sender: │
│ │ Owner: Shared │
│ │ ObjectType: 0x2::coin_manager::CoinManager │
│ │ Version: │
│ │ Digest: │
│ └── │
│ Mutated Objects: │
│ ┌── │
│ │ ObjectID: │
│ │ Sender: │
│ │ Owner: Account Address ( ) │
│ │ ObjectType: 0x2::coin::Coin<0x2::iota::IOTA> │
│ │ Version: │
│ │ Digest: │
│ └── │
│ ┌── │
│ │ ObjectID: