[docs] Add transaction builder methods documentation#25890
Draft
mystenmark wants to merge 12 commits intomainfrom
Draft
[docs] Add transaction builder methods documentation#25890mystenmark wants to merge 12 commits intomainfrom
mystenmark wants to merge 12 commits intomainfrom
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Contributor
📋 afdocs check resultsURL: https://sui-docs-32nwld2yd-sui-foundation.vercel.app |
- Add coin_reservation_obj_refs() to extract coin reservations from gas payment - Validate coin reservations are owned by sender (no sponsored tx support) - Validate coin reservations are for SUI balance type - Update gas balance checks to account for address balance gas - Filter coin reservations from input objects (they're virtual) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Pass compatibility arguments (for withdrawal PTB argument conversion) through the execution pipeline to the programmable transaction executor. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add transaction_rewriting module for handling coin reservations - Update authority to compute compat_args and pass to execution - Handle accumulator events for address balance gas payments Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Thread chain_identifier through simulacrum, replay, genesis-builder - Update network_config_builder and single_node_benchmark - Enable withdrawal compatibility PTB arguments in test config Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add test helpers for coin reservation encoding and validation - Add transactional tests for coin reservation gas scenarios - Add e2e tests for coin reservation compatibility - Test sponsored transaction rejection, mixed gas payments, etc. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add --enable-coin-reservations flag to coin_reservation_gas and insufficient_gas_payment tests so coin reservations work properly. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Document why unwrap is safe in transaction_rewriting.rs (validation happens before execution, and scheduler reserves funds) - Complete the incomplete comment in check_gas Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The change to allow empty transactions when gas is paid from address balance should be gated by enable_coin_reservation_obj_refs to avoid changing behavior for existing protocol versions. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
These tests use address balance and coin reservation features that are not yet enabled on mainnet. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The test uses empty input objects with address balance gas, which now requires coin reservations to be enabled. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Documents the step-by-step implementation of transfer and pay methods in TransactionBuilder, including how address balances can be used via coin reservation objects. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1726629 to
69a3c7b
Compare
Comment on lines
+1
to
+189
| # Transfer and Pay Methods in TransactionBuilder | ||
|
|
||
| This document describes the step-by-step implementation of transfer and pay methods in `crates/sui-transaction-builder/src/lib.rs`. | ||
|
|
||
| ## Address Balance Support | ||
|
|
||
| Address balances can be used as a funding source by passing **coin reservation objects** to these methods. Callers are responsible for: | ||
|
|
||
| 1. Creating a `FundsWithdrawalArg` to reserve the required funds from their address balance | ||
| 2. Using `coin::redeem_funds` to convert the withdrawal into a coin object | ||
| 3. Passing the resulting coin object (or its ObjectID) to the transaction builder methods | ||
|
|
||
| The transaction builder treats coin reservation objects the same as regular coin objects. This approach gives callers full control over when and how address balances are used. | ||
|
|
||
| ## 1. `transfer_object` (lines 98-121) | ||
|
|
||
| Transfers a single object to a recipient. The object must allow public transfers. | ||
|
|
||
| **Steps:** | ||
| 1. **Create a ProgrammableTransactionBuilder** - Initialize an empty transaction builder | ||
| 2. **Get full object reference** - Fetch the object from storage and compute its full reference (ID, version, digest, and owner info) | ||
| 3. **Build transfer command** - Call `builder.transfer_object(recipient, full_obj_ref)` which: | ||
| - Creates a pure input for the recipient address | ||
| - Adds the object as an input (handling shared vs owned object args) | ||
| - Emits a `Command::TransferObjects` command | ||
| 4. **Get reference gas price** - Fetch the current gas price from the network | ||
| 5. **Select gas coin** - Find a suitable gas coin from the signer's owned coins that: | ||
| - Is not the object being transferred | ||
| - Has sufficient balance for the gas budget | ||
| - If `gas` is provided, use that coin directly | ||
| 6. **Create TransactionData** - Package everything into a signed transaction | ||
|
|
||
| --- | ||
|
|
||
| ## 2. `transfer_sui` (lines 144-157) | ||
|
|
||
| Transfers SUI coin to a recipient. The SUI object is also used as the gas object. | ||
|
|
||
| **Steps:** | ||
| 1. **Get object reference** - Fetch the SUI coin's reference (ID, version, digest) | ||
| 2. **Get reference gas price** - Fetch the current gas price | ||
| 3. **Create transaction via `TransactionData::new_transfer_sui`** which internally: | ||
| - Creates a ProgrammableTransactionBuilder | ||
| - Calls `builder.transfer_sui(recipient, amount)` which: | ||
| - If `amount` is Some: Splits that amount from GasCoin, then transfers the split coin | ||
| - If `amount` is None: Transfers the entire GasCoin | ||
| - Uses the SUI object as both the coin source and gas payment | ||
|
|
||
| --- | ||
|
|
||
| ## 3. `pay` (lines 171-197) | ||
|
|
||
| Sends `Coin<T>` to multiple recipients with specified amounts. Uses a separate gas object. | ||
|
|
||
| **Steps:** | ||
| 1. **Validate gas not in input coins** - Ensure the gas coin is not in the list of input coins (fails if it is) | ||
| 2. **Get coin references** - Fetch object references for all input coins in parallel | ||
| 3. **Get reference gas price** - Fetch the current gas price | ||
| 4. **Select gas coin** - Find a gas coin not in the input list | ||
| 5. **Create transaction via `TransactionData::new_pay`** which internally: | ||
| - Creates a ProgrammableTransactionBuilder | ||
| - Calls `builder.pay(coins, recipients, amounts)` which: | ||
| - **Merge all input coins into the first coin** - If multiple coins, emit `Command::MergeCoins` to combine them | ||
| - **Split the merged coin** - Emit `Command::SplitCoins` with one split per amount | ||
| - **Transfer split coins** - Group recipients (to minimize transfers if same recipient appears multiple times) and emit `Command::TransferObjects` for each unique recipient | ||
| - Uses the separate gas object for gas payment | ||
|
|
||
| --- | ||
|
|
||
| ## 4. `pay_sui` (lines 222-248) | ||
|
|
||
| Sends SUI coins to multiple recipients. The first input coin is used as gas. | ||
|
|
||
| **Steps:** | ||
| 1. **Validate input not empty** - Ensure at least one coin is provided | ||
| 2. **Get coin references** - Fetch object references for all input coins | ||
| 3. **Extract gas coin** - Remove the first coin to use as gas payment | ||
| 4. **Get reference gas price** - Fetch the current gas price | ||
| 5. **Create transaction via `TransactionData::new_pay_sui`** which: | ||
| - Re-inserts the gas coin at position 0 of the coins vector (so all coins are available) | ||
| - Creates a ProgrammableTransactionBuilder | ||
| - Calls `builder.pay_sui(recipients, amounts)` which: | ||
| - **Uses GasCoin as the source** - The runtime provides access to all input coins via `Argument::GasCoin` | ||
| - **Split coins** - Emit `Command::SplitCoins(GasCoin, amounts)` | ||
| - **Transfer split coins** - Emit `Command::TransferObjects` for each unique recipient | ||
| - After execution: first coin holds residual balance (sum(inputs) - sum(amounts) - gas_cost), other coins are deleted | ||
|
|
||
| --- | ||
|
|
||
| ## 5. `pay_all_sui` (lines 257-281) | ||
|
|
||
| Sends all SUI from input coins to a single recipient. The first input coin is used as gas. | ||
|
|
||
| **Steps:** | ||
| 1. **Validate input not empty** - Ensure at least one coin is provided | ||
| 2. **Get coin references** - Fetch object references for all input coins | ||
| 3. **Extract gas coin** - Remove the first coin to use as gas payment | ||
| 4. **Get reference gas price** - Fetch the current gas price | ||
| 5. **Create transaction via `TransactionData::new_pay_all_sui`** which: | ||
| - Re-inserts the gas coin at position 0 of the coins vector | ||
| - Creates a ProgrammableTransactionBuilder | ||
| - Calls `builder.pay_all_sui(recipient)` which: | ||
| - **Transfer entire GasCoin** - Emits `Command::TransferObjects([GasCoin], recipient)` | ||
| - After execution: The runtime first merges all input coins into the gas coin, then transfers it to the recipient (minus gas cost). All other input coins are deleted. | ||
|
|
||
| --- | ||
|
|
||
| ## 6. `split_coin` (lines 664-694) | ||
|
|
||
| Splits a coin into multiple coins with specified amounts. | ||
|
|
||
| **Steps:** | ||
| 1. **Get coin object** - Fetch the coin and its reference | ||
| 2. **Get coin type** - Extract the coin's type arguments (e.g., `Coin<SUI>` -> `SUI`) | ||
| 3. **Get reference gas price** - Fetch the current gas price | ||
| 4. **Select gas coin** - Find a gas coin that is not the coin being split | ||
| 5. **Create Move call transaction** - Calls `sui::pay::split_vec(coin, amounts)`: | ||
| - Input 0: The coin object | ||
| - Input 1: BCS-encoded vector of split amounts | ||
| - Newly split coins are created; the original coin keeps the remainder | ||
|
|
||
| --- | ||
|
|
||
| ## 7. `split_coin_equal` (lines 697-727) | ||
|
|
||
| Splits a coin into N equal-sized coins. | ||
|
|
||
| **Steps:** | ||
| 1. **Get coin object** - Fetch the coin and its reference | ||
| 2. **Get coin type** - Extract the coin's type arguments | ||
| 3. **Get reference gas price** - Fetch the current gas price | ||
| 4. **Select gas coin** - Find a gas coin that is not the coin being split | ||
| 5. **Create Move call transaction** - Calls `sui::pay::split_n(coin, count)`: | ||
| - Input 0: The coin object | ||
| - Input 1: BCS-encoded split count | ||
| - Creates N coins of equal value from the original | ||
|
|
||
| --- | ||
|
|
||
| ## 8. `merge_coins` (lines 755-792) | ||
|
|
||
| Merges two coins into one. | ||
|
|
||
| **Steps:** | ||
| 1. **Get primary coin** - Fetch the target coin object and its reference | ||
| 2. **Get coin to merge** - Fetch the source coin's reference | ||
| 3. **Get coin type** - Extract the coin's type arguments | ||
| 4. **Get reference gas price** - Fetch the current gas price | ||
| 5. **Select gas coin** - Find a gas coin that is neither the primary nor the coin being merged | ||
| 6. **Create Move call transaction** - Calls `sui::pay::join(target, source)`: | ||
| - Input 0: Primary coin (receives the balance) | ||
| - Input 1: Coin to merge (gets destroyed) | ||
| - The primary coin's balance increases; the merged coin is deleted | ||
|
|
||
| --- | ||
|
|
||
| ## Key Helper: `select_gas` (lines 56-85) | ||
|
|
||
| Used by most methods to find a suitable gas coin. | ||
|
|
||
| **Steps:** | ||
| 1. **Validate gas budget** - Ensure budget >= reference gas price | ||
| 2. **If gas provided** - Use the specified gas object directly | ||
| 3. **If gas not provided** - Query all owned `GasCoin` objects from the signer, find the first one that: | ||
| - Is not in the list of input objects for this transaction | ||
| - Has balance >= gas budget | ||
| 4. **Error if no suitable gas** - Suggest using `pay-sui` or `transfer-sui` if no separate gas coin is available | ||
|
|
||
| --- | ||
|
|
||
| ## Summary Table | ||
|
|
||
| | Method | Gas Source | Coin Merging | Use Case | | ||
| |--------|-----------|--------------|----------| | ||
| | `transfer_object` | Separate gas coin | N/A | Transfer any object | | ||
| | `transfer_sui` | Same as transfer coin | N/A | Transfer SUI (simple) | | ||
| | `pay` | Separate gas coin | Yes (input coins merged) | Pay multiple recipients with any coin type | | ||
| | `pay_sui` | First input coin | Yes (via runtime) | Pay multiple recipients with SUI | | ||
| | `pay_all_sui` | First input coin | Yes (via runtime) | Send all SUI to one recipient | | ||
| | `split_coin` | Separate gas coin | N/A | Split coin by amounts | | ||
| | `split_coin_equal` | Separate gas coin | N/A | Split coin into N equal parts | | ||
| | `merge_coins` | Separate gas coin | Yes (2 coins) | Combine two coins | | ||
|
|
||
| ## Related Files | ||
|
|
||
| - `crates/sui-transaction-builder/src/lib.rs` - Main implementation | ||
| - `crates/sui-types/src/programmable_transaction_builder.rs` - Low-level PTB commands | ||
| - `crates/sui-types/src/transaction.rs` - TransactionData constructors | ||
| - `crates/sui-json-rpc/src/transaction_builder_api.rs` - RPC wrapper |
Contributor
There was a problem hiding this comment.
Suggested change
| # Transfer and Pay Methods in TransactionBuilder | |
| This document describes the step-by-step implementation of transfer and pay methods in `crates/sui-transaction-builder/src/lib.rs`. | |
| ## Address Balance Support | |
| Address balances can be used as a funding source by passing **coin reservation objects** to these methods. Callers are responsible for: | |
| 1. Creating a `FundsWithdrawalArg` to reserve the required funds from their address balance | |
| 2. Using `coin::redeem_funds` to convert the withdrawal into a coin object | |
| 3. Passing the resulting coin object (or its ObjectID) to the transaction builder methods | |
| The transaction builder treats coin reservation objects the same as regular coin objects. This approach gives callers full control over when and how address balances are used. | |
| ## 1. `transfer_object` (lines 98-121) | |
| Transfers a single object to a recipient. The object must allow public transfers. | |
| **Steps:** | |
| 1. **Create a ProgrammableTransactionBuilder** - Initialize an empty transaction builder | |
| 2. **Get full object reference** - Fetch the object from storage and compute its full reference (ID, version, digest, and owner info) | |
| 3. **Build transfer command** - Call `builder.transfer_object(recipient, full_obj_ref)` which: | |
| - Creates a pure input for the recipient address | |
| - Adds the object as an input (handling shared vs owned object args) | |
| - Emits a `Command::TransferObjects` command | |
| 4. **Get reference gas price** - Fetch the current gas price from the network | |
| 5. **Select gas coin** - Find a suitable gas coin from the signer's owned coins that: | |
| - Is not the object being transferred | |
| - Has sufficient balance for the gas budget | |
| - If `gas` is provided, use that coin directly | |
| 6. **Create TransactionData** - Package everything into a signed transaction | |
| --- | |
| ## 2. `transfer_sui` (lines 144-157) | |
| Transfers SUI coin to a recipient. The SUI object is also used as the gas object. | |
| **Steps:** | |
| 1. **Get object reference** - Fetch the SUI coin's reference (ID, version, digest) | |
| 2. **Get reference gas price** - Fetch the current gas price | |
| 3. **Create transaction via `TransactionData::new_transfer_sui`** which internally: | |
| - Creates a ProgrammableTransactionBuilder | |
| - Calls `builder.transfer_sui(recipient, amount)` which: | |
| - If `amount` is Some: Splits that amount from GasCoin, then transfers the split coin | |
| - If `amount` is None: Transfers the entire GasCoin | |
| - Uses the SUI object as both the coin source and gas payment | |
| --- | |
| ## 3. `pay` (lines 171-197) | |
| Sends `Coin<T>` to multiple recipients with specified amounts. Uses a separate gas object. | |
| **Steps:** | |
| 1. **Validate gas not in input coins** - Ensure the gas coin is not in the list of input coins (fails if it is) | |
| 2. **Get coin references** - Fetch object references for all input coins in parallel | |
| 3. **Get reference gas price** - Fetch the current gas price | |
| 4. **Select gas coin** - Find a gas coin not in the input list | |
| 5. **Create transaction via `TransactionData::new_pay`** which internally: | |
| - Creates a ProgrammableTransactionBuilder | |
| - Calls `builder.pay(coins, recipients, amounts)` which: | |
| - **Merge all input coins into the first coin** - If multiple coins, emit `Command::MergeCoins` to combine them | |
| - **Split the merged coin** - Emit `Command::SplitCoins` with one split per amount | |
| - **Transfer split coins** - Group recipients (to minimize transfers if same recipient appears multiple times) and emit `Command::TransferObjects` for each unique recipient | |
| - Uses the separate gas object for gas payment | |
| --- | |
| ## 4. `pay_sui` (lines 222-248) | |
| Sends SUI coins to multiple recipients. The first input coin is used as gas. | |
| **Steps:** | |
| 1. **Validate input not empty** - Ensure at least one coin is provided | |
| 2. **Get coin references** - Fetch object references for all input coins | |
| 3. **Extract gas coin** - Remove the first coin to use as gas payment | |
| 4. **Get reference gas price** - Fetch the current gas price | |
| 5. **Create transaction via `TransactionData::new_pay_sui`** which: | |
| - Re-inserts the gas coin at position 0 of the coins vector (so all coins are available) | |
| - Creates a ProgrammableTransactionBuilder | |
| - Calls `builder.pay_sui(recipients, amounts)` which: | |
| - **Uses GasCoin as the source** - The runtime provides access to all input coins via `Argument::GasCoin` | |
| - **Split coins** - Emit `Command::SplitCoins(GasCoin, amounts)` | |
| - **Transfer split coins** - Emit `Command::TransferObjects` for each unique recipient | |
| - After execution: first coin holds residual balance (sum(inputs) - sum(amounts) - gas_cost), other coins are deleted | |
| --- | |
| ## 5. `pay_all_sui` (lines 257-281) | |
| Sends all SUI from input coins to a single recipient. The first input coin is used as gas. | |
| **Steps:** | |
| 1. **Validate input not empty** - Ensure at least one coin is provided | |
| 2. **Get coin references** - Fetch object references for all input coins | |
| 3. **Extract gas coin** - Remove the first coin to use as gas payment | |
| 4. **Get reference gas price** - Fetch the current gas price | |
| 5. **Create transaction via `TransactionData::new_pay_all_sui`** which: | |
| - Re-inserts the gas coin at position 0 of the coins vector | |
| - Creates a ProgrammableTransactionBuilder | |
| - Calls `builder.pay_all_sui(recipient)` which: | |
| - **Transfer entire GasCoin** - Emits `Command::TransferObjects([GasCoin], recipient)` | |
| - After execution: The runtime first merges all input coins into the gas coin, then transfers it to the recipient (minus gas cost). All other input coins are deleted. | |
| --- | |
| ## 6. `split_coin` (lines 664-694) | |
| Splits a coin into multiple coins with specified amounts. | |
| **Steps:** | |
| 1. **Get coin object** - Fetch the coin and its reference | |
| 2. **Get coin type** - Extract the coin's type arguments (e.g., `Coin<SUI>` -> `SUI`) | |
| 3. **Get reference gas price** - Fetch the current gas price | |
| 4. **Select gas coin** - Find a gas coin that is not the coin being split | |
| 5. **Create Move call transaction** - Calls `sui::pay::split_vec(coin, amounts)`: | |
| - Input 0: The coin object | |
| - Input 1: BCS-encoded vector of split amounts | |
| - Newly split coins are created; the original coin keeps the remainder | |
| --- | |
| ## 7. `split_coin_equal` (lines 697-727) | |
| Splits a coin into N equal-sized coins. | |
| **Steps:** | |
| 1. **Get coin object** - Fetch the coin and its reference | |
| 2. **Get coin type** - Extract the coin's type arguments | |
| 3. **Get reference gas price** - Fetch the current gas price | |
| 4. **Select gas coin** - Find a gas coin that is not the coin being split | |
| 5. **Create Move call transaction** - Calls `sui::pay::split_n(coin, count)`: | |
| - Input 0: The coin object | |
| - Input 1: BCS-encoded split count | |
| - Creates N coins of equal value from the original | |
| --- | |
| ## 8. `merge_coins` (lines 755-792) | |
| Merges two coins into one. | |
| **Steps:** | |
| 1. **Get primary coin** - Fetch the target coin object and its reference | |
| 2. **Get coin to merge** - Fetch the source coin's reference | |
| 3. **Get coin type** - Extract the coin's type arguments | |
| 4. **Get reference gas price** - Fetch the current gas price | |
| 5. **Select gas coin** - Find a gas coin that is neither the primary nor the coin being merged | |
| 6. **Create Move call transaction** - Calls `sui::pay::join(target, source)`: | |
| - Input 0: Primary coin (receives the balance) | |
| - Input 1: Coin to merge (gets destroyed) | |
| - The primary coin's balance increases; the merged coin is deleted | |
| --- | |
| ## Key Helper: `select_gas` (lines 56-85) | |
| Used by most methods to find a suitable gas coin. | |
| **Steps:** | |
| 1. **Validate gas budget** - Ensure budget >= reference gas price | |
| 2. **If gas provided** - Use the specified gas object directly | |
| 3. **If gas not provided** - Query all owned `GasCoin` objects from the signer, find the first one that: | |
| - Is not in the list of input objects for this transaction | |
| - Has balance >= gas budget | |
| 4. **Error if no suitable gas** - Suggest using `pay-sui` or `transfer-sui` if no separate gas coin is available | |
| --- | |
| ## Summary Table | |
| | Method | Gas Source | Coin Merging | Use Case | | |
| |--------|-----------|--------------|----------| | |
| | `transfer_object` | Separate gas coin | N/A | Transfer any object | | |
| | `transfer_sui` | Same as transfer coin | N/A | Transfer SUI (simple) | | |
| | `pay` | Separate gas coin | Yes (input coins merged) | Pay multiple recipients with any coin type | | |
| | `pay_sui` | First input coin | Yes (via runtime) | Pay multiple recipients with SUI | | |
| | `pay_all_sui` | First input coin | Yes (via runtime) | Send all SUI to one recipient | | |
| | `split_coin` | Separate gas coin | N/A | Split coin by amounts | | |
| | `split_coin_equal` | Separate gas coin | N/A | Split coin into N equal parts | | |
| | `merge_coins` | Separate gas coin | Yes (2 coins) | Combine two coins | | |
| ## Related Files | |
| - `crates/sui-transaction-builder/src/lib.rs` - Main implementation | |
| - `crates/sui-types/src/programmable_transaction_builder.rs` - Low-level PTB commands | |
| - `crates/sui-types/src/transaction.rs` - TransactionData constructors | |
| - `crates/sui-json-rpc/src/transaction_builder_api.rs` - RPC wrapper | |
| --- | |
| title: Transfer and Pay Methods in TransactionBuilder | |
| description: Learn how transfer and pay methods work in the Sui transaction builder, including gas selection, coin merging, and address balance support. | |
| keywords: [transfer, pay, transaction builder, gas coin, coin merging, split coin, merge coins, address balance, PTB, programmable transaction block] | |
| --- | |
| This topic describes the implementation of transfer and pay methods in `crates/sui-transaction-builder/src/lib.rs`. | |
| ## Address balance support | |
| You can use address balances as a funding source by passing coin reservation objects to these methods. You are responsible for: | |
| 1. Creating a `FundsWithdrawalArg` to reserve the required funds from the address balance. | |
| 2. Using `coin::redeem_funds` to convert the withdrawal into a coin object. | |
| 3. Passing the resulting coin object (or its `ObjectID`) to the transaction builder methods. | |
| The transaction builder treats coin reservation objects the same as regular coin objects. This approach gives you full control over when and how address balances are used. | |
| ## `transfer_object` | |
| Transfers a single object to a recipient. The object must allow public transfers. | |
| The method performs the following operations: | |
| 1. Creates a `ProgrammableTransactionBuilder`. | |
| 2. Fetches the object from storage and computes its full reference (ID, version, digest, and owner information). | |
| 3. Calls `builder.transfer_object(recipient, full_obj_ref)`, which: | |
| - Creates a pure input for the recipient address. | |
| - Adds the object as an input (handling shared compared to owned object arguments). | |
| - Emits a `Command::TransferObjects` command. | |
| 4. Fetches the current reference gas price from the network. | |
| 5. Selects a gas coin from the signer's owned coins that: | |
| - Is not the object being transferred. | |
| - Has sufficient balance for the gas budget. | |
| - If `gas` is provided, uses that coin directly. | |
| 6. Packages everything into a `TransactionData`. | |
| ## `transfer_sui` | |
| Transfers SUI to a recipient. The SUI object is also used as the gas object. | |
| The method performs the following operations: | |
| 1. Fetches the SUI coin reference (ID, version, digest). | |
| 2. Fetches the current reference gas price. | |
| 3. Creates a transaction through `TransactionData::new_transfer_sui`, which internally: | |
| - Creates a `ProgrammableTransactionBuilder`. | |
| - Calls `builder.transfer_sui(recipient, amount)`, which: | |
| - If `amount` is `Some`: Splits that amount from `GasCoin`, then transfers the split coin. | |
| - If `amount` is `None`: Transfers the entire `GasCoin`. | |
| - Uses the SUI object as both the coin source and gas payment. | |
| ## `pay` | |
| Sends `Coin<T>` to multiple recipients with specified amounts. Uses a separate gas object. | |
| The method performs the following operations: | |
| 1. Validates that the gas coin is not in the list of input coins. Fails if it is. | |
| 2. Fetches object references for all input coins in parallel. | |
| 3. Fetches the current reference gas price. | |
| 4. Selects a gas coin not in the input list. | |
| 5. Creates a transaction through `TransactionData::new_pay`, which internally: | |
| - Creates a `ProgrammableTransactionBuilder`. | |
| - Calls `builder.pay(coins, recipients, amounts)`, which: | |
| - Merges all input coins into the first coin. If multiple coins exist, emits `Command::MergeCoins` to combine them. | |
| - Emits `Command::SplitCoins` with one split per amount. | |
| - Groups recipients (to minimize transfers if the same recipient appears multiple times) and emits `Command::TransferObjects` for each unique recipient. | |
| - Uses the separate gas object for gas payment. | |
| ## `pay_sui` | |
| Sends SUI to multiple recipients. The first input coin is used as gas. | |
| The method performs the following operations: | |
| 1. Validates that at least one coin is provided. | |
| 2. Fetches object references for all input coins. | |
| 3. Removes the first coin to use as gas payment. | |
| 4. Fetches the current reference gas price. | |
| 5. Creates a transaction through `TransactionData::new_pay_sui`, which: | |
| - Re-inserts the gas coin at position 0 of the coins vector (so all coins are available). | |
| - Creates a `ProgrammableTransactionBuilder`. | |
| - Calls `builder.pay_sui(recipients, amounts)`, which: | |
| - Uses `Argument::GasCoin` as the source. | |
| - Emits `Command::SplitCoins(GasCoin, amounts)`. | |
| - Emits `Command::TransferObjects` for each unique recipient. | |
| - After execution: | |
| - The first coin holds the residual balance (sum of inputs minus sum of amounts minus gas cost). | |
| - The other coins are deleted. | |
| ## `pay_all_sui` | |
| Sends all SUI from input coins to a single recipient. The first input coin is used as gas. | |
| The method performs the following operations: | |
| 1. Validates that at least one coin is provided. | |
| 2. Fetches object references for all input coins. | |
| 3. Removes the first coin to use as gas payment. | |
| 4. Fetches the current reference gas price. | |
| 5. Creates a transaction through `TransactionData::new_pay_all_sui`, which: | |
| - Re-inserts the gas coin at position 0 of the coins vector. | |
| - Creates a `ProgrammableTransactionBuilder`. | |
| - Calls `builder.pay_all_sui(recipient)`, which: | |
| - Emits `Command::TransferObjects([GasCoin], recipient)`. | |
| - The runtime first merges all input coins into the gas coin, then transfers it to the recipient (minus gas cost). All other input coins are deleted. | |
| ## `split_coin` | |
| Splits a coin into multiple coins with specified amounts. | |
| The method performs the following operations: | |
| 1. Fetches the coin object and its reference. | |
| 2. Extracts the coin type arguments (for example, `Coin<SUI>` resolves to `SUI`). | |
| 3. Fetches the current reference gas price. | |
| 4. Selects a gas coin that is not the coin being split. | |
| 5. Creates a Move call transaction that calls `sui::pay::split_vec(coin, amounts)`: | |
| - Input 0: The coin object. | |
| - Input 1: BCS-encoded vector of split amounts. | |
| - The newly split coins are created and the original coin keeps the remainder. | |
| ## `split_coin_equal` | |
| Splits a coin into N equal-sized coins. | |
| The method performs the following operations: | |
| 1. Fetches the coin object and its reference. | |
| 2. Extracts the coin type arguments. | |
| 3. Fetches the current reference gas price. | |
| 4. Selects a gas coin that is not the coin being split. | |
| 5. Creates a Move call transaction that calls `sui::pay::split_n(coin, count)`: | |
| - Input 0: The coin object. | |
| - Input 1: BCS-encoded split count. | |
| - Creates N coins of equal value from the original. | |
| ## `merge_coins` | |
| Merges two coins into one. | |
| The method performs the following operations: | |
| 1. Fetches the target coin object and its reference. | |
| 2. Fetches the source coin reference. | |
| 3. Extracts the coin type arguments. | |
| 4. Fetches the current reference gas price. | |
| 5. Selects a gas coin that is neither the target nor the source coin. | |
| 6. Creates a Move call transaction that calls `sui::pay::join(target, source)`: | |
| - Input 0: The target coin (receives the balance). | |
| - Input 1: The source coin (gets destroyed). | |
| - The target coin balance increases and the source coin is deleted. | |
| ## Gas selection helper | |
| The `select_gas` helper (used by most methods) finds a suitable gas coin through the following logic: | |
| 1. Validates that the gas budget is greater than or equal to the reference gas price. | |
| 2. If `gas` is provided, uses the specified gas object directly. | |
| 3. If `gas` is not provided, queries all owned `GasCoin` objects from the signer and finds the first one that: | |
| - Is not in the list of input objects for the transaction. | |
| - Has a balance greater than or equal to the gas budget. | |
| 4. Returns an error if no suitable gas coin exists. The error suggests using `pay-sui` or `transfer-sui` if no separate gas coin is available. | |
| ## Method comparison | |
| | **Method** | **Gas source** | **Coin merging** | **Use case** | | |
| |--------|-----------|--------------|----------| | |
| | `transfer_object` | Separate gas coin | N/A | Transfer any object | | |
| | `transfer_sui` | Same as transfer coin | N/A | Transfer SUI | | |
| | `pay` | Separate gas coin | Yes (input coins merged) | Pay multiple recipients with any coin type | | |
| | `pay_sui` | First input coin | Yes (through runtime) | Pay multiple recipients with SUI | | |
| | `pay_all_sui` | First input coin | Yes (through runtime) | Send all SUI to one recipient | | |
| | `split_coin` | Separate gas coin | N/A | Split coin by amounts | | |
| | `split_coin_equal` | Separate gas coin | N/A | Split coin into N equal parts | | |
| | `merge_coins` | Separate gas coin | Yes (2 coins) | Combine two coins | | |
| ## Related files | |
| The following source files contain the relevant implementations: | |
| - `crates/sui-transaction-builder/src/lib.rs`: Main implementation | |
| - `crates/sui-types/src/programmable_transaction_builder.rs`: Low-level PTB commands | |
| - `crates/sui-types/src/transaction.rs`: `TransactionData` constructors | |
| - `crates/sui-json-rpc/src/transaction_builder_api.rs`: RPC wrapper |
f32cee7 to
2b7aa07
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
TransactionBuilderThis PR is stacked on top of #25818 (integrate-coin-smashing).
Test plan
🤖 Generated with Claude Code