From 68ed3d6af7bd1ad4737c59658f71a9503651aaff Mon Sep 17 00:00:00 2001 From: Philipp Gackstatter Date: Tue, 6 Aug 2024 12:22:44 +0200 Subject: [PATCH 01/16] fix(docs): Typos in Standards section --- docs/content/developer/standards/closed-loop-token.mdx | 4 ++-- .../developer/standards/closed-loop-token/action-request.mdx | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/content/developer/standards/closed-loop-token.mdx b/docs/content/developer/standards/closed-loop-token.mdx index d8a36fc16fe..cad0586b726 100644 --- a/docs/content/developer/standards/closed-loop-token.mdx +++ b/docs/content/developer/standards/closed-loop-token.mdx @@ -2,13 +2,13 @@ title: Closed-Loop Token --- -Using the Closed-Loop Token standard, you can limit the applications that can use the token and set up custom policies for transfers, spends, and conversions. The [`iota::token` module](https://github.com/iotaledger/iota/blob/main/crates/iota-framework/docs/iota-framework/token.md) in the IOTA framework defines the standard. +Using the Closed-Loop Token standard, you can limit the applications that can use the token and set up custom policies for transfers, spends, and conversions. The [`iota::token` module](../../references/framework/iota-framework/token.mdx) in the IOTA framework defines the standard. ## Background and use cases The [Coin standard](coin.mdx) on IOTA is an example of an open-loop system - coins are free-flowing, [wrappable](../iota-101/objects/object-ownership/wrapped.mdx), [freely transferable](../iota-101/objects/transfers/custom-rules.mdx#the-store-ability-and-transfer-rules) and you can store them in any application. The best real world analogy would be cash - hardly regulated and can be freely used and passed. -Some applications, however, require constraining the scope of the token to a specific purpose. For example, some applications might need a token that you can only use for a specific service, or that an authorized account can only use, or a token that you can block certain accounts from using. A real-world analogy would be a bank account - regulated, bank-controlled, and compliant with certain rules and policies. +Some applications, however, require constraining the scope of the token to a specific purpose. For example, some applications might need a token that you can only use for a specific service, or that only an authorized account can use, or a token that you can block certain accounts from using. A real-world analogy would be a bank account - regulated, bank-controlled, and compliant with certain rules and policies. ## Difference with Coin diff --git a/docs/content/developer/standards/closed-loop-token/action-request.mdx b/docs/content/developer/standards/closed-loop-token/action-request.mdx index 9d7d2498313..4345a589525 100644 --- a/docs/content/developer/standards/closed-loop-token/action-request.mdx +++ b/docs/content/developer/standards/closed-loop-token/action-request.mdx @@ -146,7 +146,7 @@ tx.moveCall({ ### Confirming with TokenPolicyCap -Use `TokenPolicyCap` to confirm action requests. A convenient approach when the `TreasuryCap` is wrapped in another object, and `TokenPolicy` does not allow certain action or has rules that make the default way of confirming impossible. +Use `TokenPolicyCap` to confirm action requests. A convenient approach when the `TreasuryCap` is wrapped in another object, and `TokenPolicy` does not allow a certain action or has rules that make the default way of confirming impossible. :::info @@ -192,7 +192,7 @@ tx.moveCall({ ## Approving actions -`ActionRequest`s can collect approvals - witness stamps from applications or rules. They carry the confirmation that a certain module or a rule has approved the action. This mechanic allows gating actions behind certain requirements. +`ActionRequest`s can collect approvals - witness stamps from applications or rules. They carry the confirmation that a certain module or a rule has approved the action. This mechanism allows gating actions behind certain requirements. The signature for the `token::add_approval` function is: From a1058e20e41e817a941626736e7045ed68b4b8e7 Mon Sep 17 00:00:00 2001 From: Philipp Gackstatter Date: Tue, 6 Aug 2024 15:01:33 +0200 Subject: [PATCH 02/16] fix(docs): Fix typos and broken links in coin docs --- docs/content/developer/standards/coin.mdx | 6 +++--- docs/content/developer/standards/standards.mdx | 13 +++++++------ 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/docs/content/developer/standards/coin.mdx b/docs/content/developer/standards/coin.mdx index 5276c3597dd..3b72d68a6ab 100644 --- a/docs/content/developer/standards/coin.mdx +++ b/docs/content/developer/standards/coin.mdx @@ -191,7 +191,7 @@ let builder = ptb.finish(); - `SequenceNumber` is the `initial_shared_version` of the `DenyList` singleton. - `deny_cap` is the `ObjectRef` (`(ObjectID, SequenceNumber, ObjectDigest)`) of the `DenyCap` the publisher has received. - `otw_type` is the `TypeTag` created from `::regulated_coin::REGULATED_COIN` type. -- `cmd.address()` returns the address to ban as a `IOTAAddress`. +- `cmd.address()` returns the address to ban as an `IotaAddress`. @@ -266,6 +266,6 @@ Check out the following content for more information about coins and tokens on I - [Create a Coin](../iota-101/create-coin/create-coin.mdx): Guide for creating coins and regulated coins in your smart contracts. - [Closed-Loop Token Standard](closed-loop-token.mdx): Details the Token standard on IOTA. -- [`coin` module rustdoc documentation](https://github.com/iotaledger/iota/blob/main/crates/iota-framework/docs/iota-framework/coin.md): Automated documentation output for the IOTA framework `coin` module. -- [`token` module rustdoc documentation](https://github.com/iotaledger/iota/blob/main/crates/iota-framework/docs/iota-framework/token.md): Automated documentation output for the IOTA framework `token` module. +- [`coin` module documentation](../../references/framework/iota-framework/coin.mdx): Automated documentation output for the IOTA framework `coin` module. +- [`token` module documentation](../../references/framework/iota-framework/token.mdx): Automated documentation output for the IOTA framework `token` module. - [Tokenomics](../../about-iota/tokenomics.mdx): Discover the IOTA ecosystem and where IOTA coins fit within it. \ No newline at end of file diff --git a/docs/content/developer/standards/standards.mdx b/docs/content/developer/standards/standards.mdx index 930a8712921..65482c56d66 100644 --- a/docs/content/developer/standards/standards.mdx +++ b/docs/content/developer/standards/standards.mdx @@ -6,10 +6,11 @@ sidebar_label: Overview Standards on the IOTA blockchain are features, frameworks, or apps that you can extend or customize. - - - - - - + + + + + + + From c8b5ea76a631c2c2dba4587aaebf2d6250da00ea Mon Sep 17 00:00:00 2001 From: Philipp Gackstatter Date: Wed, 7 Aug 2024 12:06:00 +0200 Subject: [PATCH 03/16] fix(docs): Typos in CoinManager doc --- .../developer/standards/coin-manager.mdx | 47 +++++++++---------- 1 file changed, 23 insertions(+), 24 deletions(-) diff --git a/docs/content/developer/standards/coin-manager.mdx b/docs/content/developer/standards/coin-manager.mdx index 88fdf2f3041..1f99ddc5618 100644 --- a/docs/content/developer/standards/coin-manager.mdx +++ b/docs/content/developer/standards/coin-manager.mdx @@ -21,15 +21,15 @@ By having your `Coin` managed by a `CoinManager`, you gain the following functio - Both management caps can transparently be renounced through the `CoinManager` so that everyone on-chain can know that the supply and metadata are immutable, Offering end-users clarity and assurance. - A `CoinManagerTreasuryCap`-owned object will allow you to set a maximum supply for a coin. This will ensure that once set (a one-time, irrevocable action), there will never be any more tokens minted as the provided maximum supply. This offers assurances to the end-user about the asset they are interested in. - A custom additional Metadata object can be provided, allowing coins to have more data than just the standard fields provided by the default `Metadata` object. The existing metadata object will stay the same and remain fully compatible. -- The total supply of a given `Coin` type, the maximum supply, and the metadata can be transparently queried through the `CoinManager` by anyone interested, not just the `TreauryCap` owner. +- The total supply of a given `Coin` type, the maximum supply, and the metadata can be transparently queried through the `CoinManager` by anyone interested, not just the `TreasuryCap` owner. -With a `CoinManager` in place, you can offer assurances to whoever uses your `Coin` that can not be offered with just a regular `Coin` and `TreasuryCap`. We recommend every new coin utilize the `CoinManager.` Any existing coin can be managed by a `CoinManager` as long as the `TreasuryCap` object for that `Coin` is still in possession. +With a `CoinManager` in place, you can offer assurances to whoever uses your `Coin` that can not be offered with just a regular `Coin` and `TreasuryCap`. We recommend every new coin utilize the `CoinManager`. Any existing coin can be managed by a `CoinManager` as long as the `TreasuryCap` object for that `Coin` is still in possession. -## How To Manage A `Coin` With A `CoinManager` +## How To Manage a `Coin` With a `CoinManager` ### New `Coin` Assets -When you are starting a new `Coin` type and wish to use the `CoinManager` you can use the `CoinManager` directly to create this `Coin`. You will receive back the `CoinManagerTreasuryCap` and a `CoinManagerMetadataCap` to perform any follow-up management actions: +When you are creating a new `Coin` type and wish to use the `CoinManager` you can use the `CoinManager` directly to create this `Coin`. You will receive back the `CoinManagerTreasuryCap` and a `CoinManagerMetadataCap` to perform any follow-up management actions: ```move module example::exclusive_coin { @@ -50,13 +50,13 @@ module example::exclusive_coin { ctx ); - // Returning a new `CoinManagerTreasuryCap` to the creator of the `Coin` + // Transfer the `CoinManagerTreasuryCap` to the creator of the `Coin`. transfer::public_transfer(cm_treasury_cap, ctx.sender()); - // Returning a new `CoinManagerMetadataCap` to the creator of the `Coin` + // Transfer the `CoinManagerMetadataCap` to the creator of the `Coin`. transfer::public_transfer(cm_meta_cap, ctx.sender()); - // Publicly sharing the `CoinManager` object for convenient usage by anyone interested + // Publicly share the `CoinManager` object for convenient usage by anyone interested. transfer::public_share_object(manager); } } @@ -73,10 +73,10 @@ If you already froze the `Metadata` object you can only migrate to a `CoinManage ```move let (cm_treasury_cap, mut manager) = coin_manager::new_with_immutable_metadata(cap, &meta, ctx); -// Returning a new `CoinManagerTreasuryCap` to the creator of the `Coin` +// Transfer the `CoinManagerTreasuryCap` to the creator of the `Coin`. transfer::public_transfer(cm_treasury_cap, ctx.sender()); -// Publicly sharing the `CoinManager` object for convenient usage by anyone interested +// Publicly share the `CoinManager` object for convenient usage by anyone interested. transfer::public_share_object(manager); ``` #### With mutable metadata @@ -86,13 +86,13 @@ If the metadata object is still owned, you can take advantage of the full functi ```move let (cm_treasury_cap, cm_meta_cap, mut manager) = coin_manager::new(cap, meta, ctx); -// Returning a new `CoinManagerTreasuryCap` to the creator of the `Coin` +// Transfer the `CoinManagerTreasuryCap` to the creator of the `Coin`. transfer::public_transfer(cm_treasury_cap, ctx.sender()); -// Returning a new `CoinManagerMetadataCap` to the creator of the `Coin` +// Transfer the `CoinManagerMetadataCap` to the creator of the `Coin`. transfer::public_transfer(cm_meta_cap, ctx.sender()); -// Publicly sharing the `CoinManager` object for convenient usage by anyone interested +// Publicly share the `CoinManager` object for convenient usage by anyone interested. transfer::public_share_object(manager); ``` @@ -103,10 +103,10 @@ Once the `CoinManager` has been created and publicly shared you can make use of ### Retrieving metadata ```move -/// Get the decimals for a Coin managed by this manager, without needing the Metadata object +/// Get the decimals for the `Coin` of this manager, without needing the Metadata object. let decimals = manager.decimals(); -/// See if the Metadata is immutable or if it can still be changed later: +/// See if the Metadata is immutable or if it can still be changed later. let immutabe = manager.metadata_is_immutable(); ``` @@ -118,17 +118,17 @@ let max_supply = manager.maximum_supply(); let remaining_supply = manager.available_supply(); let has_maximum_supply = manager.has_maximum_supply(); let supply_reference = manager.supply_immut(); -let immutabe = manager.supply_is_immutable(); +let supply_is_immutable = manager.supply_is_immutable(); ``` ### Minting ```move -/// Minting more coins, if allowed +/// Mint more coins, if allowed. let coin = coin_manager_treasury_cap.mint(&mut manager, 100, ctx); ``` -Next to minting the same functionality is available that usually is available on the `TreasuryCap` like `burn`, `mint_balance`, and `mint_and_transfer`. +Next to minting, the same functionality is available that usually is available on the `TreasuryCap` like `burn`, `mint_balance` and `mint_and_transfer`. ### Updating Metadata @@ -143,10 +143,10 @@ coin_manager_metadata_cap.update_symbol(&mut manager, "NEW"); By renouncing ownership (handing in your cap(s)), you provide assurances for your `Coin` type to its users. Users can check if a `Coin` type has an immutable supply or metadata on-chain. ```move -/// Turns the supply immutable, no more minting or max. supply changes +/// Turns the supply immutable. No more minting or maximum supply changes. coin_manager_treasury_cap.renounce_ownership(&mut manager); -/// Turns the metadata immutable +/// Turns the metadata immutable. coin_manager_metadata_cap.renounce_ownership(&mut manager); ``` @@ -169,15 +169,14 @@ let version = wrapper.additional_metadata().version; If you wish to update or replace your custom Metadata object with a new one (of the same type or another), you can do so using the `replace_additional_metadata` function, which returns the old Metadata object: ```move - public struct NewCustomMetadata has store { - website: Url, - is_amazing: bool + website: Url, + is_amazing: bool } let new_meta = NewCustomMetadata { - website: url::new_unsafe(string(b"https://iota.org")), - is_amazing: true + website: url::new_unsafe(string(b"https://iota.org")), + is_amazing: true }; let oldmeta = metacap.replace_additional_metadata(&mut wrapper, new_meta); From 74c413a1569baf7756ec8f19a3a17f103662cdba Mon Sep 17 00:00:00 2001 From: Philipp Gackstatter Date: Thu, 8 Aug 2024 10:50:31 +0200 Subject: [PATCH 04/16] feat(docs): Add missing PTBs to kiosk docs --- docs/content/developer/standards/kiosk.mdx | 105 ++++++++++++++++----- 1 file changed, 79 insertions(+), 26 deletions(-) diff --git a/docs/content/developer/standards/kiosk.mdx b/docs/content/developer/standards/kiosk.mdx index bb79df2e85b..130af1b33b6 100644 --- a/docs/content/developer/standards/kiosk.mdx +++ b/docs/content/developer/standards/kiosk.mdx @@ -19,7 +19,7 @@ See the [Kiosk SDK documentation](../../references/ts-sdk/kiosk/index.mdx) for e ## IOTA Kiosk owners -Anyone can create a IOTA Kiosk. Ownership of a kiosk is determined by the owner of the `KioskOwnerCap`, a special object that grants full access to a single kiosk. As the owner, you can sell any asset with a type (T) that has a shared `TransferPolicy` available, or you can use a kiosk to store assets even without a shared policy. You can’t sell or transfer any assets from your kiosk that do not have an associated transfer policy available. +Anyone can create an IOTA Kiosk. Ownership of a kiosk is determined by the owner of the `KioskOwnerCap`, a special object that grants full access to a single kiosk. As the owner, you can sell any asset with a type (T) that has a shared `TransferPolicy` available, or you can use a kiosk to store assets even without a shared policy. You can’t sell or transfer any assets from your kiosk that do not have an associated transfer policy available. To sell an item, if there is an existing transfer policy for the type (T), you just add your assets to your kiosk and then list them. You specify an offer amount when you list an item. Anyone can then purchase the item for the amount of IOTA specified in the listing. The associated transfer policy determines what the buyer can do with the purchased asset. @@ -35,7 +35,7 @@ A Kiosk owner can: A buyer is a party that purchases (or - more generally - receives) items from Kiosks, anyone on the network can be a Buyer (and, for example, a Kiosk Owner at the same time). -** Benefits:** +**Benefits:** * Buyers get access to global liquidity and can get the best offer * Buyers can place bids on collections through their Kiosks * Most of the actions performed in Kiosks are free (gas-less) for Buyers @@ -55,7 +55,7 @@ As a marketplace operator, you can implement IOTA Kiosk to watch for offers made As a creator, IOTA Kiosk supports strong enforcement for transfer policies and associated rules to protect assets and enforce asset ownership. IOTA Kiosk gives creators more control over their creations, and puts creators and owners in control of how their works can be used. -Creator is a party that creates and controls the TransferPolicy for a single type. For example, the authors of IOTAFrens are the Creators of the `IOTAFren` type and act as creators in the Kiosk ecosystem. Creators set the policy, but they might also be the first sellers of their assets through a Kiosk. +A creator is a party that creates and controls the TransferPolicy for a single type. Creators set the policy, but they might also be the first sellers of their assets through a Kiosk. **Creators can:** * Set any rules for trades @@ -90,17 +90,17 @@ In practice, these guarantees mean that: IOTA Kiosk is a shared object that can store heterogeneous values, such as different sets of asset collectibles. When you add an asset to your kiosk, it has one of the following states: * PLACED - an item placed in the kiosk using the `kiosk::place` function. The Kiosk Owner can withdraw it and use it directly, borrow it (mutably or immutably), or list an item for sale. -* LOCKED - an item placed in the kiosk using the `kiosk::lock` function. You can’t withdraw a Locked item from a kiosk, but you can borrow it mutably and list it for sale. Any item placed in a kiosk that has an associated Kiosk Lock policy have a LOCKED state. +* LOCKED - an item placed in the kiosk using the `kiosk::lock` function. You can’t withdraw a Locked item from a kiosk, but you can borrow it mutably and list it for sale. Any item placed in a kiosk that has an associated Kiosk Lock policy has a LOCKED state. * LISTED - an item in the kiosk that is listed for sale using the `kiosk::list` or `kiosk::place_and_list` functions. You can’t modify an item while listed, but you can borrow it immutably or delist it, which returns it to its previous state. * LISTED EXCLUSIVELY - an item placed or locked in the kiosk by an extension that calls the `kiosk::list_with_purchase_cap` function. Only the kiosk owner can approve calling the function. The owner can only borrow it immutably. The extension must provide the functionality to delist / unlock the asset, or it might stay locked forever. Given that this action is explicitly performed by the Owner - it is the responsibility of the Owner to choose verified and audited extensions to use. When someone purchases an asset from a kiosk, the asset leaves the kiosk and ownership transfers to the buyer’s address. -## Open a IOTA Kiosk +## Open an IOTA Kiosk -To use a IOTA Kiosk, you must create one and have the `KioskOwnerCap` that matches the `Kiosk` object. You can create a new kiosk using a single transaction by calling the `kiosk::default` function. The function creates and shares a `Kiosk`, and transfers the `KioskOwnerCap` to your address. +To use an IOTA Kiosk, you must create one and have the `KioskOwnerCap` that matches the `Kiosk` object. You can create a new kiosk using a single transaction by calling the `kiosk::default` function. The function creates and shares a `Kiosk`, and transfers the `KioskOwnerCap` to your address. -### Create a IOTA Kiosk using programmable transaction blocks +### Create an IOTA Kiosk using programmable transaction blocks ```javascript let tx = new TransactionBlock(); @@ -109,7 +109,7 @@ tx.moveCall({ }); ``` -### Create a IOTA Kiosk using the IOTA CLI +### Create an IOTA Kiosk using the IOTA CLI ```shell iota client call \ @@ -119,12 +119,12 @@ iota client call \ --gas-budget 1000000000 ``` -### Create a IOTA Kiosk with advanced options +### Create an IOTA Kiosk with advanced options For more advanced use cases, when you want to choose the storage model or perform an action right away, you can use the programmable transaction block (PTB) friendly function kiosk::new. Kiosk is designed to be shared. If you choose a different storage model, such as owned, your kiosk might not function as intended or not be accessible to other users. You can make sure your Kiosk works by testing it on IOTA Testnet. -### Create a IOTA Kiosk with advanced options using programmable transaction blocks +### Create an IOTA Kiosk with advanced options using programmable transaction blocks ```javascript let tx = new TransactionBlock(); @@ -140,9 +140,18 @@ tx.moveCall({ }) ``` -### Create a IOTA Kiosk with advanced options using the IOTA CLI +### Create an IOTA Kiosk with advanced options using a PTB in the IOTA CLI -IOTA CLI does not support PTBs and transaction chaining yet. You can use the `kiosk::default` function instead. +```shell +iota client ptb \ + --gas-budget 1000000000 \ + --move-call 0x2::kiosk::new \ + --assign kiosk \ + --move-call 0x2::transfer::public_share_object "<0x2::kiosk::Kiosk>" kiosk.0 \ + --transfer-objects [kiosk.1] +``` + +Since `0x2::kiosk::new` returns a tuple, `kiosk.0` refers to the `Kiosk` itself and `kiosk.1` to the `KioskOwnerCap`. ## Place items in and take items from your kiosk @@ -208,7 +217,18 @@ let item = tx.moveCall({ ### Take an item from a kiosk using the IOTA CLI -The `kiosk::take` function is built to be PTB friendly and returns the asset. The IOTA CLI does not yet support transaction chaining. +The `kiosk::take` function is built to be PTB friendly and returns the asset. In this IOTA CLI PTB example we transfer the taken item to the given address. + +```shell +iota client ptb \ + --gas-budget 1000000000 \ + --assign kiosk @ \ + --assign kiosk_owner_cap @ \ + --assign item @ \ + --move-call 0x2::kiosk::take "" kiosk kiosk_owner_cap item \ + --assign taken_item \ + --transfer-objects [taken_item] +``` ## Lock items in a kiosk @@ -264,12 +284,12 @@ IOTA Kiosk provides basic trading functionality. As a kiosk owner, you can list * `kiosk::delist` - remove an existing listing * `kiosk::purchase` - purchase an asset listed for sale -Anyone on the network can purchase an item listed from a IOTA Kiosk. To learn more about the purchase flow, see the [Purchase section](#purchase). To learn more about asset states and what can be done with a listed item, see the [Asset States](#asset-states) section. +Anyone on the network can purchase an item listed from an IOTA Kiosk. To learn more about the purchase flow, see the [Purchase section](#purchase). To learn more about asset states and what can be done with a listed item, see the [Asset States](#asset-states) section. ### List an item from a kiosk -As a kiosk owner, you can use the `kiosk::list` function to list any asset you added to your kiosk. Include the item to sell and the list price as arguments. All listings on IOTA are in IOTA tokens. -When you list an item, IOTA emits a `kiosk::ItemListed` event that contains the Kiosk ID, Item ID, type of the Item, and the list price. +As a kiosk owner, you can use the `kiosk::list` function to list any asset you added to your kiosk by including the item to sell and the list price as arguments. All listings on IOTA are in IOTA coins. +When you list an item, IOTA emits a `kiosk::ItemListed` event that contains the Kiosk ID, Item ID, the type of the Item, and the list price. ### List an item using programmable transaction blocks @@ -309,7 +329,7 @@ When you delist an item, IOTA returns to the kiosk owner the gas fees charged to When you delist an item, IOTA emits a `kiosk::ItemDelisted` event that contains the Kiosk ID, Item ID, and the type of the item. -### Delist an item using the programmable transaction blocks +### Delist an item using programmable transaction blocks ```javascript let tx = new TransactionBlock(); @@ -339,12 +359,35 @@ iota client call \ ## Purchase an item from a kiosk {#purchase} -Anyone that has an address on the IOTA network can purchase an item listed from a IOTA Kiosk. To purchase an item, you can use the `kiosk::purchase` function. Specify the item to purchase and pay the list price set by the Kiosk Owner. +Anyone that has an address on the IOTA network can purchase an item listed from an IOTA Kiosk. To purchase an item, you can use the `kiosk::purchase` function. Specify the item to purchase and pay the list price set by the Kiosk Owner. You can discover the items listed on the network with the `kiosk::ItemListed` event. When you use the `kiosk::purchase` function, it returns the purchased asset and the `TransferRequest` for the type associated with the asset. To complete the purchase, you must meet the terms defined in the `TransferPolicy` applied to the asset. +### Purchase an item using the IOTA CLI + +```shell +iota client ptb \ + --gas-budget 1000000000 \ + --assign kiosk @ \ + --assign item @ \ + --assign coin @ \ + --assign transfer_policy @ \ + # We have to purchase the item with a `Coin` whose balance matches the item price exactly. + # In this example we take one of our coins as input and split off a `Coin` with the required balance. + # The remainder will be sent back to us. + --split-coins coin [] \ + --assign coins \ + --move-call 0x2::kiosk::purchase '' kiosk item coins.0 \ + # This is a tuple consisting of the purchased item and a `TransferRequest` that we need to resolve in this PTB. + --assign purchase_result \ + # Resolve the `TransferRequest` by confirming it with `TransferPolicy`. + --move-call 0x2::transfer_policy::confirm_request '' transfer_policy purchase_result.1 \ + # Transfer the purchased item to ourselves. + --transfer-objects [purchase_result.0] +``` + ## Borrow an item from a kiosk As a kiosk owner, you can access an asset placed or locked in a kiosk without taking the asset from the kiosk. You can always borrow the asset immutably. Whether you can mutably borrow an asset depends on the state of the asset. For example, you can’t borrow a listed asset because you can’t modify it while listed. The functions available include: @@ -376,7 +419,7 @@ You can mutably borrow an asset from a kiosk if it is not listed. You can use th ### Mutably borrow an asset using IOTA Move ```move -module examples::mutable_borrow +module examples::mutable_borrow { use iota::object::ID; use iota::kiosk::{Self, Kiosk, KioskOwnerCap}; @@ -388,9 +431,9 @@ module examples::mutable_borrow } ``` -### Mutable borrow with borrow_val +### Mutable borrow with `borrow_val` -You can use the PTB-friendly kiosk::borrow_val function. It allows you to take an asset and place it back in the same transaction. To make sure the asset is placed back into the kiosk, the function "obliges" the caller with a “Hot Potato”. +You can use the PTB-friendly `kiosk::borrow_val` function. It allows you to take an asset and place it back in the same transaction. To make sure the asset is placed back into the kiosk, the function "obliges" the caller with a “Hot Potato”. ### Mutable borrow with `borrow_val` using programmable transaction blocks @@ -408,9 +451,9 @@ let [item, promise] = tx.moveCall({ typeArguments: [ itemType ], }); -// freely mutate or reference the `item` -// any calls are available as long as they take a reference -// `returnValue` must be explicitly called +// Freely mutate or reference the `item`. +// Any calls are available as long as they take a reference. +// `return_val` must be explicitly called. tx.moveCall({ target: '0x2::kiosk::return_val', @@ -421,7 +464,7 @@ tx.moveCall({ ## Withdraw proceeds from a completed sale -When someone purchases an item, IOTA stores the proceeds from the sale in the Kiosk. As the kiosk owner, you can withdraw the proceeds at any time by calling the `kiosk::withdraw` function. The function is simple, but because it is PTB friendly it is not currently supported in the IOTA CLI. +When someone purchases an item, IOTA stores the proceeds from the sale in the Kiosk. As the kiosk owner, you can withdraw the proceeds at any time by calling the `kiosk::withdraw` function. ### Withdraw proceeds using programmable transaction blocks @@ -453,4 +496,14 @@ let coin = tx.moveCall({ ### Withdraw proceeds using the IOTA CLI -Due to the function being PTB friendly, it is not currently supported in the CLI environment. +```shell +iota client ptb \ + --assign kiosk @ \ + --assign kiosk_owner_cap @ \ + --move-call 0x2::kiosk::withdraw kiosk kiosk_owner_cap none \ + --assign withdrawn_coin \ + --transfer-objects [withdrawn_coin] \ + --gas-budget 1000000000 +``` + +Passing `none` withdraws all profits, while passing `some(x)` will attempt to withdraw a `Coin` with a balance of `x`. This amount `x` can be smaller or equal to the contained profits. From 84f38fca4aa575a62f40841812114e93b3f227b6 Mon Sep 17 00:00:00 2001 From: Philipp Gackstatter Date: Thu, 8 Aug 2024 11:26:19 +0200 Subject: [PATCH 05/16] fix(docs): Typos in kiosk apps --- .../developer/standards/kiosk-apps.mdx | 29 +++++++++---------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/docs/content/developer/standards/kiosk-apps.mdx b/docs/content/developer/standards/kiosk-apps.mdx index 2580f81172d..220c7807ab6 100644 --- a/docs/content/developer/standards/kiosk-apps.mdx +++ b/docs/content/developer/standards/kiosk-apps.mdx @@ -12,24 +12,21 @@ There are two types of apps: ## Basic apps -Basic Kiosk apps do not require Kiosk Apps API to function. They usually serve the purpose of adding custom metadata to a kiosk or wrapping/working with existing objects such as `Kiosk` or `KioskOwnerCap`. An example of an app that does not require the API is the Personal Kiosk app. +Basic Kiosk apps do not require the Kiosk Apps API to function. They usually serve the purpose of adding custom metadata to a kiosk or wrapping/working with existing objects such as `Kiosk` or `KioskOwnerCap`. An example of an app that does not require the API is the Personal Kiosk app. -### UID access via the uid_mut +### UID access via `uid_mut` Kiosk has an `id: UID` field like all objects on IOTA, which allows this object to be uniquely identified and carry custom dynamic fields and dynamic object fields. The Kiosk itself is built around dynamic fields and features like place and list are built around dynamic object fields. -### The uid_mut_as_owner function +### The `uid_mut_as_owner` function -Kiosk can carry additional dynamic fields and dynamic object fields. The `uid_mut_as_owner` function allows the Kiosk owner to mutably access the UID of the Kiosk object and use it to add or remove custom fields. +A Kiosk can carry additional dynamic fields and dynamic object fields. The `uid_mut_as_owner` function allows the Kiosk owner to mutably access the `UID` of the Kiosk object and use it to add or remove custom fields. -Function signature: +Its function signature is: `kiosk::uid_mut_as_owner(self: &mut Kiosk, cap: &KioskOwnerCap): &mut UID` +### The public UID getter -`kiosk::uid_mut_as_owner(self: &mut Kiosk, cap: &KioskOwnerCap): &mut UID` - -### The public uid getter - -Anyone can read the `uid` of kiosks. This allows third party modules to read the fields of the kiosk if they're allowed to do so. Therefore enabling the object capability and other patterns. +Anyone can read the `UID` of kiosks. This allows third party modules to read the fields of the kiosk if they're allowed to do so. Therefore enabling the object capability and other patterns. ### Basic app ideas @@ -42,16 +39,16 @@ module examples::kiosk_name_ext { use iota::dynamic_field as df; use iota::kiosk::{Self, Kiosk, KioskOwnerCap}; - /// The dynamic field key for the Kiosk Name Extension + /// The dynamic field key for the Kiosk Name extension. struct KioskName has copy, store, drop {} - /// Add a name to the Kiosk (in this implementation can be called only once) + /// Add a name to the Kiosk (in this implementation it can be called only once). public fun add(self: &mut Kiosk, cap: &KioskOwnerCap, name: String) { let uid_mut = kiosk::uid_mut_as_owner(self, cap); df::add(uid_mut, KioskName {}, name) } - /// Try read the name of the Kiosk - if set - return Some(String), if not - None + /// Return `some(String)` as the name of the Kiosk if it's set, otherwise `none`. public fun name(self: &Kiosk): Option { if (df::exists_(kiosk::uid(self), KioskName {})) { option::some(*df::borrow(kiosk::uid(self), KioskName {})) @@ -109,7 +106,7 @@ module examples::letterbox_ext { /// The Witness struct used to identify and authorize the extension. struct Extension has drop {} - /// Install the Mallbox extension into the Kiosk. + /// Install the Letterbox extension into the Kiosk. public fun add(kiosk: &mut Kiosk, cap: &KioskOwnerCap, ctx: &mut TxContext) { kiosk_extension::add(Extension {}, kiosk, cap, PERMISSIONS, ctx) } @@ -148,10 +145,10 @@ module examples::letterbox_ext { /// The expected set of permissions for the app. It requires `place`. const PERMISSIONS: u128 = 1; - /// The witness struct used to identify and authorize the app. + /// The Witness struct used to identify and authorize the app. struct Extension has drop {} - /// Install the Mallbox app into the kiosk and request `place` permission. + /// Install the Letterbox extension into the Kiosk. public fun add(kiosk: &mut Kiosk, cap: &KioskOwnerCap, ctx: &mut TxContext) { kiosk_extension::add(Extension {}, kiosk, cap, PERMISSIONS, ctx) } From d6f0f15ed131ffce5cb2e043373486959e008d51 Mon Sep 17 00:00:00 2001 From: Philipp Gackstatter Date: Thu, 8 Aug 2024 12:00:37 +0200 Subject: [PATCH 06/16] fix(docs): Fix typos and consistency --- docs/content/developer/standards/display.mdx | 53 ++++++++++---------- 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/docs/content/developer/standards/display.mdx b/docs/content/developer/standards/display.mdx index 5a69306960e..810e1b8f6a9 100644 --- a/docs/content/developer/standards/display.mdx +++ b/docs/content/developer/standards/display.mdx @@ -7,7 +7,7 @@ The IOTA Object Display standard is a template engine that enables on-chain mana Use a `Publisher` object that you own to set `iota::display` for a type. For more information about `Publisher` objects, see [Publisher](https://examples.iota.io/basics/publisher.html) topic in *IOTA Move by Example*. -In IOTA Move, `Display` represents an object that specifies a set of named templates for the type `T`. For example, for a type `0x2::capy::Capy` the display syntax is: `Display<0x2::capy::Capy>`. +In IOTA Move, `Display` represents an object that specifies a set of named templates for the type `T`. For example, for a type `0x2::hero::Hero` the display syntax is: `Display<0x2::hero::Hero>`. IOTA Full nodes process all objects of the type `T` by matching the `Display` definition, and return the processed result when you query an object with the `{ showDisplay: true }` setting in the query. @@ -82,17 +82,17 @@ module examples::my_hero { ]; let values = vector[ - // For `name` one can use the `Hero.name` property + // For `name` one can use the `Hero.name` property. utf8(b"{name}"), - // For `link` one can build a URL using an `id` property + // For `link` one can build a URL using an `id` property. utf8(b"https://iota-heroes.io/hero/{id}"), // For `image_url` use an IPFS template + `image_url` property. utf8(b"ipfs://{image_url}"), // Description is static for all `Hero` objects. utf8(b"A true Hero of the IOTA ecosystem!"), - // Project URL is usually static + // Project URL is usually static. utf8(b"https://iota-heroes.io"), - // Creator field can be any + // Creator field can be any. utf8(b"Unknown IOTA Fan") ]; @@ -137,17 +137,17 @@ After you create the `Display`, you can modify it. The following code sample dem ```move module iota::display { - /// Sets multiple fields at once + /// Sets multiple fields at once. public fun add_multiple( self: &mut Display, keys: vector, values: vector ) { /* ... */ } - /// Edit a single field + /// Edit a single field. public fun edit(self: &mut Display, key: String, value: String) { /* ... */ } - /// Remove a key from Display + /// Remove a key from Display. public fun remove(self: &mut Display, key: String ) { /* ... */ } } ``` @@ -168,14 +168,15 @@ module iota::display { In IOTA, utility objects enable authorization for capabilities. Almost all modules have features that can be accessed only with the required capability. Generic modules allow one capability per application, such as a marketplace. Some capabilities mark ownership of a shared object on-chain, or access the shared data from another account. With capabilities, it is important to provide a meaningful description of objects to facilitate user interface implementation. This helps avoid accidentally transferring the wrong object when objects are similar. It also provides a user-friendly description of items that users see. -The following example demonstrates how to create a capy capability: +The following example demonstrates how to create a pet capability: ```move -module capy::utility { - /// A capability which grants Capy Manager permission to add - /// new genes and manage the Capy Market - struct CapyManagerCap has key, store { - id: UID } +module pet::utility { + /// A capability which grants Pet Manager permission to add + /// new genes and manage the Pet Market. + struct PetManagerCap has key, store { + id: UID + } } ``` @@ -184,13 +185,13 @@ module capy::utility { A common case with in-game items is to have a large number of similar objects grouped by some criteria. It is important to optimize their size and the cost to mint and update them. Typically, a game uses a single source image or URL per group or item criteria. Storing the source image inside of every object is not optimal. In some cases, users mint in-game items when a game allows them or when they purchase an in-game item. To enable this, some IPFS/Arweave metadata must be created and stored in advance. This requires additional logic that is usually not related to the in-game properties of the item. -The following example demonstrates how to create a Capy: +The following example demonstrates how to create a Pet: ```move -module capy::capy_items { - /// A wearable Capy item. For some items there can be an +module pet::pet_items { + /// A wearable Pet item. For some items there can be an /// unlimited supply. And items with the same name are identical. - struct CapyItem has key, store { + struct PetItem has key, store { id: UID, name: String } @@ -199,18 +200,18 @@ module capy::capy_items { ## Unique objects with dynamic representation -IOTA Capys use dynamic image generation. When a Capy is born, its attributes determine the Capy’s appearance, such as color or pattern. When a user puts an item on a Capy, the Capy’s appearance changes. When users put multiple items on a Capy, there’s a chance of a bonus for a combination of items. +IOTA Pets use dynamic image generation. When a Pet is born, its attributes determine the Pet’s appearance, such as color or pattern. When a user puts an item on a Pet, the Pet’s appearance changes. When users put multiple items on a Pet, there’s a chance of a bonus for a combination of items. -To implement this, the Capys game API service refreshes the image in response to a user-initiated change. The URL for a Capy is a template with the `capy.id`. But storing the full URL - as well as other fields in the Capy object due to their diverse population - also leads to users paying for excess storage and increased gas fees. +To implement this, the Pet's game API service refreshes the image in response to a user-initiated change. The URL for a Pet is a template with the `pet.id`. But storing the full URL - as well as other fields in the Pet object due to their diverse population - also leads to users paying for excess storage and increased gas fees. The following example demonstrates how to implement dynamic image generation: ```move -module capy::capy { - /// A Capy - very diverse object with different combination - /// of genes. Created dynamically + for images a dynamic SVG +module pet::pet { + /// A Pet - very diverse object with different combination + /// of genes. Created dynamically. For images, a dynamic SVG /// generation is used. - struct Capy has key, store { + struct Pet has key, store { id: UID, genes: vector } @@ -223,8 +224,8 @@ This is the simplest scenario - an object represents everything itself. It is ve ```move module iota::devnet_nft { - /// A Collectible with a static data. URL, name, description are - /// set only once on a mint event + /// A Collectible with static data. + /// URL, name and description are set only once during minting. struct DevNetNFT has key, store { id: UID, name: String, From 53716581807ab4c1486e7115246a2e7088ecd8a0 Mon Sep 17 00:00:00 2001 From: Philipp Gackstatter Date: Thu, 8 Aug 2024 12:23:05 +0200 Subject: [PATCH 07/16] fix(docs): Convert tabs to spaces --- docs/content/developer/standards/standards.mdx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/content/developer/standards/standards.mdx b/docs/content/developer/standards/standards.mdx index 65482c56d66..82e9f77b060 100644 --- a/docs/content/developer/standards/standards.mdx +++ b/docs/content/developer/standards/standards.mdx @@ -6,11 +6,11 @@ sidebar_label: Overview Standards on the IOTA blockchain are features, frameworks, or apps that you can extend or customize. - - - - - - - + + + + + + + From f95b1ff14fc9cbbd0bdda75c22f32dd92b04cc52 Mon Sep 17 00:00:00 2001 From: Philipp Gackstatter Date: Thu, 8 Aug 2024 15:39:54 +0200 Subject: [PATCH 08/16] fix(docs): Typos in wallet standard --- .../developer/standards/wallet-standard.mdx | 80 +++++++++---------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/docs/content/developer/standards/wallet-standard.mdx b/docs/content/developer/standards/wallet-standard.mdx index b73f5712381..2aaaa596738 100644 --- a/docs/content/developer/standards/wallet-standard.mdx +++ b/docs/content/developer/standards/wallet-standard.mdx @@ -13,23 +13,23 @@ You need to create a class that represents your wallet. You can use the `Wallet` `@iota/wallet-standard` to help ensure your class adheres to the standard. ```tsx -import { IOTA_DEVNET_CHAIN, Wallet } from '@iota/wallet-standard'; +import { IOTA_TESTNET_CHAIN, Wallet } from '@iota/wallet-standard'; class YourWallet implements Wallet { - get version() { - // Return the version of the Wallet Standard this implements (in this case, 1.0.0). - return '1.0.0'; - } - get name() { - return 'Wallet Name'; - } - get icon() { - return 'some-icon-data-url'; - } - // Return the IOTA chains that your wallet supports. - get chains() { - return [IOTA_DEVNET_CHAIN]; - } + get version() { + // Return the version of the Wallet Standard this implements (in this case, 1.0.0). + return '1.0.0'; + } + get name() { + return 'Wallet Name'; + } + get icon() { + return 'some-icon-data-url'; + } + // Return the IOTA chains that your wallet supports. + get chains() { + return [IOTA_TESTNET_CHAIN]; + } } ``` @@ -64,7 +64,7 @@ import { } from "@iota/wallet-standard"; class YourWallet implements Wallet { - /* ... existing code from above ... */ + /* ... existing code from above ... */ get features(): ConnectFeature & EventsFeature & IOTAFeatures { return { @@ -76,10 +76,10 @@ class YourWallet implements Wallet { version: "1.0.0", on: this.#on, }, - "iota:signPersonalMessage": { + "iota:signPersonalMessage": { version: "1.0.0", - signPersonalMessage: this.#signPersonalMessage, - }, + signPersonalMessage: this.#signPersonalMessage, + }, "iota:signTransactionBlock": { version: "1.0.0", signTransactionBlock: this.#signTransactionBlock, @@ -99,7 +99,7 @@ class YourWallet implements Wallet { // Your wallet's connect implementation }; - #signPersonalMessage: IOTASignPersonalMessageMethod = () => { + #signPersonalMessage: IOTASignPersonalMessageMethod = () => { // Your wallet's signTransaction implementation }; @@ -126,26 +126,26 @@ required interface. import { ReadonlyWalletAccount } from '@iota/wallet-standard'; class YourWallet implements Wallet { - get accounts() { - // Assuming we already have some internal representation of accounts: - return someWalletAccounts.map( - (walletAccount) => - // Return - new ReadonlyWalletAccount({ - address: walletAccount.iotaAddress, - publicKey: walletAccount.pubkey, - // The IOTA chains that your wallet supports. - chains: [IOTA_DEVNET_CHAIN], - // The features that this account supports. This can be a subset of the wallet's supported features. - // These features must exist on the wallet as well. - features: [ - 'iota:signPersonalMessage', - 'iota:signTransactionBlock', - 'iota:signAndExecuteTransactionBlock', - ], - }), - ); - } + get accounts() { + // Assuming we already have some internal representation of accounts: + return someWalletAccounts.map( + (walletAccount) => + // Return + new ReadonlyWalletAccount({ + address: walletAccount.iotaAddress, + publicKey: walletAccount.pubkey, + // The IOTA chains that your wallet supports. + chains: [IOTA_TESTNET_CHAIN], + // The features that this account supports. This can be a subset of the wallet's supported features. + // These features must exist on the wallet as well. + features: [ + 'iota:signPersonalMessage', + 'iota:signTransactionBlock', + 'iota:signAndExecuteTransactionBlock', + ], + }), + ); + } } ``` From f4be08c9d75f4c4338f988dc9dea0c04c04d3d6a Mon Sep 17 00:00:00 2001 From: Philipp Gackstatter Date: Fri, 9 Aug 2024 11:01:08 +0200 Subject: [PATCH 09/16] fix(docs): JavaScript examples --- docs/content/developer/standards/coin.mdx | 9 +++++---- .../developer/standards/kiosk-apps.mdx | 20 +++++++++---------- docs/content/developer/standards/kiosk.mdx | 4 +++- 3 files changed, 18 insertions(+), 15 deletions(-) diff --git a/docs/content/developer/standards/coin.mdx b/docs/content/developer/standards/coin.mdx index 3b72d68a6ab..c173fa1a1d1 100644 --- a/docs/content/developer/standards/coin.mdx +++ b/docs/content/developer/standards/coin.mdx @@ -174,13 +174,14 @@ let deny_list = ptb.obj(ObjectArg::SharedObject { mutable: true, })?; let deny_cap = ptb.obj(ObjectArg::ImmOrOwnedObject(deny_cap))?; -let address = ptb.pure(cmd.address())?; +let address_to_ban = IotaAddress::from_str("0x...")?; +let address_to_ban_arg = ptb.pure(address_to_ban)?; ptb.command(Command::move_call( IOTA_FRAMEWORK_PACKAGE_ID, Identifier::from(COIN_MODULE_NAME), - Identifier::from_str("deny_list_add".to_string())?, + Identifier::from_str("deny_list_add")?, vec![], - vec![deny_list, deny_cap, address], + vec![deny_list, deny_cap, address_to_ban_arg], )); let builder = ptb.finish(); @@ -191,7 +192,7 @@ let builder = ptb.finish(); - `SequenceNumber` is the `initial_shared_version` of the `DenyList` singleton. - `deny_cap` is the `ObjectRef` (`(ObjectID, SequenceNumber, ObjectDigest)`) of the `DenyCap` the publisher has received. - `otw_type` is the `TypeTag` created from `::regulated_coin::REGULATED_COIN` type. -- `cmd.address()` returns the address to ban as an `IotaAddress`. +- `address_to_ban` is the address to ban as an `IotaAddress`. diff --git a/docs/content/developer/standards/kiosk-apps.mdx b/docs/content/developer/standards/kiosk-apps.mdx index 220c7807ab6..89558877a9a 100644 --- a/docs/content/developer/standards/kiosk-apps.mdx +++ b/docs/content/developer/standards/kiosk-apps.mdx @@ -208,15 +208,15 @@ Use the `disable(kiosk: &mut Kiosk, cap: &KioskOwnerCap)` function to disab **Example PTB** -```move -let txb = new TransactionBuilder(); -let kioskArg = tx.object(''); -let capArg = tx.object(''); +```javascript +let txb = new TransactionBlock(); +let kioskArg = txb.object(''); +let capArg = txb.object(''); txb.moveCall({ target: '0x2::kiosk_extension::disable', arguments: [ kioskArg, capArg ], - typeArguments: '::letterbox_ext::Extension' + typeArguments: [ '::letterbox_ext::Extension' ] }); ``` @@ -228,14 +228,14 @@ The call fails if the storage is not empty. **Example PTB** -```move -let txb = new TransactionBuilder(); -let kioskArg = tx.object(''); -let capArg = tx.object(''); +```javascript +let txb = new TransactionBlock(); +let kioskArg = txb.object(''); +let capArg = txb.object(''); txb.moveCall({ target: '0x2::kiosk_extension::remove', arguments: [ kioskArg, capArg ], - typeArguments: '::letterbox_ext::Extension' + typeArguments: [ '::letterbox_ext::Extension' ] }); ``` diff --git a/docs/content/developer/standards/kiosk.mdx b/docs/content/developer/standards/kiosk.mdx index 130af1b33b6..b38601d6f57 100644 --- a/docs/content/developer/standards/kiosk.mdx +++ b/docs/content/developer/standards/kiosk.mdx @@ -128,6 +128,8 @@ Kiosk is designed to be shared. If you choose a different storage model, such as ```javascript let tx = new TransactionBlock(); +let sender = "0x..."; + let [kiosk, kioskOwnerCap] = tx.moveCall({ target: '0x2::kiosk::new' }); @@ -136,7 +138,7 @@ tx.transferObjects([ kioskOwnerCap ], sender); tx.moveCall({ target: '0x2::transfer::public_share_object', arguments: [ kiosk ], - typeArguments: '0x2::kiosk::Kiosk' + typeArguments: ['0x2::kiosk::Kiosk'] }) ``` From 0b40d139e98c96936b87f8ec078cb1eed6d63b7c Mon Sep 17 00:00:00 2001 From: Philipp Gackstatter Date: Fri, 9 Aug 2024 13:45:48 +0200 Subject: [PATCH 10/16] fix(docs): Make Move examples syntactically correct --- .../standards/closed-loop-token/rules.mdx | 4 +- .../standards/closed-loop-token/spending.mdx | 2 +- docs/content/developer/standards/display.mdx | 59 +++++++++---------- .../developer/standards/kiosk-apps.mdx | 30 ++++++---- 4 files changed, 51 insertions(+), 44 deletions(-) diff --git a/docs/content/developer/standards/closed-loop-token/rules.mdx b/docs/content/developer/standards/closed-loop-token/rules.mdx index 3fd38e46619..0407abb9cae 100644 --- a/docs/content/developer/standards/closed-loop-token/rules.mdx +++ b/docs/content/developer/standards/closed-loop-token/rules.mdx @@ -10,7 +10,7 @@ A rule is represented as a witness - a type with a `drop` ability. You can eithe ```move /// The Rule type -struct Rule has drop {} +public struct Rule has drop {} ``` After you [add a rule](token-policy.mdx#adding-rules) to an action in the `TokenPolicy`, the action requires a stamp of the rule to pass confirmation. @@ -29,7 +29,7 @@ module example::pass_rule { use iota::token::{Self, ActionRequest, TokenPolicy}; /// The Rule type - struct Pass has drop {} + public struct Pass has drop {} /// Add approval from the Pass rule to the ActionRequest public fun verify( diff --git a/docs/content/developer/standards/closed-loop-token/spending.mdx b/docs/content/developer/standards/closed-loop-token/spending.mdx index 5d28ee32023..5f09f149eb4 100644 --- a/docs/content/developer/standards/closed-loop-token/spending.mdx +++ b/docs/content/developer/standards/closed-loop-token/spending.mdx @@ -28,7 +28,7 @@ Normally, the `spend` action should have at least one rule assigned to it to pre ```move /// Rule-like witness to stamp the ActionRequest -struct GiftShop has drop {} +public struct GiftShop has drop {} /// Spend the token and return a Gift + ActionRequest public fun buy_gift( diff --git a/docs/content/developer/standards/display.mdx b/docs/content/developer/standards/display.mdx index 810e1b8f6a9..8c4d35c1f26 100644 --- a/docs/content/developer/standards/display.mdx +++ b/docs/content/developer/standards/display.mdx @@ -45,24 +45,21 @@ The following represents the template the `init` function defines: /// to use it to get the `Display` object - a way to describe a /// type for the ecosystem. module examples::my_hero { - use iota::tx_context::{sender, TxContext}; use std::string::{utf8, String}; - use iota::transfer; - use iota::object::{Self, UID}; // The creator bundle: these two packages often go together. use iota::package; use iota::display; /// The Hero - an outstanding collection of digital art. - struct Hero has key, store { + public struct Hero has key, store { id: UID, name: String, image_url: String, } /// One-Time-Witness for the module. - struct MY_HERO has drop {} + public struct MY_HERO has drop {} /// In the module initializer one claims the `Publisher` object /// to then create a `Display`. The `Display` is initialized with @@ -100,15 +97,15 @@ module examples::my_hero { let publisher = package::claim(otw, ctx); // Get a new `Display` object for the `Hero` type. - let display = display::new_with_fields( + let mut display = display::new_with_fields( &publisher, keys, values, ctx ); // Commit first version of `Display` to apply changes. display::update_version(&mut display); - transfer::public_transfer(publisher, sender(ctx)); - transfer::public_transfer(display, sender(ctx)); + transfer::public_transfer(publisher, ctx.sender()); + transfer::public_transfer(display, ctx.sender()); } /// Anyone can mint their `Hero`! @@ -172,10 +169,10 @@ The following example demonstrates how to create a pet capability: ```move module pet::utility { - /// A capability which grants Pet Manager permission to add - /// new genes and manage the Pet Market. - struct PetManagerCap has key, store { - id: UID + /// A capability which grants Pet Manager permission to add + /// new genes and manage the Pet Market. + public struct PetManagerCap has key, store { + id: UID } } ``` @@ -189,12 +186,12 @@ The following example demonstrates how to create a Pet: ```move module pet::pet_items { - /// A wearable Pet item. For some items there can be an - /// unlimited supply. And items with the same name are identical. - struct PetItem has key, store { + /// A wearable Pet item. For some items there can be an + /// unlimited supply. And items with the same name are identical. + public struct PetItem has key, store { id: UID, name: String - } + } } ``` @@ -208,13 +205,13 @@ The following example demonstrates how to implement dynamic image generation: ```move module pet::pet { - /// A Pet - very diverse object with different combination - /// of genes. Created dynamically. For images, a dynamic SVG - /// generation is used. - struct Pet has key, store { - id: UID, - genes: vector - } + /// A Pet - very diverse object with different combination + /// of genes. Created dynamically. For images, a dynamic SVG + /// generation is used. + public struct Pet has key, store { + id: UID, + genes: vector + } } ``` @@ -224,13 +221,13 @@ This is the simplest scenario - an object represents everything itself. It is ve ```move module iota::devnet_nft { - /// A Collectible with static data. - /// URL, name and description are set only once during minting. - struct DevNetNFT has key, store { - id: UID, - name: String, - description: String, - url: Url, - } + /// A Collectible with static data. + /// URL, name and description are set only once during minting. + public struct DevNetNFT has key, store { + id: UID, + name: String, + description: String, + url: Url, + } } ``` diff --git a/docs/content/developer/standards/kiosk-apps.mdx b/docs/content/developer/standards/kiosk-apps.mdx index 89558877a9a..ce5d149ec86 100644 --- a/docs/content/developer/standards/kiosk-apps.mdx +++ b/docs/content/developer/standards/kiosk-apps.mdx @@ -35,12 +35,11 @@ You can attach custom dynamic fields to your kiosks that anyone can then read (b ```move module examples::kiosk_name_ext { use std::string::String; - use std::option::{Self, Option}; use iota::dynamic_field as df; use iota::kiosk::{Self, Kiosk, KioskOwnerCap}; /// The dynamic field key for the Kiosk Name extension. - struct KioskName has copy, store, drop {} + public struct KioskName has copy, store, drop {} /// Add a name to the Kiosk (in this implementation it can be called only once). public fun add(self: &mut Kiosk, cap: &KioskOwnerCap, name: String) { @@ -98,13 +97,14 @@ The signature of the `kiosk_extension::add` function requires the app witness, m ```move module examples::letterbox_ext { - // ... dependencies + use iota::kiosk_extension; + use iota::kiosk::{Kiosk, KioskOwnerCap}; /// The expected set of permissions for extension. It requires `place`. const PERMISSIONS: u128 = 1; /// The Witness struct used to identify and authorize the extension. - struct Extension has drop {} + public struct Extension has drop {} /// Install the Letterbox extension into the Kiosk. public fun add(kiosk: &mut Kiosk, cap: &KioskOwnerCap, ctx: &mut TxContext) { @@ -140,13 +140,14 @@ It's considered good practice to define a constant containing permissions of the ```move module examples::letterbox_ext { - // ... dependencies + use iota::kiosk_extension; + use iota::kiosk::{Kiosk, KioskOwnerCap}; /// The expected set of permissions for the app. It requires `place`. const PERMISSIONS: u128 = 1; /// The Witness struct used to identify and authorize the app. - struct Extension has drop {} + public struct Extension has drop {} /// Install the Letterbox extension into the Kiosk. public fun add(kiosk: &mut Kiosk, cap: &KioskOwnerCap, ctx: &mut TxContext) { @@ -161,16 +162,25 @@ If an app requests and is granted permissions (and isn't disabled), it can acces ```move module examples::letterbox_ext { - // ... + use iota::kiosk_extension; + use iota::kiosk::Kiosk; + use iota::transfer_policy::TransferPolicy; + + /// The Witness struct used to identify and authorize the app. + public struct Extension has drop {} + /// Our example object we want to place in the kiosk. + public struct Letter has key, store { + id: UID, + } /// Emitted when trying to place an item without permissions. const ENotEnoughPermissions: u64 = 1; /// Place a letter into the kiosk without the `KioskOwnerCap`. - public fun place(kiosk: &mut Kiosk, letter: Letter, policy: &TransferPolicy) { - assert!(kiosk_extension::can_place(kiosk), ENotEnoughPermissions) + public fun place(kiosk: &mut Kiosk, letter: Letter, policy: &TransferPolicy) { + assert!(kiosk_extension::can_place(kiosk), ENotEnoughPermissions); - kiosk_extension::place(Extension {}, kiosk, letter, policy) + kiosk_extension::place(Extension {}, kiosk, letter, policy); } } ``` From 99cc77af9c9e5e3e8451ee78bf895285f73be936 Mon Sep 17 00:00:00 2001 From: Philipp Gackstatter Date: Fri, 9 Aug 2024 15:57:16 +0200 Subject: [PATCH 11/16] fix(docs): Put overview on Standards header --- docs/content/developer/standards.mdx | 16 ++++++++++++++++ docs/content/developer/standards/standards.mdx | 16 ---------------- docs/content/sidebars/developer.js | 5 ++++- 3 files changed, 20 insertions(+), 17 deletions(-) create mode 100644 docs/content/developer/standards.mdx delete mode 100644 docs/content/developer/standards/standards.mdx diff --git a/docs/content/developer/standards.mdx b/docs/content/developer/standards.mdx new file mode 100644 index 00000000000..94de43e1508 --- /dev/null +++ b/docs/content/developer/standards.mdx @@ -0,0 +1,16 @@ +--- +title: IOTA Standards Overview +description: IOTA Standards Overview +--- + +Standards on the IOTA blockchain are features, frameworks, or apps that you can extend or customize. + + + + + + + + + + diff --git a/docs/content/developer/standards/standards.mdx b/docs/content/developer/standards/standards.mdx deleted file mode 100644 index 82e9f77b060..00000000000 --- a/docs/content/developer/standards/standards.mdx +++ /dev/null @@ -1,16 +0,0 @@ ---- -title: IOTA Standards Overview -sidebar_label: Overview ---- - -Standards on the IOTA blockchain are features, frameworks, or apps that you can extend or customize. - - - - - - - - - - diff --git a/docs/content/sidebars/developer.js b/docs/content/sidebars/developer.js index 7a49bcd8d9e..90ac242e96d 100644 --- a/docs/content/sidebars/developer.js +++ b/docs/content/sidebars/developer.js @@ -187,8 +187,11 @@ const developer = [ { type: 'category', label: 'Standards', + link: { + type: 'doc', + id: 'developer/standards', + }, items: [ - 'developer/standards/standards', 'developer/standards/coin', 'developer/standards/coin-manager', { From ebbc2f562ab761df385526497013092173413daf Mon Sep 17 00:00:00 2001 From: Dr-Electron Date: Mon, 12 Aug 2024 16:22:55 +0200 Subject: [PATCH 12/16] fix(docs): update link to Standards in developer documentation --- docs/content/developer/developer.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/content/developer/developer.mdx b/docs/content/developer/developer.mdx index 747e751157a..90fec804189 100644 --- a/docs/content/developer/developer.mdx +++ b/docs/content/developer/developer.mdx @@ -39,7 +39,7 @@ Go to [Cryptography](cryptography.mdx). Utilizing standards while developing applications is very important for composability. In this section you can find out all about the standards within the IOTA Move ecosystem for dealing with tokens, NFT like objects, and wallets. -Go to the [Standards](standards/standards.mdx). +Go to the [Standards](./standards.mdx). ## Advanced Topics From 6f7f0ca9c2c14f10046df0e51ec49a5786e3d673 Mon Sep 17 00:00:00 2001 From: Philipp Gackstatter Date: Tue, 13 Aug 2024 09:09:56 +0200 Subject: [PATCH 13/16] Update docs/content/sidebars/developer.js Co-authored-by: Dr-Electron --- docs/content/sidebars/developer.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/content/sidebars/developer.js b/docs/content/sidebars/developer.js index 90ac242e96d..f3f3df0a7f7 100644 --- a/docs/content/sidebars/developer.js +++ b/docs/content/sidebars/developer.js @@ -188,8 +188,10 @@ const developer = [ type: 'category', label: 'Standards', link: { - type: 'doc', - id: 'developer/standards', + type: 'generated-index', + title:'IOTA Standards Overview', + description: 'Standards on the IOTA blockchain are features, frameworks, or apps that you can extend or customize.', + slug: 'developer/standards', }, items: [ 'developer/standards/coin', From d1f03373a6ef94a6e9e3efdea73535c672dcd819 Mon Sep 17 00:00:00 2001 From: Philipp Gackstatter Date: Tue, 13 Aug 2024 09:11:52 +0200 Subject: [PATCH 14/16] fix(docs): Auto generate standards overview --- docs/content/developer/developer.mdx | 4 ++-- docs/content/developer/standards.mdx | 16 ---------------- 2 files changed, 2 insertions(+), 18 deletions(-) delete mode 100644 docs/content/developer/standards.mdx diff --git a/docs/content/developer/developer.mdx b/docs/content/developer/developer.mdx index 90fec804189..a5dc0b0e1e3 100644 --- a/docs/content/developer/developer.mdx +++ b/docs/content/developer/developer.mdx @@ -39,7 +39,7 @@ Go to [Cryptography](cryptography.mdx). Utilizing standards while developing applications is very important for composability. In this section you can find out all about the standards within the IOTA Move ecosystem for dealing with tokens, NFT like objects, and wallets. -Go to the [Standards](./standards.mdx). +Go to the [Standards](/developer/standards). ## Advanced Topics @@ -69,4 +69,4 @@ Go to [Migrating from IOTA/Shimmer Stardust](stardust/stardust-migration.mdx). This section contains the technical details needed to integrate IOTA on a exchange. -Go to [Exchange integration](exchange-integration/exchange-integration.mdx). \ No newline at end of file +Go to [Exchange integration](exchange-integration/exchange-integration.mdx). diff --git a/docs/content/developer/standards.mdx b/docs/content/developer/standards.mdx deleted file mode 100644 index 94de43e1508..00000000000 --- a/docs/content/developer/standards.mdx +++ /dev/null @@ -1,16 +0,0 @@ ---- -title: IOTA Standards Overview -description: IOTA Standards Overview ---- - -Standards on the IOTA blockchain are features, frameworks, or apps that you can extend or customize. - - - - - - - - - - From cc19022d57870bb4cefa676401c24bddf93b6500 Mon Sep 17 00:00:00 2001 From: Philipp Gackstatter Date: Tue, 13 Aug 2024 09:34:08 +0200 Subject: [PATCH 15/16] fix(docs): More move warning fixes --- .../developer/standards/closed-loop-token/rules.mdx | 1 - docs/content/developer/standards/coin-manager.mdx | 7 +++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/docs/content/developer/standards/closed-loop-token/rules.mdx b/docs/content/developer/standards/closed-loop-token/rules.mdx index 0407abb9cae..f9bb9488633 100644 --- a/docs/content/developer/standards/closed-loop-token/rules.mdx +++ b/docs/content/developer/standards/closed-loop-token/rules.mdx @@ -25,7 +25,6 @@ A rule module is a regular module with a `verify`-like function that typically t ```move module example::pass_rule { - use iota::tx_context; use iota::token::{Self, ActionRequest, TokenPolicy}; /// The Rule type diff --git a/docs/content/developer/standards/coin-manager.mdx b/docs/content/developer/standards/coin-manager.mdx index 1f99ddc5618..f554129df08 100644 --- a/docs/content/developer/standards/coin-manager.mdx +++ b/docs/content/developer/standards/coin-manager.mdx @@ -37,10 +37,9 @@ module example::exclusive_coin { public struct EXCLUSIVE_COIN has drop {} - #[allow(lint(share_owned))] fun init(witness: EXCLUSIVE_COIN, ctx: &mut TxContext) { // Create a `Coin` type and have it managed. - let (cm_treasury_cap, cm_meta_cap, mut manager) = coin_manager::create( + let (cm_treasury_cap, cm_meta_cap, manager) = coin_manager::create( witness, 0, b"EXCL", @@ -71,7 +70,7 @@ If you already have an existing `Coin`, you can create the `CoinManager` object If you already froze the `Metadata` object you can only migrate to a `CoinManager` that has immutable metadata from the start. You will not receive a `CoinManagerMetadataCap` in return, but you will get a `CoinManagerTreasuryCap`: ```move -let (cm_treasury_cap, mut manager) = coin_manager::new_with_immutable_metadata(cap, &meta, ctx); +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()); @@ -84,7 +83,7 @@ transfer::public_share_object(manager); If the metadata object is still owned, you can take advantage of the full functionality of the `CoinManager` with mutable `Metadata`: ```move -let (cm_treasury_cap, cm_meta_cap, mut manager) = coin_manager::new(cap, meta, ctx); +let (cm_treasury_cap, cm_meta_cap, manager) = coin_manager::new(cap, meta, ctx); // Transfer the `CoinManagerTreasuryCap` to the creator of the `Coin`. transfer::public_transfer(cm_treasury_cap, ctx.sender()); From 2f9e15cf6a705984410c0230273ad84bd3f12cb7 Mon Sep 17 00:00:00 2001 From: Philipp Gackstatter Date: Tue, 13 Aug 2024 10:16:34 +0200 Subject: [PATCH 16/16] fix(docs): Use `programmable_move_call` instead of command --- docs/content/developer/standards/coin.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/content/developer/standards/coin.mdx b/docs/content/developer/standards/coin.mdx index c173fa1a1d1..3a566ba903a 100644 --- a/docs/content/developer/standards/coin.mdx +++ b/docs/content/developer/standards/coin.mdx @@ -176,13 +176,13 @@ let deny_list = ptb.obj(ObjectArg::SharedObject { let deny_cap = ptb.obj(ObjectArg::ImmOrOwnedObject(deny_cap))?; let address_to_ban = IotaAddress::from_str("0x...")?; let address_to_ban_arg = ptb.pure(address_to_ban)?; -ptb.command(Command::move_call( +ptb.programmable_move_call( IOTA_FRAMEWORK_PACKAGE_ID, Identifier::from(COIN_MODULE_NAME), Identifier::from_str("deny_list_add")?, vec![], vec![deny_list, deny_cap, address_to_ban_arg], -)); +); let builder = ptb.finish(); ```