diff --git a/bindings/core/src/method/client.rs b/bindings/core/src/method/client.rs index 87da322938..6ab5784327 100644 --- a/bindings/core/src/method/client.rs +++ b/bindings/core/src/method/client.rs @@ -17,7 +17,7 @@ use iota_sdk::{ address::{Bech32Address, Hrp}, output::{ dto::OutputDto, feature::Feature, unlock_condition::dto::UnlockConditionDto, AccountId, AnchorId, - DelegationId, FoundryId, NativeToken, NftId, OutputId, TokenScheme, + DelegationId, FoundryId, NftId, OutputId, TokenScheme, }, payload::{dto::PayloadDto, signed_transaction::TransactionId}, BlockDto, BlockId, IssuerId, @@ -43,7 +43,6 @@ pub enum ClientMethod { // TODO: Determine if `default` is wanted here #[serde(default, with = "string")] mana: u64, - native_tokens: Option>, account_id: AccountId, foundry_counter: Option, unlock_conditions: Vec, @@ -61,7 +60,6 @@ pub enum ClientMethod { // TODO: Determine if `default` is wanted here #[serde(default, with = "string")] mana: u64, - native_tokens: Option>, unlock_conditions: Vec, features: Option>, }, @@ -73,7 +71,6 @@ pub enum ClientMethod { // If not provided, minimum amount will be used #[serde(default, with = "option_string")] amount: Option, - native_tokens: Option>, serial_number: u32, token_scheme: TokenScheme, unlock_conditions: Vec, @@ -91,7 +88,6 @@ pub enum ClientMethod { // TODO: Determine if `default` is wanted here #[serde(default, with = "string")] mana: u64, - native_tokens: Option>, nft_id: NftId, unlock_conditions: Vec, features: Option>, diff --git a/bindings/core/src/method/wallet.rs b/bindings/core/src/method/wallet.rs index f65467ae52..36f280a558 100644 --- a/bindings/core/src/method/wallet.rs +++ b/bindings/core/src/method/wallet.rs @@ -26,7 +26,7 @@ use iota_sdk::{ }, wallet::{ ClientOptions, ConsolidationParams, CreateAccountParams, CreateNativeTokenParams, FilterOptions, MintNftParams, - OutputParams, OutputsToClaim, SendNativeTokensParams, SendNftParams, SendParams, SyncOptions, + OutputParams, OutputsToClaim, SendNativeTokenParams, SendNftParams, SendParams, SyncOptions, TransactionOptions, }, U256, @@ -295,7 +295,7 @@ pub enum WalletMethod { /// Prepare to send native tokens. /// Expected response: [`PreparedTransaction`](crate::Response::PreparedTransaction) PrepareSendNativeTokens { - params: Vec, + params: Vec, options: Option, }, /// Prepare to Send nft. diff --git a/bindings/core/src/method_handler/client.rs b/bindings/core/src/method_handler/client.rs index 53f65631cd..d68fea59b3 100644 --- a/bindings/core/src/method_handler/client.rs +++ b/bindings/core/src/method_handler/client.rs @@ -59,7 +59,6 @@ pub(crate) async fn call_client_method_internal(client: &Client, method: ClientM ClientMethod::BuildAccountOutput { amount, mana, - native_tokens, account_id, foundry_counter, unlock_conditions, @@ -73,7 +72,6 @@ pub(crate) async fn call_client_method_internal(client: &Client, method: ClientM OutputBuilderAmount::MinimumAmount(client.get_storage_score_parameters().await?) }, mana, - native_tokens, &account_id, foundry_counter, unlock_conditions, @@ -86,7 +84,6 @@ pub(crate) async fn call_client_method_internal(client: &Client, method: ClientM ClientMethod::BuildBasicOutput { amount, mana, - native_tokens, unlock_conditions, features, } => { @@ -97,7 +94,6 @@ pub(crate) async fn call_client_method_internal(client: &Client, method: ClientM OutputBuilderAmount::MinimumAmount(client.get_storage_score_parameters().await?) }, mana, - native_tokens, unlock_conditions, features, )?); @@ -106,7 +102,6 @@ pub(crate) async fn call_client_method_internal(client: &Client, method: ClientM } ClientMethod::BuildFoundryOutput { amount, - native_tokens, serial_number, token_scheme, unlock_conditions, @@ -119,7 +114,6 @@ pub(crate) async fn call_client_method_internal(client: &Client, method: ClientM } else { OutputBuilderAmount::MinimumAmount(client.get_storage_score_parameters().await?) }, - native_tokens, serial_number, token_scheme, unlock_conditions, @@ -132,7 +126,6 @@ pub(crate) async fn call_client_method_internal(client: &Client, method: ClientM ClientMethod::BuildNftOutput { amount, mana, - native_tokens, nft_id, unlock_conditions, features, @@ -145,7 +138,6 @@ pub(crate) async fn call_client_method_internal(client: &Client, method: ClientM OutputBuilderAmount::MinimumAmount(client.get_storage_score_parameters().await?) }, mana, - native_tokens, &nft_id, unlock_conditions, features, diff --git a/bindings/nodejs/examples/how_tos/native_tokens/send.ts b/bindings/nodejs/examples/how_tos/native_tokens/send.ts index a42a1459b4..4f832d8a56 100644 --- a/bindings/nodejs/examples/how_tos/native_tokens/send.ts +++ b/bindings/nodejs/examples/how_tos/native_tokens/send.ts @@ -1,17 +1,17 @@ // Copyright 2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { SendNativeTokensParams } from '@iota/sdk'; +import { SendNativeTokenParams } from '@iota/sdk'; import { getUnlockedWallet } from '../../wallet/common'; // The native token amount to send. const SEND_NATIVE_TOKEN_AMOUNT = BigInt(10); -// The address to send the tokens to +// The address to send the token to const RECV_ADDRESS = 'rms1qpszqzadsym6wpppd6z037dvlejmjuke7s24hm95s9fg9vpua7vluaw60xu'; -// In this example we will send native tokens. +// In this example we will send a native token. // // Make sure that `STRONGHOLD_SNAPSHOT_PATH` and `WALLET_DB_PATH` already exist by // running the `how_tos/accounts_and_addresses/create-wallet` example! @@ -32,10 +32,10 @@ async function run() { )?.tokenId; if (tokenId != null) { - const outputs: SendNativeTokensParams[] = [ + const outputs: SendNativeTokenParams[] = [ { address: RECV_ADDRESS, - nativeTokens: [[tokenId, SEND_NATIVE_TOKEN_AMOUNT]], + nativeToken: [tokenId, SEND_NATIVE_TOKEN_AMOUNT], }, ]; diff --git a/bindings/nodejs/lib/types/wallet/address.ts b/bindings/nodejs/lib/types/wallet/address.ts index c88fbf5fde..18845f1d0d 100644 --- a/bindings/nodejs/lib/types/wallet/address.ts +++ b/bindings/nodejs/lib/types/wallet/address.ts @@ -35,12 +35,12 @@ export interface SendParams { expiration?: SlotIndex; } -/** Address with native tokens */ -export interface SendNativeTokensParams { +/** Address with native token */ +export interface SendNativeTokenParams { /** The Bech32 address. */ address: Bech32Address; - /** The Native Tokens to send. */ - nativeTokens: [TokenId, u256][]; + /** The Native Token to send. */ + nativeToken: [TokenId, u256]; /** * Bech32 encoded address, to which the storage deposit will be returned. * Default will use the address of the wallet. diff --git a/bindings/nodejs/lib/types/wallet/bridge/account.ts b/bindings/nodejs/lib/types/wallet/bridge/account.ts index a347917568..26c33803ac 100644 --- a/bindings/nodejs/lib/types/wallet/bridge/account.ts +++ b/bindings/nodejs/lib/types/wallet/bridge/account.ts @@ -3,7 +3,7 @@ import type { SendParams, - SendNativeTokensParams, + SendNativeTokenParams, SendNftParams, GenerateAddressOptions, } from '../address'; @@ -258,7 +258,7 @@ export type __SendWithParamsMethod__ = { export type __PrepareSendNativeTokensMethod__ = { name: 'prepareSendNativeTokens'; data: { - params: SendNativeTokensParams[]; + params: SendNativeTokenParams[]; options?: TransactionOptions; }; }; diff --git a/bindings/nodejs/lib/types/wallet/bridge/wallet.ts b/bindings/nodejs/lib/types/wallet/bridge/wallet.ts index 63dc52caa8..895a9aeeaf 100644 --- a/bindings/nodejs/lib/types/wallet/bridge/wallet.ts +++ b/bindings/nodejs/lib/types/wallet/bridge/wallet.ts @@ -9,7 +9,7 @@ import type { } from '../../client'; import type { SendParams, - SendNativeTokensParams, + SendNativeTokenParams, SendNftParams, } from '../address'; import type { OutputParams } from '../output-params'; @@ -337,7 +337,7 @@ export type __SendWithParamsMethod__ = { export type __PrepareSendNativeTokensMethod__ = { name: 'prepareSendNativeTokens'; data: { - params: SendNativeTokensParams[]; + params: SendNativeTokenParams[]; options?: TransactionOptions; }; }; diff --git a/bindings/nodejs/lib/types/wallet/output-params.ts b/bindings/nodejs/lib/types/wallet/output-params.ts index 1e9be9073d..eaba4bb4d0 100644 --- a/bindings/nodejs/lib/types/wallet/output-params.ts +++ b/bindings/nodejs/lib/types/wallet/output-params.ts @@ -24,8 +24,6 @@ export interface OutputParams { /** Assets to include in the output. */ export interface Assets { - /** Native Token assets to include. */ - nativeTokens?: INativeToken[]; /** The NFT to include. */ nftId?: HexEncodedString; } @@ -40,6 +38,8 @@ export interface Features { sender?: string; /** An Issuer feature to include. */ issuer?: string; + /** Native Token to include. */ + nativeToken?: INativeToken; } /** Time unlocks to include in the output. */ diff --git a/bindings/nodejs/lib/wallet/wallet.ts b/bindings/nodejs/lib/wallet/wallet.ts index 29e3fdb0dc..071d0b3667 100644 --- a/bindings/nodejs/lib/wallet/wallet.ts +++ b/bindings/nodejs/lib/wallet/wallet.ts @@ -6,7 +6,7 @@ import { Balance, SyncOptions, SendParams, - SendNativeTokensParams, + SendNativeTokenParams, SendNftParams, AccountOutputParams, FilterOptions, @@ -1325,7 +1325,7 @@ export class Wallet { * @returns The transaction. */ async sendNativeTokens( - params: SendNativeTokensParams[], + params: SendNativeTokenParams[], transactionOptions?: TransactionOptions, ): Promise { return ( @@ -1342,7 +1342,7 @@ export class Wallet { * @returns The prepared transaction. */ async prepareSendNativeTokens( - params: SendNativeTokensParams[], + params: SendNativeTokenParams[], transactionOptions?: TransactionOptions, ): Promise { const response = await this.methodHandler.callMethod({ diff --git a/bindings/nodejs/package-lock.json b/bindings/nodejs/package-lock.json index 4094d96ed9..eca7eb77be 100644 --- a/bindings/nodejs/package-lock.json +++ b/bindings/nodejs/package-lock.json @@ -5930,18 +5930,6 @@ "semver": "bin/semver" } }, - "node_modules/node-ninja/node_modules/tar": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.2.tgz", - "integrity": "sha512-FCEhQ/4rE1zYv9rYXJw/msRqsnmlje5jHP6huWeBZ704jUTy02c5AZyWujpMR1ax6mVw9NyJMfuK2CMDWVIfgA==", - "deprecated": "This version of tar is no longer supported, and will not receive security updates. Please upgrade asap.", - "dev": true, - "dependencies": { - "block-stream": "*", - "fstream": "^1.0.12", - "inherits": "2" - } - }, "node_modules/node-ninja/node_modules/which": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", @@ -13025,7 +13013,7 @@ "request": "2", "rimraf": "2", "semver": "2.x || 3.x || 4 || 5", - "tar": "^4.4.19", + "tar": "^2.0.0", "which": "1" }, "dependencies": { @@ -13077,16 +13065,6 @@ "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "dev": true }, - "tar": { - "version": "https://registry.npmjs.org/tar/-/tar-2.2.2.tgz", - "integrity": "sha512-FCEhQ/4rE1zYv9rYXJw/msRqsnmlje5jHP6huWeBZ704jUTy02c5AZyWujpMR1ax6mVw9NyJMfuK2CMDWVIfgA==", - "dev": true, - "requires": { - "block-stream": "*", - "fstream": "^1.0.12", - "inherits": "2" - } - }, "which": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", diff --git a/bindings/nodejs/yarn.lock b/bindings/nodejs/yarn.lock index ba918689f7..1914f42d80 100644 --- a/bindings/nodejs/yarn.lock +++ b/bindings/nodejs/yarn.lock @@ -2201,9 +2201,9 @@ fs.realpath@^1.0.0: integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== fsevents@^2.3.2: - version "2.3.3" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" - integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== + version "2.3.2" + resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz" + integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== fstream@^1.0.0, fstream@~1.0.10: version "1.0.12" diff --git a/bindings/python/examples/how_tos/native_tokens/send.py b/bindings/python/examples/how_tos/native_tokens/send.py index 5c5b6b623f..7c854fe215 100644 --- a/bindings/python/examples/how_tos/native_tokens/send.py +++ b/bindings/python/examples/how_tos/native_tokens/send.py @@ -2,7 +2,7 @@ from dotenv import load_dotenv -from iota_sdk import SendNativeTokensParams, Wallet +from iota_sdk import SendNativeTokenParams, Wallet load_dotenv() @@ -24,12 +24,12 @@ wallet.set_stronghold_password(os.environ["STRONGHOLD_PASSWORD"]) -outputs = [SendNativeTokensParams( +outputs = [SendNativeTokenParams( "rms1qpszqzadsym6wpppd6z037dvlejmjuke7s24hm95s9fg9vpua7vluaw60xu", - [( + ( token.token_id, hex(10) - )], + ), )] transaction = account.send_native_tokens(outputs, None) diff --git a/bindings/python/iota_sdk/types/output_params.py b/bindings/python/iota_sdk/types/output_params.py index 5229c2a9f2..b5b896b61b 100644 --- a/bindings/python/iota_sdk/types/output_params.py +++ b/bindings/python/iota_sdk/types/output_params.py @@ -15,7 +15,6 @@ class Assets(): """Assets for OutputParams. """ - native_tokens: Optional[List[NativeToken]] = None nft_id: Optional[HexStr] = None @@ -28,6 +27,7 @@ class Features(): metadata: Optional[HexStr] = None issuer: Optional[str] = None sender: Optional[str] = None + native_token: Optional[NativeToken] = None @json diff --git a/bindings/python/iota_sdk/types/send_params.py b/bindings/python/iota_sdk/types/send_params.py index c8f47f5e0d..6bcccd9c2e 100644 --- a/bindings/python/iota_sdk/types/send_params.py +++ b/bindings/python/iota_sdk/types/send_params.py @@ -32,17 +32,17 @@ class SendParams(): @json @dataclass -class SendNativeTokensParams(): - """Parameters for sending native tokens +class SendNativeTokenParams(): + """Parameters for sending a native token Attributes: address: The address to send to. - native_tokens: The native tokens to send. - return_address: The address to return the native tokens to if not claimed. - expiration: The expiration timestamp until native tokens can be claimed. + native_token: The native token to send. + return_address: The address to return the native token to if not claimed. + expiration: The expiration timestamp until the native token can be claimed. """ address: str - native_tokens: List[NativeToken] + native_token: NativeToken return_address: Optional[str] = None expiration: Optional[int] = None diff --git a/bindings/python/iota_sdk/wallet/account.py b/bindings/python/iota_sdk/wallet/account.py index 1d0a463097..3bc91c0181 100644 --- a/bindings/python/iota_sdk/wallet/account.py +++ b/bindings/python/iota_sdk/wallet/account.py @@ -19,7 +19,7 @@ from iota_sdk.types.output import BasicOutput, NftOutput, Output, deserialize_output from iota_sdk.types.output_params import OutputParams from iota_sdk.types.transaction_data import PreparedTransactionData, SignedTransactionData -from iota_sdk.types.send_params import CreateAccountOutputParams, CreateNativeTokenParams, MintNftParams, SendNativeTokensParams, SendNftParams, SendParams +from iota_sdk.types.send_params import CreateAccountOutputParams, CreateNativeTokenParams, MintNftParams, SendNativeTokenParams, SendNftParams, SendParams from iota_sdk.types.transaction_with_metadata import TransactionWithMetadata from iota_sdk.types.transaction_options import TransactionOptions from iota_sdk.types.consolidation_params import ConsolidationParams @@ -502,14 +502,14 @@ def send_with_params( )) def send_native_tokens( - self, params: List[SendNativeTokensParams], options: Optional[TransactionOptions] = None) -> TransactionWithMetadata: + self, params: List[SendNativeTokenParams], options: Optional[TransactionOptions] = None) -> TransactionWithMetadata: """Send native tokens. """ return self.prepare_send_native_tokens(params, options).send() def prepare_send_native_tokens( self, - params: List[SendNativeTokensParams], + params: List[SendNativeTokenParams], options: Optional[TransactionOptions] = None) -> PreparedTransaction: """Send native tokens. """ diff --git a/cli/src/wallet_cli/mod.rs b/cli/src/wallet_cli/mod.rs index a0b0d34413..dba658b975 100644 --- a/cli/src/wallet_cli/mod.rs +++ b/cli/src/wallet_cli/mod.rs @@ -24,7 +24,7 @@ use iota_sdk::{ utils::ConvertTo, wallet::{ types::{OutputData, TransactionWithMetadata}, - ConsolidationParams, CreateNativeTokenParams, MintNftParams, OutputsToClaim, SendNativeTokensParams, + ConsolidationParams, CreateNativeTokenParams, MintNftParams, OutputsToClaim, SendNativeTokenParams, SendNftParams, SendParams, SyncOptions, TransactionOptions, Wallet, }, U256, @@ -194,7 +194,7 @@ pub enum WalletCommand { #[arg(long, default_value_t = false)] allow_micro_amount: bool, }, - /// Send native tokens. + /// Send a native token. /// This will create an output with an expiration and storage deposit return unlock condition. SendNativeToken { /// Address to send the native tokens to, e.g. rms1qztwng6cty8cfm42nzvq099ev7udhrnk0rw8jt8vttf9kpqnxhpsx869vr3. @@ -418,14 +418,15 @@ pub async fn claimable_outputs_command(wallet: &Wallet) -> Result<(), Error> { }; println_log_info!("{output_id:?} ({kind})"); - if let Some(native_tokens) = output.native_tokens() { - if !native_tokens.is_empty() { - println_log_info!(" - native token amount:"); - native_tokens.iter().for_each(|token| { - println_log_info!(" + {} {}", token.amount(), token.token_id()); - }); - } - } + // TODO https://github.com/iotaledger/iota-sdk/issues/1633 + // if let Some(native_tokens) = output.native_tokens() { + // if !native_tokens.is_empty() { + // println_log_info!(" - native token amount:"); + // native_tokens.iter().for_each(|token| { + // println_log_info!(" + {} {}", token.amount(), token.token_id()); + // }); + // } + // } if let Some(unlock_conditions) = output.unlock_conditions() { let deposit_return = unlock_conditions @@ -736,21 +737,21 @@ pub async fn send_native_token_command( let outputs = [BasicOutputBuilder::new_with_minimum_amount(storage_params) .add_unlock_condition(AddressUnlockCondition::new(address)) - .with_native_tokens([NativeToken::new( + .with_native_token(NativeToken::new( TokenId::from_str(&token_id)?, U256::from_dec_str(&amount).map_err(|e| Error::Miscellaneous(e.to_string()))?, - )?]) + )?) .finish_output()?]; wallet.send_outputs(outputs, None).await? } else { // Send native tokens with storage deposit return and expiration - let outputs = [SendNativeTokensParams::new( + let outputs = [SendNativeTokenParams::new( address, - [( + ( TokenId::from_str(&token_id)?, U256::from_dec_str(&amount).map_err(|e| Error::Miscellaneous(e.to_string()))?, - )], + ), )?]; wallet.send_native_tokens(outputs, None).await? }; @@ -952,8 +953,8 @@ async fn print_wallet_address(wallet: &Wallet) -> Result<(), Error> { .required_and_unlocked_address(slot_index, &output_id)?; if address.inner() == required_address { - if let Some(nts) = output_data.output.native_tokens() { - native_tokens.add_native_tokens(nts.clone())?; + if let Some(nt) = output_data.output.native_token() { + native_tokens.add_native_token(nt.clone())?; } match &output_data.output { Output::Basic(_) => {} diff --git a/sdk/examples/client/02_address_balance.rs b/sdk/examples/client/02_address_balance.rs index 97c3d992ec..fc9cc522cd 100644 --- a/sdk/examples/client/02_address_balance.rs +++ b/sdk/examples/client/02_address_balance.rs @@ -55,8 +55,8 @@ async fn main() -> Result<()> { let mut total_amount = 0; let mut total_native_tokens = NativeTokensBuilder::new(); for output in outputs { - if let Some(native_tokens) = output.native_tokens() { - total_native_tokens.add_native_tokens(native_tokens.clone())?; + if let Some(native_token) = output.native_token() { + total_native_tokens.add_native_token(native_token.clone())?; } total_amount += output.amount(); } diff --git a/sdk/examples/how_tos/accounts_and_addresses/consolidate_outputs.rs b/sdk/examples/how_tos/accounts_and_addresses/consolidate_outputs.rs index bb08f13690..9726ba09bd 100644 --- a/sdk/examples/how_tos/accounts_and_addresses/consolidate_outputs.rs +++ b/sdk/examples/how_tos/accounts_and_addresses/consolidate_outputs.rs @@ -50,7 +50,7 @@ async fn main() -> Result<()> { "- address: {:?}\n- amount: {:?}\n- native tokens: {:?}", output_data.address.clone().to_bech32_unchecked("rms"), output_data.output.amount(), - output_data.output.native_tokens() + output_data.output.native_token() ) }); @@ -86,7 +86,7 @@ async fn main() -> Result<()> { "- address: {:?}\n- amount: {:?}\n- native tokens: {:?}", output_data.address.clone().to_bech32_unchecked("rms"), output_data.output.amount(), - output_data.output.native_tokens() + output_data.output.native_token() ) }); diff --git a/sdk/examples/how_tos/native_tokens/send.rs b/sdk/examples/how_tos/native_tokens/send.rs index d611442b05..01b0b5ec2b 100644 --- a/sdk/examples/how_tos/native_tokens/send.rs +++ b/sdk/examples/how_tos/native_tokens/send.rs @@ -13,7 +13,7 @@ use iota_sdk::{ types::block::address::Bech32Address, - wallet::{Result, SendNativeTokensParams}, + wallet::{Result, SendNativeTokenParams}, Wallet, }; use primitive_types::U256; @@ -58,9 +58,9 @@ async fn main() -> Result<()> { let bech32_address = RECV_ADDRESS.parse::()?; - let outputs = [SendNativeTokensParams::new( + let outputs = [SendNativeTokenParams::new( bech32_address, - [(*token_id, U256::from(SEND_NATIVE_TOKEN_AMOUNT))], + (*token_id, U256::from(SEND_NATIVE_TOKEN_AMOUNT)), )?]; let transaction = wallet.send_native_tokens(outputs, None).await?; diff --git a/sdk/src/client/api/block_builder/input_selection/mod.rs b/sdk/src/client/api/block_builder/input_selection/mod.rs index 113513f103..c8f8d742f5 100644 --- a/sdk/src/client/api/block_builder/input_selection/mod.rs +++ b/sdk/src/client/api/block_builder/input_selection/mod.rs @@ -397,8 +397,8 @@ impl InputSelection { let mut input_nfts = Vec::new(); for input in &self.selected_inputs { - if let Some(native_tokens) = input.output.native_tokens() { - input_native_tokens_builder.add_native_tokens(native_tokens.clone())?; + if let Some(native_token) = input.output.native_token() { + input_native_tokens_builder.add_native_token(native_token.clone())?; } match &input.output { Output::Account(_) => { @@ -416,8 +416,8 @@ impl InputSelection { } for output in self.outputs.iter() { - if let Some(native_token) = output.native_tokens() { - output_native_tokens_builder.add_native_tokens(native_token.clone())?; + if let Some(native_token) = output.native_token() { + output_native_tokens_builder.add_native_token(native_token.clone())?; } } diff --git a/sdk/src/client/api/block_builder/input_selection/remainder.rs b/sdk/src/client/api/block_builder/input_selection/remainder.rs index 0dae140a3e..e0a37a56fa 100644 --- a/sdk/src/client/api/block_builder/input_selection/remainder.rs +++ b/sdk/src/client/api/block_builder/input_selection/remainder.rs @@ -71,9 +71,10 @@ impl InputSelection { [0; 32], )))); - if let Some(native_tokens) = native_tokens_diff { - remainder_builder = remainder_builder.with_native_tokens(native_tokens); - } + // TODO https://github.com/iotaledger/iota-sdk/issues/1631 + // if let Some(native_tokens) = native_tokens_diff { + // remainder_builder = remainder_builder.with_native_tokens(native_tokens); + // } Ok((remainder_builder.finish_output()?.amount(), native_tokens_remainder)) } @@ -131,10 +132,11 @@ impl InputSelection { remainder_builder = remainder_builder.add_unlock_condition(AddressUnlockCondition::new(remainder_address.clone())); - if let Some(native_tokens) = native_tokens_diff { - log::debug!("Adding {native_tokens:?} to remainder output for {remainder_address:?}"); - remainder_builder = remainder_builder.with_native_tokens(native_tokens); - } + // TODO https://github.com/iotaledger/iota-sdk/issues/1631 + // if let Some(native_tokens) = native_tokens_diff { + // log::debug!("Adding {native_tokens:?} to remainder output for {remainder_address:?}"); + // remainder_builder = remainder_builder.with_native_tokens(native_tokens); + // } let remainder = remainder_builder.finish_output()?; diff --git a/sdk/src/client/api/block_builder/input_selection/requirement/amount.rs b/sdk/src/client/api/block_builder/input_selection/requirement/amount.rs index 9a08208936..e0822901dc 100644 --- a/sdk/src/client/api/block_builder/input_selection/requirement/amount.rs +++ b/sdk/src/client/api/block_builder/input_selection/requirement/amount.rs @@ -172,40 +172,36 @@ impl InputSelection { base_inputs: impl Iterator + Clone, amount_selection: &mut AmountSelection, ) -> bool { - // No native tokens, expired SDRUC. + // No native token, expired SDRUC. let inputs = base_inputs.clone().filter(|input| { - input.output.native_tokens().unwrap().is_empty() - && sdruc_not_expired(&input.output, self.slot_index).is_none() + input.output.native_token().is_none() && sdruc_not_expired(&input.output, self.slot_index).is_none() }); if amount_selection.fulfil(inputs) { return true; } - // No native tokens, unexpired SDRUC. + // No native token, unexpired SDRUC. let inputs = base_inputs.clone().filter(|input| { - input.output.native_tokens().unwrap().is_empty() - && sdruc_not_expired(&input.output, self.slot_index).is_some() + input.output.native_token().is_none() && sdruc_not_expired(&input.output, self.slot_index).is_some() }); if amount_selection.fulfil(inputs) { return true; } - // Native tokens, expired SDRUC. + // Native token, expired SDRUC. let inputs = base_inputs.clone().filter(|input| { - !input.output.native_tokens().unwrap().is_empty() - && sdruc_not_expired(&input.output, self.slot_index).is_none() + input.output.native_token().is_some() && sdruc_not_expired(&input.output, self.slot_index).is_none() }); if amount_selection.fulfil(inputs) { return true; } - // Native tokens, unexpired SDRUC. + // Native token, unexpired SDRUC. let inputs = base_inputs.clone().filter(|input| { - !input.output.native_tokens().unwrap().is_empty() - && sdruc_not_expired(&input.output, self.slot_index).is_some() + input.output.native_token().is_some() && sdruc_not_expired(&input.output, self.slot_index).is_some() }); if amount_selection.fulfil(inputs) { diff --git a/sdk/src/client/api/block_builder/input_selection/requirement/native_tokens.rs b/sdk/src/client/api/block_builder/input_selection/requirement/native_tokens.rs index a9871d508e..02b2818cc8 100644 --- a/sdk/src/client/api/block_builder/input_selection/requirement/native_tokens.rs +++ b/sdk/src/client/api/block_builder/input_selection/requirement/native_tokens.rs @@ -15,8 +15,8 @@ pub(crate) fn get_native_tokens<'a>(outputs: impl Iterator) - let mut required_native_tokens = NativeTokensBuilder::new(); for output in outputs { - if let Some(output_native_tokens) = output.native_tokens() { - required_native_tokens.add_native_tokens(output_native_tokens.clone())?; + if let Some(output_native_token) = output.native_token() { + required_native_tokens.add_native_token(output_native_token.clone())?; } } @@ -139,15 +139,14 @@ impl InputSelection { let inputs = self.available_inputs.iter().filter(|input| { input .output - .native_tokens() - .map_or(false, |native_tokens| native_tokens.contains(diff.token_id())) + .native_token() + .is_some_and(|native_token| native_token.token_id() == diff.token_id()) }); for input in inputs { amount += input .output - .native_tokens() - .and_then(|native_tokens| native_tokens.get(diff.token_id())) + .native_token() // PANIC: safe to unwrap as the filter guarantees inputs containing this native token. .unwrap() .amount(); diff --git a/sdk/src/types/block/error.rs b/sdk/src/types/block/error.rs index 394a04a605..4249c4f3cb 100644 --- a/sdk/src/types/block/error.rs +++ b/sdk/src/types/block/error.rs @@ -137,7 +137,6 @@ pub enum Error { InvalidTagLength(>::Error), InvalidTokenSchemeKind(u8), InvalidTransactionAmountSum(u128), - InvalidTransactionNativeTokensCount(u16), InvalidManaAllotmentSum { max: u64, sum: u128, @@ -345,9 +344,6 @@ impl fmt::Display for Error { } Self::InvalidTokenSchemeKind(k) => write!(f, "invalid token scheme kind {k}"), Self::InvalidTransactionAmountSum(value) => write!(f, "invalid transaction amount sum: {value}"), - Self::InvalidTransactionNativeTokensCount(count) => { - write!(f, "invalid transaction native tokens count: {count}") - } Self::InvalidManaAllotmentSum { max, sum } => { write!(f, "invalid mana allotment sum: {sum} greater than max of {max}") } diff --git a/sdk/src/types/block/mod.rs b/sdk/src/types/block/mod.rs index 724454453e..c5ebdde771 100644 --- a/sdk/src/types/block/mod.rs +++ b/sdk/src/types/block/mod.rs @@ -42,7 +42,6 @@ pub mod unlock; #[cfg(feature = "serde")] pub use self::core::dto::{BlockBodyDto, BlockDto, UnsignedBlockDto}; -pub(crate) use self::r#macro::*; pub use self::{ block_id::{BlockHash, BlockId}, core::{Block, BlockBody, UnsignedBlock}, diff --git a/sdk/src/types/block/output/account.rs b/sdk/src/types/block/output/account.rs index a1f27ab433..cf8b230550 100644 --- a/sdk/src/types/block/output/account.rs +++ b/sdk/src/types/block/output/account.rs @@ -16,8 +16,8 @@ use crate::types::block::{ output::{ feature::{verify_allowed_features, Feature, FeatureFlags, Features}, unlock_condition::{verify_allowed_unlock_conditions, UnlockCondition, UnlockConditionFlags, UnlockConditions}, - ChainId, MinimumOutputAmount, NativeToken, NativeTokens, Output, OutputBuilderAmount, OutputId, - StateTransitionError, StateTransitionVerifier, StorageScore, StorageScoreParameters, + ChainId, MinimumOutputAmount, Output, OutputBuilderAmount, OutputId, StateTransitionError, + StateTransitionVerifier, StorageScore, StorageScoreParameters, }, payload::signed_transaction::TransactionCapabilityFlag, protocol::ProtocolParameters, @@ -58,7 +58,6 @@ impl From for Address { pub struct AccountOutputBuilder { amount: OutputBuilderAmount, mana: u64, - native_tokens: BTreeSet, account_id: AccountId, foundry_counter: Option, unlock_conditions: BTreeSet, @@ -82,7 +81,6 @@ impl AccountOutputBuilder { Self { amount, mana: Default::default(), - native_tokens: BTreeSet::new(), account_id, foundry_counter: None, unlock_conditions: BTreeSet::new(), @@ -112,20 +110,6 @@ impl AccountOutputBuilder { self } - /// - #[inline(always)] - pub fn add_native_token(mut self, native_token: NativeToken) -> Self { - self.native_tokens.insert(native_token); - self - } - - /// - #[inline(always)] - pub fn with_native_tokens(mut self, native_tokens: impl IntoIterator) -> Self { - self.native_tokens = native_tokens.into_iter().collect(); - self - } - /// Sets the account ID to the provided value. #[inline(always)] pub fn with_account_id(mut self, account_id: AccountId) -> Self { @@ -245,7 +229,6 @@ impl AccountOutputBuilder { let mut output = AccountOutput { amount: 0, mana: self.mana, - native_tokens: NativeTokens::from_set(self.native_tokens)?, account_id: self.account_id, foundry_counter, unlock_conditions, @@ -272,7 +255,6 @@ impl From<&AccountOutput> for AccountOutputBuilder { Self { amount: OutputBuilderAmount::Amount(output.amount), mana: output.mana, - native_tokens: output.native_tokens.iter().copied().collect(), account_id: output.account_id, foundry_counter: Some(output.foundry_counter), unlock_conditions: output.unlock_conditions.iter().cloned().collect(), @@ -288,8 +270,6 @@ pub struct AccountOutput { // Amount of IOTA coins held by the output. amount: u64, mana: u64, - // Native tokens held by the output. - native_tokens: NativeTokens, // Unique identifier of the account. account_id: AccountId, // A counter that denotes the number of foundries created by this account. @@ -335,12 +315,6 @@ impl AccountOutput { self.mana } - /// - #[inline(always)] - pub fn native_tokens(&self) -> &NativeTokens { - &self.native_tokens - } - /// #[inline(always)] pub fn account_id(&self) -> &AccountId { @@ -436,7 +410,6 @@ impl AccountOutput { // TODO update when TIP is updated // // Governance transition. // if current_state.amount != next_state.amount - // || current_state.native_tokens != next_state.native_tokens // || current_state.foundry_counter != next_state.foundry_counter // { // return Err(StateTransitionError::MutatedFieldWithoutRights); @@ -538,7 +511,6 @@ impl Packable for AccountOutput { fn pack(&self, packer: &mut P) -> Result<(), P::Error> { self.amount.pack(packer)?; self.mana.pack(packer)?; - self.native_tokens.pack(packer)?; self.account_id.pack(packer)?; self.foundry_counter.pack(packer)?; self.unlock_conditions.pack(packer)?; @@ -556,7 +528,6 @@ impl Packable for AccountOutput { let mana = u64::unpack::<_, VERIFY>(unpacker, &()).coerce()?; - let native_tokens = NativeTokens::unpack::<_, VERIFY>(unpacker, &())?; let account_id = AccountId::unpack::<_, VERIFY>(unpacker, &()).coerce()?; let foundry_counter = u32::unpack::<_, VERIFY>(unpacker, &()).coerce()?; @@ -587,7 +558,6 @@ impl Packable for AccountOutput { Ok(Self { amount, mana, - native_tokens, account_id, foundry_counter, unlock_conditions, @@ -642,8 +612,6 @@ pub(crate) mod dto { pub amount: u64, #[serde(with = "string")] pub mana: u64, - #[serde(skip_serializing_if = "Vec::is_empty", default)] - pub native_tokens: Vec, pub account_id: AccountId, pub foundry_counter: u32, pub unlock_conditions: Vec, @@ -659,7 +627,6 @@ pub(crate) mod dto { kind: AccountOutput::KIND, amount: value.amount(), mana: value.mana(), - native_tokens: value.native_tokens().to_vec(), account_id: *value.account_id(), foundry_counter: value.foundry_counter(), unlock_conditions: value.unlock_conditions().iter().map(Into::into).collect::<_>(), @@ -676,7 +643,6 @@ pub(crate) mod dto { let mut builder = AccountOutputBuilder::new_with_amount(dto.amount, dto.account_id) .with_mana(dto.mana) .with_foundry_counter(dto.foundry_counter) - .with_native_tokens(dto.native_tokens) .with_features(dto.features) .with_immutable_features(dto.immutable_features); @@ -693,7 +659,6 @@ pub(crate) mod dto { pub fn try_from_dtos( amount: OutputBuilderAmount, mana: u64, - native_tokens: Option>, account_id: &AccountId, foundry_counter: Option, unlock_conditions: Vec, @@ -708,10 +673,6 @@ pub(crate) mod dto { } .with_mana(mana); - if let Some(native_tokens) = native_tokens { - builder = builder.with_native_tokens(native_tokens); - } - if let Some(foundry_counter) = foundry_counter { builder = builder.with_foundry_counter(foundry_counter); } @@ -741,14 +702,11 @@ mod tests { use super::*; use crate::types::block::{ - output::{dto::OutputDto, FoundryId, SimpleTokenScheme, TokenId}, + output::dto::OutputDto, protocol::protocol_parameters, - rand::{ - address::rand_account_address, - output::{ - feature::rand_allowed_features, rand_account_id, rand_account_output, - unlock_condition::rand_address_unlock_condition_different_from_account_id, - }, + rand::output::{ + feature::rand_allowed_features, rand_account_id, rand_account_output, + unlock_condition::rand_address_unlock_condition_different_from_account_id, }, }; @@ -765,7 +723,6 @@ mod tests { let output_split = AccountOutput::try_from_dtos( OutputBuilderAmount::Amount(output.amount()), output.mana(), - Some(output.native_tokens().to_vec()), output.account_id(), output.foundry_counter().into(), output.unlock_conditions().iter().map(Into::into).collect(), @@ -776,14 +733,12 @@ mod tests { assert_eq!(output, output_split); let account_id = rand_account_id(); - let foundry_id = FoundryId::build(&rand_account_address(), 0, SimpleTokenScheme::KIND); let address = rand_address_unlock_condition_different_from_account_id(&account_id); let test_split_dto = |builder: AccountOutputBuilder| { let output_split = AccountOutput::try_from_dtos( builder.amount, builder.mana, - Some(builder.native_tokens.iter().copied().collect()), &builder.account_id, builder.foundry_counter, builder.unlock_conditions.iter().map(Into::into).collect(), @@ -795,7 +750,6 @@ mod tests { }; let builder = AccountOutput::build_with_amount(100, account_id) - .add_native_token(NativeToken::new(TokenId::from(foundry_id), 1000).unwrap()) .add_unlock_condition(address.clone()) .with_features(rand_allowed_features(AccountOutput::ALLOWED_FEATURES)) .with_immutable_features(rand_allowed_features(AccountOutput::ALLOWED_IMMUTABLE_FEATURES)); @@ -803,7 +757,6 @@ mod tests { let builder = AccountOutput::build_with_minimum_amount(protocol_parameters.storage_score_parameters(), account_id) - .add_native_token(NativeToken::new(TokenId::from(foundry_id), 1000).unwrap()) .add_unlock_condition(address) .with_features(rand_allowed_features(AccountOutput::ALLOWED_FEATURES)) .with_immutable_features(rand_allowed_features(AccountOutput::ALLOWED_IMMUTABLE_FEATURES)); diff --git a/sdk/src/types/block/output/basic.rs b/sdk/src/types/block/output/basic.rs index 5cf17ea955..0f310d76f4 100644 --- a/sdk/src/types/block/output/basic.rs +++ b/sdk/src/types/block/output/basic.rs @@ -8,13 +8,12 @@ use packable::{Packable, PackableExt}; use crate::types::block::{ address::Address, output::{ - feature::{verify_allowed_features, Feature, FeatureFlags, Features}, + feature::{verify_allowed_features, Feature, FeatureFlags, Features, NativeTokenFeature}, unlock_condition::{ verify_allowed_unlock_conditions, AddressUnlockCondition, StorageDepositReturnUnlockCondition, UnlockCondition, UnlockConditionFlags, UnlockConditions, }, - MinimumOutputAmount, NativeToken, NativeTokens, Output, OutputBuilderAmount, OutputId, StorageScore, - StorageScoreParameters, + MinimumOutputAmount, NativeToken, Output, OutputBuilderAmount, OutputId, StorageScore, StorageScoreParameters, }, protocol::ProtocolParameters, semantic::{SemanticValidationContext, TransactionFailureReason}, @@ -28,7 +27,6 @@ use crate::types::block::{ pub struct BasicOutputBuilder { amount: OutputBuilderAmount, mana: u64, - native_tokens: BTreeSet, unlock_conditions: BTreeSet, features: BTreeSet, } @@ -51,7 +49,6 @@ impl BasicOutputBuilder { Self { amount, mana: Default::default(), - native_tokens: BTreeSet::new(), unlock_conditions: BTreeSet::new(), features: BTreeSet::new(), } @@ -78,20 +75,6 @@ impl BasicOutputBuilder { self } - /// - #[inline(always)] - pub fn add_native_token(mut self, native_token: NativeToken) -> Self { - self.native_tokens.insert(native_token); - self - } - - /// - #[inline(always)] - pub fn with_native_tokens(mut self, native_tokens: impl IntoIterator) -> Self { - self.native_tokens = native_tokens.into_iter().collect(); - self - } - /// Adds an [`UnlockCondition`] to the builder, if one does not already exist of that type. #[inline(always)] pub fn add_unlock_condition(mut self, unlock_condition: impl Into) -> Self { @@ -149,6 +132,12 @@ impl BasicOutputBuilder { self } + /// Sets the native token of the builder. + #[inline(always)] + pub fn with_native_token(self, native_token: impl Into) -> Self { + self.add_feature(NativeTokenFeature::from(native_token.into())) + } + /// Adds a storage deposit return unlock condition if one is needed to cover the current amount /// (i.e. `amount < minimum_amount`). This will increase the total amount to satisfy the `minimum_amount` with /// the additional unlock condition that will return the remainder to the provided `return_address`. @@ -210,7 +199,6 @@ impl BasicOutputBuilder { let mut output = BasicOutput { amount: 0, mana: self.mana, - native_tokens: NativeTokens::from_set(self.native_tokens)?, unlock_conditions, features, }; @@ -234,7 +222,6 @@ impl From<&BasicOutput> for BasicOutputBuilder { Self { amount: OutputBuilderAmount::Amount(output.amount), mana: output.mana, - native_tokens: output.native_tokens.iter().copied().collect(), unlock_conditions: output.unlock_conditions.iter().cloned().collect(), features: output.features.iter().cloned().collect(), } @@ -250,8 +237,6 @@ pub struct BasicOutput { amount: u64, /// Amount of stored Mana held by this output. mana: u64, - /// Native tokens held by this output. - native_tokens: NativeTokens, /// Define how the output can be unlocked in a transaction. #[packable(verify_with = verify_unlock_conditions_packable)] unlock_conditions: UnlockConditions, @@ -272,7 +257,8 @@ impl BasicOutput { /// The set of allowed [`Feature`]s for an [`BasicOutput`]. pub const ALLOWED_FEATURES: FeatureFlags = FeatureFlags::SENDER .union(FeatureFlags::METADATA) - .union(FeatureFlags::TAG); + .union(FeatureFlags::TAG) + .union(FeatureFlags::NATIVE_TOKEN); /// Creates a new [`BasicOutputBuilder`] with a provided amount. #[inline(always)] @@ -298,12 +284,6 @@ impl BasicOutput { self.mana } - /// - #[inline(always)] - pub fn native_tokens(&self) -> &NativeTokens { - &self.native_tokens - } - /// #[inline(always)] pub fn unlock_conditions(&self) -> &UnlockConditions { @@ -316,6 +296,12 @@ impl BasicOutput { &self.features } + /// + #[inline(always)] + pub fn native_token(&self) -> Option<&NativeToken> { + self.features.native_token().map(|f| f.native_token()) + } + /// #[inline(always)] pub fn address(&self) -> &Address { @@ -342,9 +328,9 @@ impl BasicOutput { /// Simple deposit outputs are basic outputs with only an address unlock condition, no native tokens and no /// features. They are used to return storage deposits. pub fn simple_deposit_address(&self) -> Option<&Address> { - if let [UnlockCondition::Address(uc)] = self.unlock_conditions().as_ref() { - if self.mana == 0 && self.native_tokens.is_empty() && self.features.is_empty() { - return Some(uc.address()); + if let [UnlockCondition::Address(address)] = self.unlock_conditions().as_ref() { + if self.mana == 0 && self.features.is_empty() { + return Some(address.address()); } } @@ -436,8 +422,6 @@ pub(crate) mod dto { pub amount: u64, #[serde(with = "string")] pub mana: u64, - #[serde(skip_serializing_if = "Vec::is_empty", default)] - pub native_tokens: Vec, pub unlock_conditions: Vec, #[serde(skip_serializing_if = "Vec::is_empty", default)] pub features: Vec, @@ -449,7 +433,6 @@ pub(crate) mod dto { kind: BasicOutput::KIND, amount: value.amount(), mana: value.mana(), - native_tokens: value.native_tokens().to_vec(), unlock_conditions: value.unlock_conditions().iter().map(Into::into).collect::<_>(), features: value.features().to_vec(), } @@ -461,7 +444,6 @@ pub(crate) mod dto { fn try_from(dto: BasicOutputDto) -> Result { let mut builder = BasicOutputBuilder::new_with_amount(dto.amount) - .with_native_tokens(dto.native_tokens) .with_mana(dto.mana) .with_features(dto.features); @@ -477,7 +459,6 @@ pub(crate) mod dto { pub fn try_from_dtos( amount: OutputBuilderAmount, mana: u64, - native_tokens: Option>, unlock_conditions: Vec, features: Option>, ) -> Result { @@ -487,10 +468,6 @@ pub(crate) mod dto { } .with_mana(mana); - if let Some(native_tokens) = native_tokens { - builder = builder.with_native_tokens(native_tokens); - } - let unlock_conditions = unlock_conditions .into_iter() .map(UnlockCondition::from) @@ -535,7 +512,6 @@ mod tests { let output_split = BasicOutput::try_from_dtos( OutputBuilderAmount::Amount(output.amount()), output.mana(), - Some(output.native_tokens().to_vec()), output.unlock_conditions().iter().map(Into::into).collect(), Some(output.features().to_vec()), ) @@ -549,7 +525,6 @@ mod tests { let output_split = BasicOutput::try_from_dtos( builder.amount, builder.mana, - Some(builder.native_tokens.iter().copied().collect()), builder.unlock_conditions.iter().map(Into::into).collect(), Some(builder.features.iter().cloned().collect()), ) @@ -558,13 +533,13 @@ mod tests { }; let builder = BasicOutput::build_with_amount(100) - .add_native_token(NativeToken::new(TokenId::from(foundry_id), 1000).unwrap()) + .with_native_token(NativeToken::new(TokenId::from(foundry_id), 1000).unwrap()) .add_unlock_condition(address.clone()) .with_features(rand_allowed_features(BasicOutput::ALLOWED_FEATURES)); test_split_dto(builder); let builder = BasicOutput::build_with_minimum_amount(protocol_parameters.storage_score_parameters()) - .add_native_token(NativeToken::new(TokenId::from(foundry_id), 1000).unwrap()) + .with_native_token(NativeToken::new(TokenId::from(foundry_id), 1000).unwrap()) .add_unlock_condition(address) .with_features(rand_allowed_features(BasicOutput::ALLOWED_FEATURES)); test_split_dto(builder); diff --git a/sdk/src/types/block/output/feature/block_issuer.rs b/sdk/src/types/block/output/feature/block_issuer.rs index 829430a0c5..c544d936f1 100644 --- a/sdk/src/types/block/output/feature/block_issuer.rs +++ b/sdk/src/types/block/output/feature/block_issuer.rs @@ -210,7 +210,7 @@ pub struct BlockIssuerFeature { impl BlockIssuerFeature { /// The [`Feature`](crate::types::block::output::Feature) kind of a [`BlockIssuerFeature`]. - pub const KIND: u8 = 4; + pub const KIND: u8 = 5; /// Creates a new [`BlockIssuerFeature`]. #[inline(always)] diff --git a/sdk/src/types/block/output/feature/mod.rs b/sdk/src/types/block/output/feature/mod.rs index 087e5607be..8f3067fcf7 100644 --- a/sdk/src/types/block/output/feature/mod.rs +++ b/sdk/src/types/block/output/feature/mod.rs @@ -4,6 +4,7 @@ mod block_issuer; mod issuer; mod metadata; +mod native_token; mod sender; mod staking; mod tag; @@ -24,6 +25,7 @@ pub use self::{ block_issuer::{BlockIssuerFeature, BlockIssuerKey, BlockIssuerKeys, Ed25519BlockIssuerKey}, issuer::IssuerFeature, metadata::MetadataFeature, + native_token::NativeTokenFeature, sender::SenderFeature, staking::StakingFeature, tag::TagFeature, @@ -51,6 +53,9 @@ pub enum Feature { /// A tag feature. #[packable(tag = TagFeature::KIND)] Tag(TagFeature), + /// A native token feature. + #[packable(tag = NativeTokenFeature::KIND)] + NativeToken(NativeTokenFeature), /// A block issuer feature. #[packable(tag = BlockIssuerFeature::KIND)] BlockIssuer(BlockIssuerFeature), @@ -78,6 +83,7 @@ impl StorageScore for Feature { Self::Issuer(feature) => feature.storage_score(params), Self::Metadata(feature) => feature.storage_score(params), Self::Tag(feature) => feature.storage_score(params), + Self::NativeToken(feature) => feature.storage_score(params), Self::BlockIssuer(feature) => feature.storage_score(params), Self::Staking(feature) => feature.storage_score(params), } @@ -91,6 +97,7 @@ impl core::fmt::Debug for Feature { Self::Issuer(feature) => feature.fmt(f), Self::Metadata(feature) => feature.fmt(f), Self::Tag(feature) => feature.fmt(f), + Self::NativeToken(feature) => feature.fmt(f), Self::BlockIssuer(feature) => feature.fmt(f), Self::Staking(feature) => feature.fmt(f), } @@ -105,6 +112,7 @@ impl Feature { Self::Issuer(_) => IssuerFeature::KIND, Self::Metadata(_) => MetadataFeature::KIND, Self::Tag(_) => TagFeature::KIND, + Self::NativeToken(_) => NativeTokenFeature::KIND, Self::BlockIssuer(_) => BlockIssuerFeature::KIND, Self::Staking(_) => StakingFeature::KIND, } @@ -117,12 +125,13 @@ impl Feature { Self::Issuer(_) => FeatureFlags::ISSUER, Self::Metadata(_) => FeatureFlags::METADATA, Self::Tag(_) => FeatureFlags::TAG, + Self::NativeToken(_) => FeatureFlags::NATIVE_TOKEN, Self::BlockIssuer(_) => FeatureFlags::BLOCK_ISSUER, Self::Staking(_) => FeatureFlags::STAKING, } } - crate::def_is_as_opt!(Feature: Sender, Issuer, Metadata, Tag, BlockIssuer, Staking); + crate::def_is_as_opt!(Feature: Sender, Issuer, Metadata, Tag, NativeToken, BlockIssuer, Staking); } crate::create_bitflags!( @@ -134,6 +143,7 @@ crate::create_bitflags!( (ISSUER, IssuerFeature), (METADATA, MetadataFeature), (TAG, TagFeature), + (NATIVE_TOKEN, NativeTokenFeature), (BLOCK_ISSUER, BlockIssuerFeature), (STAKING, StakingFeature), ] @@ -230,6 +240,11 @@ impl Features { self.get(TagFeature::KIND).map(Feature::as_tag) } + /// Gets a reference to a [`NativeTokenFeature`], if any. + pub fn native_token(&self) -> Option<&NativeTokenFeature> { + self.get(NativeTokenFeature::KIND).map(Feature::as_native_token) + } + /// Gets a reference to a [`BlockIssuerFeature`], if any. pub fn block_issuer(&self) -> Option<&BlockIssuerFeature> { self.get(BlockIssuerFeature::KIND).map(Feature::as_block_issuer) @@ -284,6 +299,7 @@ mod test { FeatureFlags::ISSUER, FeatureFlags::METADATA, FeatureFlags::TAG, + FeatureFlags::NATIVE_TOKEN, FeatureFlags::BLOCK_ISSUER, FeatureFlags::STAKING ] diff --git a/sdk/src/types/block/output/feature/native_token.rs b/sdk/src/types/block/output/feature/native_token.rs new file mode 100644 index 0000000000..7bb52a0275 --- /dev/null +++ b/sdk/src/types/block/output/feature/native_token.rs @@ -0,0 +1,64 @@ +// Copyright 2023 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use derive_more::{Deref, From}; + +use crate::types::block::output::{NativeToken, StorageScore}; + +#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Deref, From, packable::Packable)] +pub struct NativeTokenFeature(NativeToken); + +impl NativeTokenFeature { + /// The [`Feature`](crate::types::block::output::Feature) kind of [`NativeTokenFeature`]. + pub const KIND: u8 = 4; + + /// Creates a new [`NativeTokenFeature`]. + pub fn new(native_token: NativeToken) -> Self { + Self(native_token) + } + + /// Returns the inner native token. + pub fn native_token(&self) -> &NativeToken { + &self.0 + } +} + +impl StorageScore for NativeTokenFeature {} + +#[cfg(feature = "serde")] +mod dto { + use primitive_types::U256; + use serde::{Deserialize, Serialize}; + + use super::*; + use crate::types::block::{output::TokenId, Error}; + + #[derive(Serialize, Deserialize)] + struct NativeTokenFeatureDto { + #[serde(rename = "type")] + kind: u8, + #[serde(rename = "id")] + token_id: TokenId, + amount: U256, + } + + impl From<&NativeTokenFeature> for NativeTokenFeatureDto { + fn from(value: &NativeTokenFeature) -> Self { + Self { + kind: NativeTokenFeature::KIND, + token_id: value.token_id().clone(), + amount: value.amount(), + } + } + } + + impl TryFrom for NativeTokenFeature { + type Error = Error; + + fn try_from(value: NativeTokenFeatureDto) -> Result { + Ok(Self::new(NativeToken::new(value.token_id, value.amount)?)) + } + } + + crate::impl_serde_typed_dto!(NativeTokenFeature, NativeTokenFeatureDto, "native token feature"); +} diff --git a/sdk/src/types/block/output/feature/staking.rs b/sdk/src/types/block/output/feature/staking.rs index ee4c8d1fd5..9ab86dfd3d 100644 --- a/sdk/src/types/block/output/feature/staking.rs +++ b/sdk/src/types/block/output/feature/staking.rs @@ -21,7 +21,7 @@ pub struct StakingFeature { impl StakingFeature { /// The [`Feature`](crate::types::block::output::Feature) kind of [`StakingFeature`]. - pub const KIND: u8 = 5; + pub const KIND: u8 = 6; /// Creates a new [`StakingFeature`]. pub fn new( diff --git a/sdk/src/types/block/output/foundry.rs b/sdk/src/types/block/output/foundry.rs index 7978462879..0bec812f32 100644 --- a/sdk/src/types/block/output/foundry.rs +++ b/sdk/src/types/block/output/foundry.rs @@ -16,10 +16,10 @@ use crate::types::block::{ address::{AccountAddress, Address}, output::{ account::AccountId, - feature::{verify_allowed_features, Feature, FeatureFlags, Features}, + feature::{verify_allowed_features, Feature, FeatureFlags, Features, NativeTokenFeature}, unlock_condition::{verify_allowed_unlock_conditions, UnlockCondition, UnlockConditionFlags, UnlockConditions}, - ChainId, MinimumOutputAmount, NativeToken, NativeTokens, Output, OutputBuilderAmount, OutputId, - StateTransitionError, StateTransitionVerifier, StorageScore, StorageScoreParameters, TokenId, TokenScheme, + ChainId, MinimumOutputAmount, NativeToken, Output, OutputBuilderAmount, OutputId, StateTransitionError, + StateTransitionVerifier, StorageScore, StorageScoreParameters, TokenId, TokenScheme, }, payload::signed_transaction::{TransactionCapabilities, TransactionCapabilityFlag}, protocol::ProtocolParameters, @@ -84,7 +84,6 @@ impl FoundryId { #[must_use] pub struct FoundryOutputBuilder { amount: OutputBuilderAmount, - native_tokens: BTreeSet, serial_number: u32, token_scheme: TokenScheme, unlock_conditions: BTreeSet, @@ -111,7 +110,6 @@ impl FoundryOutputBuilder { fn new(amount: OutputBuilderAmount, serial_number: u32, token_scheme: TokenScheme) -> Self { Self { amount, - native_tokens: BTreeSet::new(), serial_number, token_scheme, unlock_conditions: BTreeSet::new(), @@ -134,20 +132,6 @@ impl FoundryOutputBuilder { self } - /// - #[inline(always)] - pub fn add_native_token(mut self, native_token: NativeToken) -> Self { - self.native_tokens.insert(native_token); - self - } - - /// - #[inline(always)] - pub fn with_native_tokens(mut self, native_tokens: impl IntoIterator) -> Self { - self.native_tokens = native_tokens.into_iter().collect(); - self - } - /// Sets the serial number to the provided value. #[inline(always)] pub fn with_serial_number(mut self, serial_number: u32) -> Self { @@ -219,6 +203,12 @@ impl FoundryOutputBuilder { self } + /// Sets the native token of the builder. + #[inline(always)] + pub fn with_native_token(self, native_token: impl Into) -> Self { + self.add_feature(NativeTokenFeature::from(native_token.into())) + } + /// Adds an immutable [`Feature`] to the builder, if one does not already exist of that type. #[inline(always)] pub fn add_immutable_feature(mut self, immutable_feature: impl Into) -> Self { @@ -266,7 +256,6 @@ impl FoundryOutputBuilder { let mut output = FoundryOutput { amount: 0, - native_tokens: NativeTokens::from_set(self.native_tokens)?, serial_number: self.serial_number, token_scheme: self.token_scheme, unlock_conditions, @@ -292,7 +281,6 @@ impl From<&FoundryOutput> for FoundryOutputBuilder { fn from(output: &FoundryOutput) -> Self { Self { amount: OutputBuilderAmount::Amount(output.amount), - native_tokens: output.native_tokens.iter().copied().collect(), serial_number: output.serial_number, token_scheme: output.token_scheme.clone(), unlock_conditions: output.unlock_conditions.iter().cloned().collect(), @@ -307,8 +295,6 @@ impl From<&FoundryOutput> for FoundryOutputBuilder { pub struct FoundryOutput { /// Amount of IOTA coins to deposit with this output. amount: u64, - /// Native tokens held by this output. - native_tokens: NativeTokens, /// The serial number of the foundry with respect to the controlling account. serial_number: u32, /// Define the supply control scheme of the native tokens controlled by the foundry. @@ -327,7 +313,7 @@ impl FoundryOutput { /// The set of allowed [`UnlockCondition`]s for a [`FoundryOutput`]. pub const ALLOWED_UNLOCK_CONDITIONS: UnlockConditionFlags = UnlockConditionFlags::IMMUTABLE_ACCOUNT_ADDRESS; /// The set of allowed [`Feature`]s for a [`FoundryOutput`]. - pub const ALLOWED_FEATURES: FeatureFlags = FeatureFlags::METADATA; + pub const ALLOWED_FEATURES: FeatureFlags = FeatureFlags::METADATA.union(FeatureFlags::NATIVE_TOKEN); /// The set of allowed immutable [`Feature`]s for a [`FoundryOutput`]. pub const ALLOWED_IMMUTABLE_FEATURES: FeatureFlags = FeatureFlags::METADATA; @@ -354,12 +340,6 @@ impl FoundryOutput { self.amount } - /// - #[inline(always)] - pub fn native_tokens(&self) -> &NativeTokens { - &self.native_tokens - } - /// #[inline(always)] pub fn serial_number(&self) -> u32 { @@ -384,6 +364,12 @@ impl FoundryOutput { &self.features } + /// + #[inline(always)] + pub fn native_token(&self) -> Option<&NativeToken> { + self.features.native_token().map(|f| f.native_token()) + } + /// #[inline(always)] pub fn immutable_features(&self) -> &Features { @@ -607,7 +593,6 @@ impl Packable for FoundryOutput { fn pack(&self, packer: &mut P) -> Result<(), P::Error> { self.amount.pack(packer)?; - self.native_tokens.pack(packer)?; self.serial_number.pack(packer)?; self.token_scheme.pack(packer)?; self.unlock_conditions.pack(packer)?; @@ -623,7 +608,6 @@ impl Packable for FoundryOutput { ) -> Result> { let amount = u64::unpack::<_, VERIFY>(unpacker, &()).coerce()?; - let native_tokens = NativeTokens::unpack::<_, VERIFY>(unpacker, &())?; let serial_number = u32::unpack::<_, VERIFY>(unpacker, &()).coerce()?; let token_scheme = TokenScheme::unpack::<_, VERIFY>(unpacker, &())?; @@ -648,7 +632,6 @@ impl Packable for FoundryOutput { Ok(Self { amount, - native_tokens, serial_number, token_scheme, unlock_conditions, @@ -685,8 +668,6 @@ pub(crate) mod dto { pub kind: u8, #[serde(with = "string")] pub amount: u64, - #[serde(skip_serializing_if = "Vec::is_empty", default)] - pub native_tokens: Vec, pub serial_number: u32, pub token_scheme: TokenScheme, pub unlock_conditions: Vec, @@ -701,7 +682,6 @@ pub(crate) mod dto { Self { kind: FoundryOutput::KIND, amount: value.amount(), - native_tokens: value.native_tokens().to_vec(), serial_number: value.serial_number(), token_scheme: value.token_scheme().clone(), unlock_conditions: value.unlock_conditions().iter().map(Into::into).collect::<_>(), @@ -718,10 +698,6 @@ pub(crate) mod dto { let mut builder: FoundryOutputBuilder = FoundryOutputBuilder::new_with_amount(dto.amount, dto.serial_number, dto.token_scheme); - for t in dto.native_tokens { - builder = builder.add_native_token(t); - } - for b in dto.features { builder = builder.add_feature(b); } @@ -742,7 +718,6 @@ pub(crate) mod dto { #[allow(clippy::too_many_arguments)] pub fn try_from_dtos( amount: OutputBuilderAmount, - native_tokens: Option>, serial_number: u32, token_scheme: TokenScheme, unlock_conditions: Vec, @@ -758,10 +733,6 @@ pub(crate) mod dto { } }; - if let Some(native_tokens) = native_tokens { - builder = builder.with_native_tokens(native_tokens); - } - let unlock_conditions = unlock_conditions .into_iter() .map(UnlockCondition::from) @@ -816,7 +787,6 @@ mod tests { let test_split_dto = |builder: FoundryOutputBuilder| { let output_split = FoundryOutput::try_from_dtos( builder.amount, - Some(builder.native_tokens.iter().copied().collect()), builder.serial_number, builder.token_scheme.clone(), builder.unlock_conditions.iter().map(Into::into).collect(), @@ -828,7 +798,7 @@ mod tests { }; let builder = FoundryOutput::build_with_amount(100, 123, rand_token_scheme()) - .add_native_token(NativeToken::new(TokenId::from(foundry_id), 1000).unwrap()) + .with_native_token(NativeToken::new(TokenId::from(foundry_id), 1000).unwrap()) .add_unlock_condition(ImmutableAccountAddressUnlockCondition::new(rand_account_address())) .add_immutable_feature(rand_metadata_feature()) .with_features(rand_allowed_features(FoundryOutput::ALLOWED_FEATURES)); @@ -839,7 +809,7 @@ mod tests { 123, rand_token_scheme(), ) - .add_native_token(NativeToken::new(TokenId::from(foundry_id), 1000).unwrap()) + .with_native_token(NativeToken::new(TokenId::from(foundry_id), 1000).unwrap()) .add_unlock_condition(ImmutableAccountAddressUnlockCondition::new(rand_account_address())) .add_immutable_feature(rand_metadata_feature()) .with_features(rand_allowed_features(FoundryOutput::ALLOWED_FEATURES)); diff --git a/sdk/src/types/block/output/mod.rs b/sdk/src/types/block/output/mod.rs index 9bbe5280c2..dc0ab45a58 100644 --- a/sdk/src/types/block/output/mod.rs +++ b/sdk/src/types/block/output/mod.rs @@ -193,18 +193,6 @@ impl Output { } } - /// Returns the native tokens of an [`Output`], if any. - pub fn native_tokens(&self) -> Option<&NativeTokens> { - match self { - Self::Basic(output) => Some(output.native_tokens()), - Self::Account(output) => Some(output.native_tokens()), - Self::Anchor(output) => Some(output.native_tokens()), - Self::Foundry(output) => Some(output.native_tokens()), - Self::Nft(output) => Some(output.native_tokens()), - Self::Delegation(_) => None, - } - } - /// Returns the unlock conditions of an [`Output`], if any. pub fn unlock_conditions(&self) -> Option<&UnlockConditions> { match self { @@ -229,6 +217,18 @@ impl Output { } } + /// Returns the native token of an [`Output`], if any. + pub fn native_token(&self) -> Option<&NativeToken> { + match self { + Self::Basic(output) => output.native_token(), + Self::Account(_) => None, + Self::Anchor(_) => None, + Self::Foundry(output) => output.native_token(), + Self::Nft(_) => None, + Self::Delegation(_) => None, + } + } + /// Returns the immutable features of an [`Output`], if any. pub fn immutable_features(&self) -> Option<&Features> { match self { diff --git a/sdk/src/types/block/output/native_token.rs b/sdk/src/types/block/output/native_token.rs index d2c430f718..5aee716319 100644 --- a/sdk/src/types/block/output/native_token.rs +++ b/sdk/src/types/block/output/native_token.rs @@ -12,10 +12,7 @@ use iterator_sorted::is_unique_sorted; use packable::{bounded::BoundedU8, prefix::BoxedSlicePrefix, Packable}; use primitive_types::U256; -use crate::types::block::{ - output::{FoundryId, StorageScore}, - Error, -}; +use crate::types::block::{output::FoundryId, Error}; crate::impl_id!( /// Unique identifier of a [`NativeToken`](crate::types::block::output::NativeToken). @@ -80,9 +77,6 @@ impl Ord for NativeToken { } } -// TODO remove when NT are a feature -impl StorageScore for NativeToken {} - #[inline] fn verify_amount(amount: &U256) -> Result<(), Error> { if VERIFY && amount.is_zero() { diff --git a/sdk/src/types/block/output/nft.rs b/sdk/src/types/block/output/nft.rs index 8c00c17128..0a48fe21ba 100644 --- a/sdk/src/types/block/output/nft.rs +++ b/sdk/src/types/block/output/nft.rs @@ -18,8 +18,8 @@ use crate::types::block::{ verify_allowed_unlock_conditions, AddressUnlockCondition, StorageDepositReturnUnlockCondition, UnlockCondition, UnlockConditionFlags, UnlockConditions, }, - BasicOutputBuilder, ChainId, MinimumOutputAmount, NativeToken, NativeTokens, Output, OutputBuilderAmount, - OutputId, StateTransitionError, StateTransitionVerifier, StorageScore, StorageScoreParameters, + BasicOutputBuilder, ChainId, MinimumOutputAmount, Output, OutputBuilderAmount, OutputId, StateTransitionError, + StateTransitionVerifier, StorageScore, StorageScoreParameters, }, payload::signed_transaction::TransactionCapabilityFlag, protocol::ProtocolParameters, @@ -61,7 +61,6 @@ impl From for Address { pub struct NftOutputBuilder { amount: OutputBuilderAmount, mana: u64, - native_tokens: BTreeSet, nft_id: NftId, unlock_conditions: BTreeSet, features: BTreeSet, @@ -84,7 +83,6 @@ impl NftOutputBuilder { Self { amount, mana: Default::default(), - native_tokens: BTreeSet::new(), nft_id, unlock_conditions: BTreeSet::new(), features: BTreeSet::new(), @@ -113,20 +111,6 @@ impl NftOutputBuilder { self } - /// - #[inline(always)] - pub fn add_native_token(mut self, native_token: NativeToken) -> Self { - self.native_tokens.insert(native_token); - self - } - - /// - #[inline(always)] - pub fn with_native_tokens(mut self, native_tokens: impl IntoIterator) -> Self { - self.native_tokens = native_tokens.into_iter().collect(); - self - } - /// Sets the NFT ID to the provided value. #[inline(always)] pub fn with_nft_id(mut self, nft_id: NftId) -> Self { @@ -283,7 +267,6 @@ impl NftOutputBuilder { let mut output = NftOutput { amount: 0, mana: self.mana, - native_tokens: NativeTokens::from_set(self.native_tokens)?, nft_id: self.nft_id, unlock_conditions, features, @@ -309,7 +292,6 @@ impl From<&NftOutput> for NftOutputBuilder { Self { amount: OutputBuilderAmount::Amount(output.amount), mana: output.mana, - native_tokens: output.native_tokens.iter().copied().collect(), nft_id: output.nft_id, unlock_conditions: output.unlock_conditions.iter().cloned().collect(), features: output.features.iter().cloned().collect(), @@ -325,8 +307,6 @@ pub struct NftOutput { amount: u64, /// Amount of stored Mana held by this output. mana: u64, - /// Native tokens held by this output. - native_tokens: NativeTokens, /// Unique identifier of the NFT. nft_id: NftId, /// Define how the output can be unlocked in a transaction. @@ -376,12 +356,6 @@ impl NftOutput { self.mana } - /// - #[inline(always)] - pub fn native_tokens(&self) -> &NativeTokens { - &self.native_tokens - } - /// #[inline(always)] pub fn nft_id(&self) -> &NftId { @@ -520,7 +494,6 @@ impl Packable for NftOutput { fn pack(&self, packer: &mut P) -> Result<(), P::Error> { self.amount.pack(packer)?; self.mana.pack(packer)?; - self.native_tokens.pack(packer)?; self.nft_id.pack(packer)?; self.unlock_conditions.pack(packer)?; self.features.pack(packer)?; @@ -537,7 +510,6 @@ impl Packable for NftOutput { let mana = u64::unpack::<_, VERIFY>(unpacker, &()).coerce()?; - let native_tokens = NativeTokens::unpack::<_, VERIFY>(unpacker, &())?; let nft_id = NftId::unpack::<_, VERIFY>(unpacker, &()).coerce()?; let unlock_conditions = UnlockConditions::unpack::<_, VERIFY>(unpacker, visitor)?; @@ -561,7 +533,6 @@ impl Packable for NftOutput { Ok(Self { amount, mana, - native_tokens, nft_id, unlock_conditions, features, @@ -605,8 +576,6 @@ pub(crate) mod dto { pub amount: u64, #[serde(with = "string")] pub mana: u64, - #[serde(skip_serializing_if = "Vec::is_empty", default)] - pub native_tokens: Vec, pub nft_id: NftId, pub unlock_conditions: Vec, #[serde(skip_serializing_if = "Vec::is_empty", default)] @@ -621,7 +590,6 @@ pub(crate) mod dto { kind: NftOutput::KIND, amount: value.amount(), mana: value.mana(), - native_tokens: value.native_tokens().to_vec(), nft_id: *value.nft_id(), unlock_conditions: value.unlock_conditions().iter().map(Into::into).collect::<_>(), features: value.features().to_vec(), @@ -636,7 +604,6 @@ pub(crate) mod dto { fn try_from(dto: NftOutputDto) -> Result { let mut builder = NftOutputBuilder::new_with_amount(dto.amount, dto.nft_id) .with_mana(dto.mana) - .with_native_tokens(dto.native_tokens) .with_features(dto.features) .with_immutable_features(dto.immutable_features); @@ -653,7 +620,6 @@ pub(crate) mod dto { pub fn try_from_dtos( amount: OutputBuilderAmount, mana: u64, - native_tokens: Option>, nft_id: &NftId, unlock_conditions: Vec, features: Option>, @@ -667,10 +633,6 @@ pub(crate) mod dto { } .with_mana(mana); - if let Some(native_tokens) = native_tokens { - builder = builder.with_native_tokens(native_tokens); - } - let unlock_conditions = unlock_conditions .into_iter() .map(UnlockCondition::from) @@ -696,13 +658,10 @@ mod tests { use super::*; use crate::types::block::{ - output::{dto::OutputDto, FoundryId, SimpleTokenScheme, TokenId}, + output::dto::OutputDto, protocol::protocol_parameters, - rand::{ - address::rand_account_address, - output::{ - feature::rand_allowed_features, rand_nft_output, unlock_condition::rand_address_unlock_condition, - }, + rand::output::{ + feature::rand_allowed_features, rand_nft_output, unlock_condition::rand_address_unlock_condition, }, }; @@ -716,12 +675,9 @@ mod tests { let output_ver = Output::try_from(dto).unwrap(); assert_eq!(&output, output_ver.as_nft()); - let foundry_id = FoundryId::build(&rand_account_address(), 0, SimpleTokenScheme::KIND); - let output_split = NftOutput::try_from_dtos( OutputBuilderAmount::Amount(output.amount()), output.mana(), - Some(output.native_tokens().to_vec()), output.nft_id(), output.unlock_conditions().iter().map(Into::into).collect(), Some(output.features().to_vec()), @@ -734,7 +690,6 @@ mod tests { let output_split = NftOutput::try_from_dtos( builder.amount, builder.mana, - Some(builder.native_tokens.iter().copied().collect()), &builder.nft_id, builder.unlock_conditions.iter().map(Into::into).collect(), Some(builder.features.iter().cloned().collect()), @@ -745,7 +700,6 @@ mod tests { }; let builder = NftOutput::build_with_amount(100, NftId::null()) - .add_native_token(NativeToken::new(TokenId::from(foundry_id), 1000).unwrap()) .add_unlock_condition(rand_address_unlock_condition()) .with_features(rand_allowed_features(NftOutput::ALLOWED_FEATURES)) .with_immutable_features(rand_allowed_features(NftOutput::ALLOWED_IMMUTABLE_FEATURES)); @@ -753,7 +707,6 @@ mod tests { let builder = NftOutput::build_with_minimum_amount(protocol_parameters.storage_score_parameters(), NftId::null()) - .add_native_token(NativeToken::new(TokenId::from(foundry_id), 1000).unwrap()) .add_unlock_condition(rand_address_unlock_condition()) .with_features(rand_allowed_features(NftOutput::ALLOWED_FEATURES)) .with_immutable_features(rand_allowed_features(NftOutput::ALLOWED_IMMUTABLE_FEATURES)); diff --git a/sdk/src/types/block/payload/signed_transaction/transaction.rs b/sdk/src/types/block/payload/signed_transaction/transaction.rs index 8b8bea5d33..2682350a3b 100644 --- a/sdk/src/types/block/payload/signed_transaction/transaction.rs +++ b/sdk/src/types/block/payload/signed_transaction/transaction.rs @@ -13,7 +13,7 @@ use crate::{ context_input::{ContextInput, CONTEXT_INPUT_COUNT_RANGE}, input::{Input, INPUT_COUNT_RANGE}, mana::{verify_mana_allotments_sum, ManaAllotment, ManaAllotments}, - output::{NativeTokens, Output, OUTPUT_COUNT_RANGE}, + output::{Output, OUTPUT_COUNT_RANGE}, payload::{ signed_transaction::{TransactionHash, TransactionId, TransactionSigningHash}, OptionalPayload, Payload, @@ -425,17 +425,16 @@ fn verify_payload_packable( fn verify_outputs(outputs: &[Output], visitor: &ProtocolParameters) -> Result<(), Error> { if VERIFY { let mut amount_sum: u64 = 0; - let mut native_tokens_count: u8 = 0; let mut chain_ids = HashSet::new(); for output in outputs.iter() { - let (amount, native_tokens, chain_id) = match output { - Output::Basic(output) => (output.amount(), Some(output.native_tokens()), None), - Output::Account(output) => (output.amount(), Some(output.native_tokens()), Some(output.chain_id())), - Output::Anchor(output) => (output.amount(), None, Some(output.chain_id())), - Output::Foundry(output) => (output.amount(), Some(output.native_tokens()), Some(output.chain_id())), - Output::Nft(output) => (output.amount(), Some(output.native_tokens()), Some(output.chain_id())), - Output::Delegation(output) => (output.amount(), None, Some(output.chain_id())), + let (amount, chain_id) = match output { + Output::Basic(output) => (output.amount(), None), + Output::Account(output) => (output.amount(), Some(output.chain_id())), + Output::Anchor(output) => (output.amount(), Some(output.chain_id())), + Output::Foundry(output) => (output.amount(), Some(output.chain_id())), + Output::Nft(output) => (output.amount(), Some(output.chain_id())), + Output::Delegation(output) => (output.amount(), Some(output.chain_id())), }; amount_sum = amount_sum @@ -447,16 +446,6 @@ fn verify_outputs(outputs: &[Output], visitor: &ProtocolPara return Err(Error::InvalidTransactionAmountSum(amount_sum as u128)); } - if let Some(native_tokens) = native_tokens { - native_tokens_count = native_tokens_count.checked_add(native_tokens.len() as u8).ok_or( - Error::InvalidTransactionNativeTokensCount(native_tokens_count as u16 + native_tokens.len() as u16), - )?; - - if native_tokens_count > NativeTokens::COUNT_MAX { - return Err(Error::InvalidTransactionNativeTokensCount(native_tokens_count as u16)); - } - } - if let Some(chain_id) = chain_id { if !chain_id.is_null() && !chain_ids.insert(chain_id) { return Err(Error::DuplicateOutputChain(chain_id)); diff --git a/sdk/src/types/block/rand/output/feature.rs b/sdk/src/types/block/rand/output/feature.rs index 85ebdbb374..57a8fdd609 100644 --- a/sdk/src/types/block/rand/output/feature.rs +++ b/sdk/src/types/block/rand/output/feature.rs @@ -6,12 +6,13 @@ use alloc::{collections::BTreeSet, vec::Vec}; use crate::types::block::{ output::feature::{ BlockIssuerFeature, BlockIssuerKey, BlockIssuerKeys, Ed25519BlockIssuerKey, Feature, FeatureFlags, - IssuerFeature, MetadataFeature, SenderFeature, StakingFeature, TagFeature, + IssuerFeature, MetadataFeature, NativeTokenFeature, SenderFeature, StakingFeature, TagFeature, }, rand::{ address::rand_address, bytes::rand_bytes, number::{rand_number, rand_number_range}, + output::rand_native_token, slot::{rand_epoch_index, rand_slot_index}, }, }; @@ -62,6 +63,11 @@ pub fn rand_block_issuer_keys(len: usize) -> BTreeSet { block_issuer_keys } +/// Generates a random [`NativeTokenFeature`]. +pub fn rand_native_token_feature() -> NativeTokenFeature { + NativeTokenFeature::new(rand_native_token()) +} + /// Generates a random [`BlockIssuerFeature`]. pub fn rand_block_issuer_feature() -> BlockIssuerFeature { BlockIssuerFeature::new( @@ -84,6 +90,7 @@ fn rand_feature_from_flag(flag: &FeatureFlags) -> Feature { FeatureFlags::ISSUER => Feature::Issuer(rand_issuer_feature()), FeatureFlags::METADATA => Feature::Metadata(rand_metadata_feature()), FeatureFlags::TAG => Feature::Tag(rand_tag_feature()), + FeatureFlags::NATIVE_TOKEN => Feature::NativeToken(rand_native_token_feature()), FeatureFlags::BLOCK_ISSUER => Feature::BlockIssuer(rand_block_issuer_feature()), FeatureFlags::STAKING => Feature::Staking(rand_staking_feature()), _ => unreachable!(), diff --git a/sdk/src/types/block/rand/output/mod.rs b/sdk/src/types/block/rand/output/mod.rs index 53b81781c7..f96ada2d25 100644 --- a/sdk/src/types/block/rand/output/mod.rs +++ b/sdk/src/types/block/rand/output/mod.rs @@ -5,12 +5,14 @@ pub mod feature; /// Module providing random output metadata generation utilities. pub mod metadata; +/// Module providing random native token generation utilities. +pub mod native_token; /// Module providing random unlock condition generation utilities. pub mod unlock_condition; use primitive_types::U256; -pub use self::metadata::rand_output_metadata; +pub use self::{metadata::rand_output_metadata, native_token::rand_native_token}; use crate::types::block::{ output::{ unlock_condition::ImmutableAccountAddressUnlockCondition, AccountId, AccountOutput, AnchorId, AnchorOutput, diff --git a/sdk/src/types/block/rand/output/native_token.rs b/sdk/src/types/block/rand/output/native_token.rs new file mode 100644 index 0000000000..06ef180063 --- /dev/null +++ b/sdk/src/types/block/rand/output/native_token.rs @@ -0,0 +1,14 @@ +// Copyright 2023 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use primitive_types::U256; + +use crate::types::block::{ + output::{NativeToken, TokenId}, + rand::{bytes::rand_bytes_array, number::rand_number}, +}; + +/// Generates a random [`NativeToken`]. +pub fn rand_native_token() -> NativeToken { + NativeToken::new(TokenId::from(rand_bytes_array()), U256::from(rand_number::() + 1)).unwrap() +} diff --git a/sdk/src/types/block/semantic.rs b/sdk/src/types/block/semantic.rs index 6359cee8e7..6f2b7f726b 100644 --- a/sdk/src/types/block/semantic.rs +++ b/sdk/src/types/block/semantic.rs @@ -258,19 +258,19 @@ impl<'a> SemanticValidationContext<'a> { pub fn validate(mut self) -> Result, Error> { // Validation of inputs. for ((output_id, consumed_output), unlock) in self.inputs.iter().zip(self.unlocks.iter()) { - let (conflict, amount, mana, consumed_native_tokens, unlock_conditions) = match consumed_output { + let (conflict, amount, mana, consumed_native_token, unlock_conditions) = match consumed_output { Output::Basic(output) => ( output.unlock(output_id, unlock, &mut self), output.amount(), output.mana(), - Some(output.native_tokens()), + output.native_token(), output.unlock_conditions(), ), Output::Account(output) => ( output.unlock(output_id, unlock, &mut self), output.amount(), output.mana(), - Some(output.native_tokens()), + None, output.unlock_conditions(), ), Output::Anchor(_) => return Err(Error::UnsupportedOutputKind(AnchorOutput::KIND)), @@ -278,14 +278,14 @@ impl<'a> SemanticValidationContext<'a> { output.unlock(output_id, unlock, &mut self), output.amount(), 0, - Some(output.native_tokens()), + output.native_token(), output.unlock_conditions(), ), Output::Nft(output) => ( output.unlock(output_id, unlock, &mut self), output.amount(), output.mana(), - Some(output.native_tokens()), + None, output.unlock_conditions(), ), Output::Delegation(output) => ( @@ -325,20 +325,21 @@ impl<'a> SemanticValidationContext<'a> { self.input_mana = self.input_mana.checked_add(mana).ok_or(Error::ConsumedManaOverflow)?; - if let Some(consumed_native_tokens) = consumed_native_tokens { - for native_token in consumed_native_tokens.iter() { - let native_token_amount = self.input_native_tokens.entry(*native_token.token_id()).or_default(); + if let Some(consumed_native_token) = consumed_native_token { + let native_token_amount = self + .input_native_tokens + .entry(*consumed_native_token.token_id()) + .or_default(); - *native_token_amount = native_token_amount - .checked_add(native_token.amount()) - .ok_or(Error::ConsumedNativeTokensAmountOverflow)?; - } + *native_token_amount = native_token_amount + .checked_add(consumed_native_token.amount()) + .ok_or(Error::ConsumedNativeTokensAmountOverflow)?; } } // Validation of outputs. for created_output in self.transaction.outputs() { - let (amount, mana, created_native_tokens, features) = match created_output { + let (amount, mana, created_native_token, features) = match created_output { Output::Basic(output) => { if let Some(address) = output.simple_deposit_address() { let amount = self.simple_deposits.entry(address.clone()).or_default(); @@ -351,29 +352,14 @@ impl<'a> SemanticValidationContext<'a> { ( output.amount(), output.mana(), - Some(output.native_tokens()), + output.native_token(), Some(output.features()), ) } - Output::Account(output) => ( - output.amount(), - output.mana(), - Some(output.native_tokens()), - Some(output.features()), - ), + Output::Account(output) => (output.amount(), output.mana(), None, Some(output.features())), Output::Anchor(_) => return Err(Error::UnsupportedOutputKind(AnchorOutput::KIND)), - Output::Foundry(output) => ( - output.amount(), - 0, - Some(output.native_tokens()), - Some(output.features()), - ), - Output::Nft(output) => ( - output.amount(), - output.mana(), - Some(output.native_tokens()), - Some(output.features()), - ), + Output::Foundry(output) => (output.amount(), 0, output.native_token(), Some(output.features())), + Output::Nft(output) => (output.amount(), output.mana(), None, Some(output.features())), Output::Delegation(output) => (output.amount(), 0, None, None), }; @@ -390,14 +376,14 @@ impl<'a> SemanticValidationContext<'a> { }) .filter_map(Address::as_restricted_opt); for address in addresses { - if created_output.native_tokens().map(|t| t.len()).unwrap_or_default() > 0 + if created_native_token.is_some() && !address.has_capability(AddressCapabilityFlag::OutputsWithNativeTokens) { // TODO: add a variant https://github.com/iotaledger/iota-sdk/issues/1430 return Ok(Some(TransactionFailureReason::SemanticValidationFailed)); } - if created_output.mana() > 0 && !address.has_capability(AddressCapabilityFlag::OutputsWithMana) { + if mana > 0 && !address.has_capability(AddressCapabilityFlag::OutputsWithMana) { // TODO: add a variant https://github.com/iotaledger/iota-sdk/issues/1430 return Ok(Some(TransactionFailureReason::SemanticValidationFailed)); } @@ -449,14 +435,15 @@ impl<'a> SemanticValidationContext<'a> { self.output_mana = self.output_mana.checked_add(mana).ok_or(Error::CreatedManaOverflow)?; - if let Some(created_native_tokens) = created_native_tokens { - for native_token in created_native_tokens.iter() { - let native_token_amount = self.output_native_tokens.entry(*native_token.token_id()).or_default(); + if let Some(created_native_token) = created_native_token { + let native_token_amount = self + .output_native_tokens + .entry(*created_native_token.token_id()) + .or_default(); - *native_token_amount = native_token_amount - .checked_add(native_token.amount()) - .ok_or(Error::CreatedNativeTokensAmountOverflow)?; - } + *native_token_amount = native_token_amount + .checked_add(created_native_token.amount()) + .ok_or(Error::CreatedNativeTokensAmountOverflow)?; } } diff --git a/sdk/src/wallet/mod.rs b/sdk/src/wallet/mod.rs index 258d5be150..ed5b3b6e67 100644 --- a/sdk/src/wallet/mod.rs +++ b/sdk/src/wallet/mod.rs @@ -60,7 +60,7 @@ pub use self::{ mint_nfts::MintNftParams, }, send::SendParams, - send_native_tokens::SendNativeTokensParams, + send_native_tokens::SendNativeTokenParams, send_nft::SendNftParams, }, prepare_output::{Assets, Features, OutputParams, ReturnStrategy, StorageDeposit, Unlocks}, diff --git a/sdk/src/wallet/operations/balance.rs b/sdk/src/wallet/operations/balance.rs index 1bd8e93d95..374e74cc90 100644 --- a/sdk/src/wallet/operations/balance.rs +++ b/sdk/src/wallet/operations/balance.rs @@ -73,8 +73,6 @@ where if !wallet_data.locked_outputs.contains(output_id) { total_storage_cost += storage_cost; } - // Add native tokens - total_native_tokens.add_native_tokens(output.native_tokens().clone())?; let account_id = output.account_id_non_null(output_id); balance.accounts.push(account_id); @@ -87,8 +85,11 @@ where if !wallet_data.locked_outputs.contains(output_id) { total_storage_cost += storage_cost; } - // Add native tokens - total_native_tokens.add_native_tokens(output.native_tokens().clone())?; + + // Add native token + if let Some(native_token) = output.native_token() { + total_native_tokens.add_native_token(native_token.clone())?; + } balance.foundries.push(output.id()); } @@ -112,12 +113,7 @@ where // Add storage deposit if output.is_basic() { balance.required_storage_deposit.basic += storage_cost; - if output - .native_tokens() - .map(|native_tokens| !native_tokens.is_empty()) - .unwrap_or(false) - && !wallet_data.locked_outputs.contains(output_id) - { + if output.native_token().is_some() && !wallet_data.locked_outputs.contains(output_id) { total_storage_cost += storage_cost; } } else if output.is_nft() { @@ -127,9 +123,9 @@ where } } - // Add native tokens - if let Some(native_tokens) = output.native_tokens() { - total_native_tokens.add_native_tokens(native_tokens.clone())?; + // Add native token + if let Some(native_token) = output.native_token() { + total_native_tokens.add_native_token(native_token.clone())?; } } else { // if we have multiple unlock conditions for basic or nft outputs, then we can't @@ -187,13 +183,9 @@ where // Add storage deposit if output.is_basic() { balance.required_storage_deposit.basic += storage_cost; - // Amount for basic outputs isn't added to total storage cost if there aren't - // native tokens, since we can - // spend it without burning. - if output - .native_tokens() - .map(|native_tokens| !native_tokens.is_empty()) - .unwrap_or(false) + // Amount for basic outputs isn't added to total storage cost if there aren't native + // tokens, since we can spend it without burning. + if output.native_token().is_some() && !wallet_data.locked_outputs.contains(output_id) { total_storage_cost += storage_cost; @@ -205,9 +197,9 @@ where } } - // Add native tokens - if let Some(native_tokens) = output.native_tokens() { - total_native_tokens.add_native_tokens(native_tokens.clone())?; + // Add native token + if let Some(native_token) = output.native_token() { + total_native_tokens.add_native_token(native_token.clone())?; } } else { // only add outputs that can't be locked now and at any point in the future @@ -267,8 +259,8 @@ where // Only check outputs that are in this network if output_data.network_id == network_id { locked_amount += output_data.output.amount(); - if let Some(native_tokens) = output_data.output.native_tokens() { - locked_native_tokens.add_native_tokens(native_tokens.clone())?; + if let Some(native_token) = output_data.output.native_token() { + locked_native_tokens.add_native_token(native_token.clone())?; } } } diff --git a/sdk/src/wallet/operations/output_claiming.rs b/sdk/src/wallet/operations/output_claiming.rs index a5d27a32f3..2db2b94d41 100644 --- a/sdk/src/wallet/operations/output_claiming.rs +++ b/sdk/src/wallet/operations/output_claiming.rs @@ -11,7 +11,7 @@ use crate::{ address::{Address, Ed25519Address}, output::{ unlock_condition::{AddressUnlockCondition, StorageDepositReturnUnlockCondition}, - BasicOutput, BasicOutputBuilder, NativeTokens, NativeTokensBuilder, NftOutputBuilder, Output, OutputId, + BasicOutput, BasicOutputBuilder, NativeTokensBuilder, NftOutputBuilder, Output, OutputId, }, slot::SlotIndex, }, @@ -86,9 +86,10 @@ where } } OutputsToClaim::NativeTokens => { - if !output_data.output.native_tokens().map(|n| n.is_empty()).unwrap_or(true) { - output_ids_to_claim.insert(output_data.output_id); - } + // TODO https://github.com/iotaledger/iota-sdk/issues/1633 + // if !output_data.output.native_tokens().map(|n| n.is_empty()).unwrap_or(true) { + // output_ids_to_claim.insert(output_data.output_id); + // } } OutputsToClaim::Nfts => { if output_data.output.is_nft() { @@ -246,13 +247,8 @@ where // check native tokens for output_data in &outputs_to_claim { - if let Some(native_tokens) = output_data.output.native_tokens() { - // Skip output if the max native tokens count would be exceeded - if get_new_native_token_count(&new_native_tokens, native_tokens)? > NativeTokens::COUNT_MAX.into() { - log::debug!("[OUTPUT_CLAIMING] skipping output to not exceed the max native tokens count"); - continue; - } - new_native_tokens.add_native_tokens(native_tokens.clone())?; + if let Some(native_token) = output_data.output.native_token() { + new_native_tokens.add_native_token(native_token.clone())?; } if let Some(sdr) = sdr_not_expired(&output_data.output, slot_index) { // for own output subtract the return amount @@ -282,8 +278,6 @@ where .with_minimum_amount(storage_score_params) .with_nft_id(nft_output.nft_id_non_null(&output_data.output_id)) .with_unlock_conditions([AddressUnlockCondition::new(wallet_address.clone())]) - // Set native tokens empty, we will collect them from all inputs later - .with_native_tokens([]) .finish_output()? }; @@ -308,7 +302,8 @@ where required_amount_for_nfts + BasicOutputBuilder::new_with_minimum_amount(storage_score_params) .add_unlock_condition(AddressUnlockCondition::new(Ed25519Address::null())) - .with_native_tokens(option_native_token.into_iter().flatten()) + // TODO https://github.com/iotaledger/iota-sdk/issues/1633 + // .with_native_tokens(option_native_token.into_iter().flatten()) .finish()? .amount() }; @@ -330,23 +325,15 @@ where required_amount = required_amount_for_nfts + BasicOutputBuilder::new_with_minimum_amount(storage_score_params) .add_unlock_condition(AddressUnlockCondition::new(Ed25519Address::null())) - .with_native_tokens(option_native_token.into_iter().flatten()) + // TODO https://github.com/iotaledger/iota-sdk/issues/1633 + // .with_native_token(option_native_token) .finish()? .amount(); if available_amount < required_amount { if !additional_inputs_used.contains(&output_data.output_id) { - if let Some(native_tokens) = output_data.output.native_tokens() { - // Skip input if the max native tokens count would be exceeded - if get_new_native_token_count(&new_native_tokens, native_tokens)? - > NativeTokens::COUNT_MAX.into() - { - log::debug!( - "[OUTPUT_CLAIMING] skipping input to not exceed the max native tokens count" - ); - continue; - } - new_native_tokens.add_native_tokens(native_tokens.clone())?; + if let Some(native_token) = output_data.output.native_token() { + new_native_tokens.add_native_token(native_token.clone())?; } available_amount += output_data.output.amount(); additional_inputs.push(output_data.output_id); @@ -380,7 +367,8 @@ where outputs_to_send.push( BasicOutputBuilder::new_with_amount(available_amount - required_amount_for_nfts) .add_unlock_condition(AddressUnlockCondition::new(wallet_address)) - .with_native_tokens(new_native_tokens.finish()?) + // TODO https://github.com/iotaledger/iota-sdk/issues/1633 + // .with_native_tokens(new_native_tokens.finish()?) .finish_output()?, ); } else if !new_native_tokens.finish()?.is_empty() { @@ -429,15 +417,3 @@ pub(crate) fn sdr_not_expired(output: &Output, slot_index: SlotIndex) -> Option< }) }) } - -// Helper function to calculate the native token count without duplicates, when new native tokens are added -// Might be possible to refactor the sections where it's used to remove the clones -pub(crate) fn get_new_native_token_count( - native_tokens_builder: &NativeTokensBuilder, - native_tokens: &NativeTokens, -) -> crate::wallet::Result { - // Clone to get the new native token count without actually modifying it - let mut native_tokens_count = native_tokens_builder.clone(); - native_tokens_count.add_native_tokens(native_tokens.clone())?; - Ok(native_tokens_count.len()) -} diff --git a/sdk/src/wallet/operations/output_consolidation.rs b/sdk/src/wallet/operations/output_consolidation.rs index b1854a12b0..1e8a3c8d97 100644 --- a/sdk/src/wallet/operations/output_consolidation.rs +++ b/sdk/src/wallet/operations/output_consolidation.rs @@ -10,17 +10,12 @@ use crate::{ types::block::{ address::{Address, Bech32Address}, input::INPUT_COUNT_MAX, - output::{ - unlock_condition::AddressUnlockCondition, BasicOutputBuilder, NativeTokens, NativeTokensBuilder, Output, - }, + output::{unlock_condition::AddressUnlockCondition, BasicOutputBuilder, NativeTokensBuilder, Output}, slot::SlotIndex, }, wallet::{ constants::DEFAULT_OUTPUT_CONSOLIDATION_THRESHOLD, - operations::{ - helpers::time::can_output_be_unlocked_now, output_claiming::get_new_native_token_count, - transaction::TransactionOptions, - }, + operations::{helpers::time::can_output_be_unlocked_now, transaction::TransactionOptions}, types::{OutputData, TransactionWithMetadata}, Result, Wallet, }, @@ -236,13 +231,8 @@ where let mut total_native_tokens = NativeTokensBuilder::new(); for output_data in outputs_to_consolidate.iter().take(max_inputs.into()) { - if let Some(native_tokens) = output_data.output.native_tokens() { - // Skip output if the max native tokens count would be exceeded - if get_new_native_token_count(&total_native_tokens, native_tokens)? > NativeTokens::COUNT_MAX.into() { - log::debug!("[OUTPUT_CONSOLIDATION] skipping output to not exceed the max native tokens count"); - continue; - } - total_native_tokens.add_native_tokens(native_tokens.clone())?; + if let Some(native_token) = output_data.output.native_token() { + total_native_tokens.add_native_token(native_token.clone())?; }; total_amount += output_data.output.amount(); @@ -256,7 +246,8 @@ where .map(|bech32| bech32.into_inner()) .unwrap_or_else(|| outputs_to_consolidate[0].address.clone()), )) - .with_native_tokens(total_native_tokens.finish()?) + // TODO https://github.com/iotaledger/iota-sdk/issues/1632 + // .with_native_tokens(total_native_tokens.finish()?) .finish_output()?]; let options = Some(TransactionOptions { diff --git a/sdk/src/wallet/operations/syncing/mod.rs b/sdk/src/wallet/operations/syncing/mod.rs index b5fccd6a82..2d3b616bd7 100644 --- a/sdk/src/wallet/operations/syncing/mod.rs +++ b/sdk/src/wallet/operations/syncing/mod.rs @@ -143,10 +143,10 @@ where if options.sync_native_token_foundries { let native_token_foundry_ids = outputs_data .iter() - .filter_map(|output| output.output.native_tokens()) - .flat_map(|native_tokens| { - native_tokens - .iter() + .filter_map(|output| { + output + .output + .native_token() .map(|native_token| FoundryId::from(*native_token.token_id())) }) .collect::>(); diff --git a/sdk/src/wallet/operations/transaction/high_level/send_native_tokens.rs b/sdk/src/wallet/operations/transaction/high_level/send_native_tokens.rs index a3dbc318b4..1ec3794083 100644 --- a/sdk/src/wallet/operations/transaction/high_level/send_native_tokens.rs +++ b/sdk/src/wallet/operations/transaction/high_level/send_native_tokens.rs @@ -11,7 +11,7 @@ use crate::{ address::{Bech32Address, ToBech32Ext}, output::{ unlock_condition::{AddressUnlockCondition, ExpirationUnlockCondition}, - BasicOutputBuilder, NativeToken, NativeTokens, TokenId, + BasicOutputBuilder, NativeToken, TokenId, }, slot::SlotIndex, }, @@ -26,13 +26,13 @@ use crate::{ /// Params for `send_native_tokens()` #[derive(Debug, Clone, Serialize, Deserialize, Getters)] #[serde(rename_all = "camelCase")] -pub struct SendNativeTokensParams { +pub struct SendNativeTokenParams { /// Bech32 encoded address #[getset(get = "pub")] address: Bech32Address, - /// Native tokens + /// Native token #[getset(get = "pub")] - native_tokens: Vec<(TokenId, U256)>, + native_token: (TokenId, U256), /// Bech32 encoded address return address, to which the storage deposit will be returned. Default will use the /// address of the wallet. #[getset(get = "pub")] @@ -43,15 +43,12 @@ pub struct SendNativeTokensParams { expiration: Option, } -impl SendNativeTokensParams { - /// Creates a new instance of [`SendNativeTokensParams`] - pub fn new( - address: impl ConvertTo, - native_tokens: impl IntoIterator, - ) -> Result { +impl SendNativeTokenParams { + /// Creates a new instance of [`SendNativeTokenParams`] + pub fn new(address: impl ConvertTo, native_token: (TokenId, U256)) -> Result { Ok(Self { address: address.convert()?, - native_tokens: native_tokens.into_iter().collect(), + native_token, return_address: None, expiration: None, }) @@ -87,12 +84,12 @@ where /// Calls [Account::send_outputs()](crate::wallet::Account::send_outputs) internally. The options may define the /// remainder value strategy or custom inputs. Note that the address needs to be bech32-encoded. /// ```ignore - /// let params = [SendNativeTokensParams { + /// let params = [SendNativeTokenParams { /// address: "rms1qpszqzadsym6wpppd6z037dvlejmjuke7s24hm95s9fg9vpua7vluaw60xu".to_string(), - /// native_tokens: vec![( + /// native_token: ( /// TokenId::from_str("08e68f7616cd4948efebc6a77c4f93aed770ac53860100000000000000000000000000000000")?, /// U256::from(50), - /// )], + /// ), /// ..Default::default() /// }]; /// @@ -102,7 +99,7 @@ where /// println!("Block sent: {}", block_id); /// } /// ``` - pub async fn send_native_tokens + Send>( + pub async fn send_native_tokens + Send>( &self, params: I, options: impl Into> + Send, @@ -118,7 +115,7 @@ where /// Prepares the transaction for /// [Account::send_native_tokens()](crate::wallet::Account::send_native_tokens). - pub async fn prepare_send_native_tokens + Send>( + pub async fn prepare_send_native_tokens + Send>( &self, params: I, options: impl Into> + Send, @@ -135,9 +132,9 @@ where let slot_index = self.client().get_slot_index().await?; let mut outputs = Vec::new(); - for SendNativeTokensParams { + for SendNativeTokenParams { address, - native_tokens, + native_token, return_address, expiration, } in params @@ -156,14 +153,7 @@ where .transpose()? .unwrap_or_else(|| default_return_address.clone()); - let native_tokens = NativeTokens::from_vec( - native_tokens - .into_iter() - .map(|(id, amount)| { - NativeToken::new(id, amount).map_err(|e| crate::wallet::Error::Client(Box::new(e.into()))) - }) - .collect::>>()?, - )?; + let native_token = NativeToken::new(native_token.0, native_token.1)?; let expiration_slot_index = expiration .map_or(slot_index + DEFAULT_EXPIRATION_SLOTS, |expiration_slot_index| { @@ -172,7 +162,7 @@ where outputs.push( BasicOutputBuilder::new_with_amount(0) - .with_native_tokens(native_tokens) + .with_native_token(native_token) .add_unlock_condition(AddressUnlockCondition::new(address)) .add_unlock_condition(ExpirationUnlockCondition::new( return_address.clone(), diff --git a/sdk/src/wallet/operations/transaction/prepare_output.rs b/sdk/src/wallet/operations/transaction/prepare_output.rs index afc93d3c2f..d34d8c1aa7 100644 --- a/sdk/src/wallet/operations/transaction/prepare_output.rs +++ b/sdk/src/wallet/operations/transaction/prepare_output.rs @@ -8,7 +8,7 @@ use crate::{ types::block::{ address::{Address, Bech32Address, Ed25519Address}, output::{ - feature::{IssuerFeature, MetadataFeature, SenderFeature, TagFeature}, + feature::{IssuerFeature, MetadataFeature, NativeTokenFeature, SenderFeature, TagFeature}, unlock_condition::{ AddressUnlockCondition, ExpirationUnlockCondition, StorageDepositReturnUnlockCondition, TimelockUnlockCondition, @@ -56,12 +56,6 @@ where .create_initial_output_builder(params.recipient_address, nft_id, storage_score_params) .await?; - if let Some(assets) = ¶ms.assets { - if let Some(native_tokens) = &assets.native_tokens { - first_output_builder = first_output_builder.with_native_tokens(native_tokens.clone()); - } - } - if let Some(features) = params.features { if let Some(tag) = features.tag { first_output_builder = first_output_builder.add_feature(TagFeature::new( @@ -85,6 +79,10 @@ where } first_output_builder = first_output_builder.add_immutable_feature(IssuerFeature::new(issuer)); } + + if let Some(native_token) = &features.native_token { + first_output_builder = first_output_builder.with_native_token(native_token.clone()); + } } if let Some(unlocks) = params.unlocks { @@ -312,7 +310,6 @@ pub struct OutputParams { #[derive(Debug, Default, Clone, Eq, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct Assets { - pub native_tokens: Option>, pub nft_id: Option, } @@ -322,6 +319,7 @@ pub struct Features { pub metadata: Option, pub issuer: Option, pub sender: Option, + pub native_token: Option, } #[derive(Debug, Default, Clone, Eq, PartialEq, Serialize, Deserialize)] @@ -418,15 +416,11 @@ impl OutputBuilder { } self } - fn with_native_tokens(mut self, native_tokens: impl IntoIterator) -> Self { - match self { - Self::Basic(b) => { - self = Self::Basic(b.with_native_tokens(native_tokens)); - } - Self::Nft(b) => { - self = Self::Nft(b.with_native_tokens(native_tokens)); - } + fn with_native_token(mut self, native_token: NativeToken) -> Self { + if let Self::Basic(b) = self { + self = Self::Basic(b.add_feature(NativeTokenFeature::from(native_token))); } + self } fn finish_output(self) -> Result { diff --git a/sdk/tests/client/input_selection/account_outputs.rs b/sdk/tests/client/input_selection/account_outputs.rs index 93469e6c4a..46be201a92 100644 --- a/sdk/tests/client/input_selection/account_outputs.rs +++ b/sdk/tests/client/input_selection/account_outputs.rs @@ -32,7 +32,6 @@ fn input_account_eq_output_account() { None, None, None, - None, )]); let outputs = build_outputs([Account( 1_000_000, @@ -41,7 +40,6 @@ fn input_account_eq_output_account() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -69,7 +67,6 @@ fn transition_account_id_zero() { None, None, None, - None, )]); let account_id = AccountId::from(inputs[0].output_id()); let outputs = build_outputs([Account( @@ -79,7 +76,6 @@ fn transition_account_id_zero() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -251,7 +247,6 @@ fn create_account() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -288,7 +283,6 @@ fn burn_account() { None, None, None, - None, )]); let outputs = build_outputs([Basic( 2_000_000, @@ -382,7 +376,6 @@ fn missing_input_for_account_output() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -406,15 +399,7 @@ fn missing_input_for_account_output_2() { let account_id_2 = AccountId::from_str(ACCOUNT_ID_2).unwrap(); let inputs = build_inputs([ - Account( - 2_000_000, - account_id_1, - BECH32_ADDRESS_ED25519_0, - None, - None, - None, - None, - ), + Account(2_000_000, account_id_1, BECH32_ADDRESS_ED25519_0, None, None, None), Basic(1_000_000, BECH32_ADDRESS_ED25519_0, None, None, None, None, None, None), ]); let outputs = build_outputs([Account( @@ -424,7 +409,6 @@ fn missing_input_for_account_output_2() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -463,7 +447,6 @@ fn missing_input_for_account_output_but_created() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -483,15 +466,7 @@ fn account_in_output_and_sender() { let account_id_1 = AccountId::from_str(ACCOUNT_ID_1).unwrap(); let inputs = build_inputs([ - Account( - 1_000_000, - account_id_1, - BECH32_ADDRESS_ED25519_0, - None, - None, - None, - None, - ), + Account(1_000_000, account_id_1, BECH32_ADDRESS_ED25519_0, None, None, None), Basic(1_000_000, BECH32_ADDRESS_ED25519_0, None, None, None, None, None, None), ]); let account_output = AccountOutputBuilder::from(inputs[0].output.as_account()) @@ -534,13 +509,11 @@ fn missing_ed25519_sender() { None, None, None, - None, )]); let outputs = build_outputs([Account( 1_000_000, account_id_2, BECH32_ADDRESS_ED25519_0, - None, Some(BECH32_ADDRESS_ED25519_1), None, None, @@ -580,7 +553,6 @@ fn missing_ed25519_issuer_created() { account_id_0, BECH32_ADDRESS_ED25519_0, None, - None, Some(BECH32_ADDRESS_ED25519_1), None, )]); @@ -609,7 +581,6 @@ fn missing_ed25519_issuer_transition() { account_id_1, BECH32_ADDRESS_ED25519_0, None, - None, Some(BECH32_ADDRESS_ED25519_1), None, )]); @@ -618,7 +589,6 @@ fn missing_ed25519_issuer_transition() { account_id_1, BECH32_ADDRESS_ED25519_0, None, - None, Some(BECH32_ADDRESS_ED25519_1), None, )]); @@ -646,13 +616,11 @@ fn missing_account_sender() { None, None, None, - None, )]); let outputs = build_outputs([Account( 1_000_000, account_id_2, BECH32_ADDRESS_ED25519_0, - None, Some(BECH32_ADDRESS_ACCOUNT_1), None, None, @@ -692,7 +660,6 @@ fn missing_account_issuer_created() { account_id_0, BECH32_ADDRESS_ED25519_0, None, - None, Some(BECH32_ADDRESS_ACCOUNT_1), None, )]); @@ -721,7 +688,6 @@ fn missing_account_issuer_transition() { account_id_2, BECH32_ADDRESS_ED25519_0, None, - None, Some(BECH32_ADDRESS_ACCOUNT_1), None, )]); @@ -730,7 +696,6 @@ fn missing_account_issuer_transition() { account_id_2, BECH32_ADDRESS_ED25519_0, None, - None, Some(BECH32_ADDRESS_ACCOUNT_1), None, )]); @@ -758,13 +723,11 @@ fn missing_nft_sender() { None, None, None, - None, )]); let outputs = build_outputs([Account( 1_000_000, account_id_2, BECH32_ADDRESS_ED25519_0, - None, Some(BECH32_ADDRESS_NFT_1), None, None, @@ -804,7 +767,6 @@ fn missing_nft_issuer_created() { account_id_0, BECH32_ADDRESS_ED25519_0, None, - None, Some(BECH32_ADDRESS_NFT_1), None, )]); @@ -833,7 +795,6 @@ fn missing_nft_issuer_transition() { account_id_1, BECH32_ADDRESS_ED25519_0, None, - None, Some(BECH32_ADDRESS_NFT_1), None, )]); @@ -842,7 +803,6 @@ fn missing_nft_issuer_transition() { account_id_1, BECH32_ADDRESS_ED25519_0, None, - None, Some(BECH32_ADDRESS_NFT_1), None, )]); @@ -864,15 +824,7 @@ fn increase_account_amount() { let account_id_1 = AccountId::from_str(ACCOUNT_ID_1).unwrap(); let inputs = build_inputs([ - Account( - 2_000_000, - account_id_1, - BECH32_ADDRESS_ED25519_0, - None, - None, - None, - None, - ), + Account(2_000_000, account_id_1, BECH32_ADDRESS_ED25519_0, None, None, None), Basic(1_000_000, BECH32_ADDRESS_ED25519_0, None, None, None, None, None, None), ]); let outputs = build_outputs([Account( @@ -882,7 +834,6 @@ fn increase_account_amount() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -904,15 +855,7 @@ fn decrease_account_amount() { let account_id_1 = AccountId::from_str(ACCOUNT_ID_1).unwrap(); let inputs = build_inputs([ - Account( - 2_000_000, - account_id_1, - BECH32_ADDRESS_ED25519_0, - None, - None, - None, - None, - ), + Account(2_000_000, account_id_1, BECH32_ADDRESS_ED25519_0, None, None, None), Basic(1_000_000, BECH32_ADDRESS_ED25519_0, None, None, None, None, None, None), ]); let outputs = build_outputs([Account( @@ -922,7 +865,6 @@ fn decrease_account_amount() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -956,15 +898,7 @@ fn prefer_basic_to_account() { let account_id_1 = AccountId::from_str(ACCOUNT_ID_1).unwrap(); let inputs = build_inputs([ - Account( - 1_000_000, - account_id_1, - BECH32_ADDRESS_ED25519_0, - None, - None, - None, - None, - ), + Account(1_000_000, account_id_1, BECH32_ADDRESS_ED25519_0, None, None, None), Basic(1_000_000, BECH32_ADDRESS_ED25519_0, None, None, None, None, None, None), ]); let outputs = build_outputs([Basic( @@ -998,15 +932,7 @@ fn take_amount_from_account_to_fund_basic() { let account_id_1 = AccountId::from_str(ACCOUNT_ID_1).unwrap(); let inputs = build_inputs([ - Account( - 2_000_000, - account_id_1, - BECH32_ADDRESS_ED25519_0, - None, - None, - None, - None, - ), + Account(2_000_000, account_id_1, BECH32_ADDRESS_ED25519_0, None, None, None), Basic(1_000_000, BECH32_ADDRESS_ED25519_0, None, None, None, None, None, None), ]); let outputs = build_outputs([Basic( @@ -1036,7 +962,6 @@ fn take_amount_from_account_to_fund_basic() { if !outputs.contains(output) { assert!(output.is_account()); assert_eq!(output.amount(), 1_800_000); - assert_eq!(output.as_account().native_tokens().len(), 0); assert_eq!(*output.as_account().account_id(), account_id_1); assert_eq!(output.as_account().unlock_conditions().len(), 1); assert_eq!(output.as_account().features().len(), 0); @@ -1056,15 +981,7 @@ fn account_burn_should_validate_account_sender() { let inputs = build_inputs([ Basic(2_000_000, BECH32_ADDRESS_ED25519_0, None, None, None, None, None, None), - Account( - 1_000_000, - account_id_1, - BECH32_ADDRESS_ED25519_0, - None, - None, - None, - None, - ), + Account(1_000_000, account_id_1, BECH32_ADDRESS_ED25519_0, None, None, None), ]); let outputs = build_outputs([Basic( 2_000_000, @@ -1110,15 +1027,7 @@ fn account_burn_should_validate_account_address() { let inputs = build_inputs([ Basic(2_000_000, BECH32_ADDRESS_ACCOUNT_1, None, None, None, None, None, None), - Account( - 1_000_000, - account_id_1, - BECH32_ADDRESS_ED25519_0, - None, - None, - None, - None, - ), + Account(1_000_000, account_id_1, BECH32_ADDRESS_ED25519_0, None, None, None), ]); let outputs = build_outputs([Basic( 2_000_000, @@ -1169,7 +1078,6 @@ fn transitioned_zero_account_id_no_longer_is_zero() { None, None, None, - None, )]); let outputs = build_outputs([Basic( 1_000_000, @@ -1198,7 +1106,6 @@ fn transitioned_zero_account_id_no_longer_is_zero() { if !outputs.contains(output) { assert!(output.is_account()); assert_eq!(output.amount(), 1_000_000); - assert_eq!(output.as_account().native_tokens().len(), 0); assert_ne!(*output.as_account().account_id(), account_id_0); assert_eq!(output.as_account().unlock_conditions().len(), 1); assert_eq!(output.as_account().features().len(), 0); @@ -1218,24 +1125,8 @@ fn two_accounts_required() { let account_id_2 = AccountId::from_str(ACCOUNT_ID_2).unwrap(); let inputs = build_inputs([ - Account( - 2_000_000, - account_id_1, - BECH32_ADDRESS_ED25519_0, - None, - None, - None, - None, - ), - Account( - 2_000_000, - account_id_2, - BECH32_ADDRESS_ED25519_0, - None, - None, - None, - None, - ), + Account(2_000_000, account_id_1, BECH32_ADDRESS_ED25519_0, None, None, None), + Account(2_000_000, account_id_2, BECH32_ADDRESS_ED25519_0, None, None, None), ]); let outputs = build_outputs([Basic( 3_000_000, @@ -1294,7 +1185,6 @@ fn state_controller_sender_required() { None, None, None, - None, )]); let outputs = build_outputs([Basic( 1_000_000, @@ -1333,18 +1223,9 @@ fn state_controller_sender_required_already_selected() { None, None, None, - None, )]); let outputs = build_outputs([ - Account( - 1_000_000, - account_id_1, - BECH32_ADDRESS_ED25519_0, - None, - None, - None, - None, - ), + Account(1_000_000, account_id_1, BECH32_ADDRESS_ED25519_0, None, None, None), Basic( 1_000_000, BECH32_ADDRESS_ED25519_0, @@ -1383,7 +1264,6 @@ fn state_transition_and_required() { None, None, None, - None, )]); let outputs = build_outputs([Account( 2_000_000, @@ -1392,7 +1272,6 @@ fn state_transition_and_required() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -1421,7 +1300,6 @@ fn remainder_address_in_state_controller() { None, None, None, - None, )]); let outputs = build_outputs([Account( 1_000_000, @@ -1430,7 +1308,6 @@ fn remainder_address_in_state_controller() { None, None, None, - None, )]); let selected = InputSelection::new( diff --git a/sdk/tests/client/input_selection/basic_outputs.rs b/sdk/tests/client/input_selection/basic_outputs.rs index 712a6588b2..760799e75b 100644 --- a/sdk/tests/client/input_selection/basic_outputs.rs +++ b/sdk/tests/client/input_selection/basic_outputs.rs @@ -551,15 +551,7 @@ fn account_sender() { let inputs = build_inputs([ Basic(2_000_000, BECH32_ADDRESS_ED25519_0, None, None, None, None, None, None), Basic(2_000_000, BECH32_ADDRESS_ED25519_0, None, None, None, None, None, None), - Account( - 1_000_000, - account_id_1, - BECH32_ADDRESS_ED25519_0, - None, - None, - None, - None, - ), + Account(1_000_000, account_id_1, BECH32_ADDRESS_ED25519_0, None, None, None), Basic(2_000_000, BECH32_ADDRESS_ED25519_0, None, None, None, None, None, None), Basic(2_000_000, BECH32_ADDRESS_ED25519_0, None, None, None, None, None, None), ]); @@ -604,15 +596,7 @@ fn account_sender_zero_id() { let inputs = build_inputs([ Basic(2_000_000, BECH32_ADDRESS_ED25519_0, None, None, None, None, None, None), - Account( - 1_000_000, - account_id_0, - BECH32_ADDRESS_ED25519_0, - None, - None, - None, - None, - ), + Account(1_000_000, account_id_0, BECH32_ADDRESS_ED25519_0, None, None, None), ]); let account_id = AccountId::from(inputs[1].output_id()); let outputs = build_outputs([Basic( @@ -705,7 +689,6 @@ fn nft_sender() { None, None, None, - None, ), Basic(2_000_000, BECH32_ADDRESS_ED25519_0, None, None, None, None, None, None), Basic(2_000_000, BECH32_ADDRESS_ED25519_0, None, None, None, None, None, None), @@ -760,7 +743,6 @@ fn nft_sender_zero_id() { None, None, None, - None, ), ]); let nft_id = NftId::from(inputs[1].output_id()); @@ -1449,7 +1431,6 @@ fn restricted_nft() { None, None, None, - None, ), ]); let outputs = build_outputs([Basic( @@ -1487,15 +1468,7 @@ fn restricted_account() { let inputs = build_inputs([ Basic(2_000_000, &restricted_bech32, None, None, None, None, None, None), - Account( - 2_000_000, - account_id_1, - BECH32_ADDRESS_ED25519_0, - None, - None, - None, - None, - ), + Account(2_000_000, account_id_1, BECH32_ADDRESS_ED25519_0, None, None, None), ]); let outputs = build_outputs([Basic( diff --git a/sdk/tests/client/input_selection/burn.rs b/sdk/tests/client/input_selection/burn.rs index c89c1e26e1..f814fe2a8c 100644 --- a/sdk/tests/client/input_selection/burn.rs +++ b/sdk/tests/client/input_selection/burn.rs @@ -29,15 +29,7 @@ fn burn_account_present() { let account_id_1 = AccountId::from_str(ACCOUNT_ID_1).unwrap(); let inputs = build_inputs([ - Account( - 1_000_000, - account_id_1, - BECH32_ADDRESS_ED25519_0, - None, - None, - None, - None, - ), + Account(1_000_000, account_id_1, BECH32_ADDRESS_ED25519_0, None, None, None), Basic(1_000_000, BECH32_ADDRESS_ED25519_0, None, None, None, None, None, None), ]); let outputs = build_outputs([Basic( @@ -72,15 +64,7 @@ fn burn_account_present_and_required() { let account_id_1 = AccountId::from_str(ACCOUNT_ID_1).unwrap(); let inputs = build_inputs([ - Account( - 1_000_000, - account_id_1, - BECH32_ADDRESS_ED25519_0, - None, - None, - None, - None, - ), + Account(1_000_000, account_id_1, BECH32_ADDRESS_ED25519_0, None, None, None), Basic(1_000_000, BECH32_ADDRESS_ED25519_0, None, None, None, None, None, None), ]); let outputs = build_outputs([Basic( @@ -125,7 +109,6 @@ fn burn_account_id_zero() { None, None, None, - None, ), Basic(1_000_000, BECH32_ADDRESS_ED25519_0, None, None, None, None, None, None), ]); @@ -204,24 +187,8 @@ fn burn_accounts_present() { let account_id_2 = AccountId::from_str(ACCOUNT_ID_2).unwrap(); let inputs = build_inputs([ - Account( - 1_000_000, - account_id_1, - BECH32_ADDRESS_ED25519_0, - None, - None, - None, - None, - ), - Account( - 1_000_000, - account_id_2, - BECH32_ADDRESS_ED25519_0, - None, - None, - None, - None, - ), + Account(1_000_000, account_id_1, BECH32_ADDRESS_ED25519_0, None, None, None), + Account(1_000_000, account_id_2, BECH32_ADDRESS_ED25519_0, None, None, None), Basic(1_000_000, BECH32_ADDRESS_ED25519_0, None, None, None, None, None, None), ]); let outputs = build_outputs([Basic( @@ -255,27 +222,11 @@ fn burn_account_in_outputs() { let account_id_1 = AccountId::from_str(ACCOUNT_ID_1).unwrap(); let inputs = build_inputs([ - Account( - 1_000_000, - account_id_1, - BECH32_ADDRESS_ED25519_0, - None, - None, - None, - None, - ), + Account(1_000_000, account_id_1, BECH32_ADDRESS_ED25519_0, None, None, None), Basic(1_000_000, BECH32_ADDRESS_ED25519_0, None, None, None, None, None, None), ]); let outputs = build_outputs([ - Account( - 1_000_000, - account_id_1, - BECH32_ADDRESS_ED25519_0, - None, - None, - None, - None, - ), + Account(1_000_000, account_id_1, BECH32_ADDRESS_ED25519_0, None, None, None), Basic(1_000_000, BECH32_ADDRESS_ED25519_0, None, None, None, None, None, None), ]); @@ -309,7 +260,6 @@ fn burn_nft_present() { None, None, None, - None, ), Basic(1_000_000, BECH32_ADDRESS_ED25519_0, None, None, None, None, None, None), ]); @@ -354,7 +304,6 @@ fn burn_nft_present_and_required() { None, None, None, - None, ), Basic(1_000_000, BECH32_ADDRESS_ED25519_0, None, None, None, None, None, None), ]); @@ -391,15 +340,7 @@ fn burn_nft_id_zero() { let account_id_0 = AccountId::from_str(ACCOUNT_ID_0).unwrap(); let inputs = build_inputs([ - Account( - 1_000_000, - account_id_0, - BECH32_ADDRESS_ED25519_0, - None, - None, - None, - None, - ), + Account(1_000_000, account_id_0, BECH32_ADDRESS_ED25519_0, None, None, None), Basic(1_000_000, BECH32_ADDRESS_ED25519_0, None, None, None, None, None, None), ]); let outputs = build_outputs([Basic( @@ -486,7 +427,6 @@ fn burn_nfts_present() { None, None, None, - None, ), Nft( 1_000_000, @@ -497,7 +437,6 @@ fn burn_nfts_present() { None, None, None, - None, ), Basic(1_000_000, BECH32_ADDRESS_ED25519_0, None, None, None, None, None, None), ]); @@ -541,7 +480,6 @@ fn burn_nft_in_outputs() { None, None, None, - None, ), Basic(1_000_000, BECH32_ADDRESS_ED25519_0, None, None, None, None, None, None), ]); @@ -555,7 +493,6 @@ fn burn_nft_in_outputs() { None, None, None, - None, ), Basic(1_000_000, BECH32_ADDRESS_ED25519_0, None, None, None, None, None, None), ]); @@ -588,15 +525,7 @@ fn burn_foundry_present() { SimpleTokenScheme::new(0, 0, 10).unwrap(), None, ), - Account( - 1_000_000, - account_id_1, - BECH32_ADDRESS_ED25519_0, - None, - None, - None, - None, - ), + Account(1_000_000, account_id_1, BECH32_ADDRESS_ED25519_0, None, None, None), Basic(1_000_000, BECH32_ADDRESS_ED25519_0, None, None, None, None, None, None), ]); let outputs = build_outputs([Basic( @@ -636,7 +565,6 @@ fn burn_foundry_present() { )); } else if output.is_account() { assert_eq!(output.amount(), 1_000_000); - assert_eq!(output.as_account().native_tokens().len(), 0); assert_eq!(*output.as_account().account_id(), account_id_1); assert_eq!(output.as_account().unlock_conditions().len(), 1); assert_eq!(output.as_account().features().len(), 0); @@ -668,15 +596,7 @@ fn burn_foundry_absent() { .id(); let inputs = build_inputs([ - Account( - 1_000_000, - account_id_1, - BECH32_ADDRESS_ED25519_0, - None, - None, - None, - None, - ), + Account(1_000_000, account_id_1, BECH32_ADDRESS_ED25519_0, None, None, None), Basic(1_000_000, BECH32_ADDRESS_ED25519_0, None, None, None, None, None, None), ]); let outputs = build_outputs([Basic( @@ -725,15 +645,7 @@ fn burn_foundries_present() { SimpleTokenScheme::new(0, 0, 10).unwrap(), None, ), - Account( - 1_000_000, - account_id_1, - BECH32_ADDRESS_ED25519_0, - None, - None, - None, - None, - ), + Account(1_000_000, account_id_1, BECH32_ADDRESS_ED25519_0, None, None, None), ]); let outputs = build_outputs([Basic( 2_000_000, @@ -766,7 +678,6 @@ fn burn_foundries_present() { if !outputs.contains(output) { assert!(output.is_account()); assert_eq!(output.amount(), 1_000_000); - assert_eq!(output.as_account().native_tokens().len(), 0); assert_eq!(*output.as_account().account_id(), account_id_1); assert_eq!(output.as_account().unlock_conditions().len(), 1); assert_eq!(output.as_account().features().len(), 0); @@ -828,7 +739,7 @@ fn burn_native_tokens() { let inputs = build_inputs([Basic( 1_000_000, BECH32_ADDRESS_ED25519_0, - Some(vec![(TOKEN_ID_1, 100), (TOKEN_ID_2, 100)]), + Some((TOKEN_ID_1, 100), (TOKEN_ID_2, 100)), None, None, None, @@ -855,7 +766,7 @@ fn burn_native_tokens() { &selected.outputs[0], 1_000_000, BECH32_ADDRESS_ED25519_0, - Some(vec![(TOKEN_ID_1, 80), (TOKEN_ID_2, 70)]) + Some((TOKEN_ID_1, 80), (TOKEN_ID_2, 70)) )); } @@ -872,15 +783,7 @@ fn burn_foundry_and_its_account() { SimpleTokenScheme::new(0, 0, 10).unwrap(), None, ), - Account( - 1_000_000, - account_id_1, - BECH32_ADDRESS_ED25519_0, - None, - None, - None, - None, - ), + Account(1_000_000, account_id_1, BECH32_ADDRESS_ED25519_0, None, None, None), Basic(1_000_000, BECH32_ADDRESS_ED25519_0, None, None, None, None, None, None), ]); let outputs = build_outputs([Basic( diff --git a/sdk/tests/client/input_selection/expiration.rs b/sdk/tests/client/input_selection/expiration.rs index 7128f505b3..320316d9e4 100644 --- a/sdk/tests/client/input_selection/expiration.rs +++ b/sdk/tests/client/input_selection/expiration.rs @@ -680,15 +680,7 @@ fn expiration_expired_only_account_addresses() { Some((BECH32_ADDRESS_ACCOUNT_1, 50)), None, ), - Account( - 1_000_000, - account_id_1, - BECH32_ADDRESS_ED25519_0, - None, - None, - None, - None, - ), + Account(1_000_000, account_id_1, BECH32_ADDRESS_ED25519_0, None, None, None), ]); let outputs = build_outputs([Basic( @@ -728,7 +720,6 @@ fn one_nft_output_expiration_unexpired() { None, None, None, - None, Some((BECH32_ADDRESS_ED25519_0, 150)), None, )]); @@ -741,7 +732,6 @@ fn one_nft_output_expiration_unexpired() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -770,7 +760,6 @@ fn one_nft_output_expiration_expired() { None, None, None, - None, Some((BECH32_ADDRESS_ED25519_0, 50)), None, )]); @@ -783,7 +772,6 @@ fn one_nft_output_expiration_expired() { None, None, None, - None, )]); let selected = InputSelection::new( diff --git a/sdk/tests/client/input_selection/foundry_outputs.rs b/sdk/tests/client/input_selection/foundry_outputs.rs index 2e0039f571..8e40b50d78 100644 --- a/sdk/tests/client/input_selection/foundry_outputs.rs +++ b/sdk/tests/client/input_selection/foundry_outputs.rs @@ -108,15 +108,7 @@ fn minted_native_tokens_in_new_remainder() { let inputs = build_inputs([ Basic(1_000_000, BECH32_ADDRESS_ED25519_0, None, None, None, None, None, None), - Account( - 1_000_000, - account_id_2, - BECH32_ADDRESS_ED25519_0, - None, - None, - None, - None, - ), + Account(1_000_000, account_id_2, BECH32_ADDRESS_ED25519_0, None, None, None), ]); let outputs = build_outputs([Foundry( 1_000_000, @@ -139,9 +131,10 @@ fn minted_native_tokens_in_new_remainder() { // Account next state + foundry + basic output with native tokens assert_eq!(selected.outputs.len(), 3); selected.outputs.iter().for_each(|output| { - if let Output::Basic(basic_output) = &output { + if let Output::Basic(_basic_output) = &output { // Basic output remainder has the minted native tokens - assert_eq!(basic_output.native_tokens().first().unwrap().amount().as_u32(), 10); + // TODO reenable when ISA supports NTs again + // assert_eq!(basic_output.native_token().unwrap().amount().as_u32(), 10); } }); } @@ -155,15 +148,7 @@ fn minted_native_tokens_in_provided_output() { let inputs = build_inputs([ Basic(2_000_000, BECH32_ADDRESS_ED25519_0, None, None, None, None, None, None), - Account( - 1_000_000, - account_id_2, - BECH32_ADDRESS_ED25519_0, - None, - None, - None, - None, - ), + Account(1_000_000, account_id_2, BECH32_ADDRESS_ED25519_0, None, None, None), ]); let outputs = build_outputs([ Foundry( @@ -176,7 +161,7 @@ fn minted_native_tokens_in_provided_output() { Basic( 1_000_000, BECH32_ADDRESS_ED25519_0, - Some(vec![(&token_id.to_string(), 100)]), + Some((&token_id.to_string(), 100)), None, None, None, @@ -213,10 +198,10 @@ fn melt_native_tokens() { account_id_1, 1, SimpleTokenScheme::new(10, 0, 10).unwrap(), - Some(vec![( + Some(( "0x0811111111111111111111111111111111111111111111111111111111111111110100000000", 10, - )]), + )), ), ]); let account_output = AccountOutputBuilder::new_with_amount(1_000_000, account_id_1) @@ -253,9 +238,10 @@ fn melt_native_tokens() { // Account next state + foundry + basic output with native tokens assert_eq!(selected.outputs.len(), 3); selected.outputs.iter().for_each(|output| { - if let Output::Basic(basic_output) = &output { + if let Output::Basic(_basic_output) = &output { // Basic output remainder has the remaining native tokens - assert_eq!(basic_output.native_tokens().first().unwrap().amount().as_u32(), 5); + // TODO reenable when ISA supports NTs again + // assert_eq!(basic_output.native_token().unwrap().amount().as_u32(), 5); } }); } @@ -266,7 +252,7 @@ fn destroy_foundry_with_account_state_transition() { let account_id_2 = AccountId::from_str(ACCOUNT_ID_2).unwrap(); let inputs = build_inputs([ - Account(50_300, account_id_2, BECH32_ADDRESS_ED25519_0, None, None, None, None), + Account(50_300, account_id_2, BECH32_ADDRESS_ED25519_0, None, None, None), Foundry( 52_800, account_id_2, @@ -303,15 +289,7 @@ fn destroy_foundry_with_account_burn() { let account_id_2 = AccountId::from_str(ACCOUNT_ID_2).unwrap(); let inputs = build_inputs([ - Account( - 1_000_000, - account_id_2, - BECH32_ADDRESS_ED25519_0, - None, - None, - None, - None, - ), + Account(1_000_000, account_id_2, BECH32_ADDRESS_ED25519_0, None, None, None), Foundry( 1_000_000, account_id_2, @@ -366,15 +344,7 @@ fn prefer_basic_to_foundry() { let account_id_1 = AccountId::from_str(ACCOUNT_ID_1).unwrap(); let inputs = build_inputs([ - Account( - 1_000_000, - account_id_1, - BECH32_ADDRESS_ED25519_0, - None, - None, - None, - None, - ), + Account(1_000_000, account_id_1, BECH32_ADDRESS_ED25519_0, None, None, None), Foundry( 1_000_000, account_id_1, @@ -463,7 +433,6 @@ fn simple_foundry_transition_basic_not_needed() { if !outputs.contains(output) { assert!(output.is_account()); assert_eq!(output.amount(), 2_000_000); - assert_eq!(output.as_account().native_tokens().len(), 0); assert_eq!(*output.as_account().account_id(), account_id_1); assert_eq!(output.as_account().unlock_conditions().len(), 1); assert_eq!(output.as_account().features().len(), 0); @@ -529,7 +498,6 @@ fn simple_foundry_transition_basic_not_needed_with_remainder() { if !outputs.contains(output) { if output.is_account() { assert_eq!(output.amount(), 2_000_000); - assert_eq!(output.as_account().native_tokens().len(), 0); assert_eq!(*output.as_account().account_id(), account_id_1); assert_eq!(output.as_account().unlock_conditions().len(), 1); assert_eq!(output.as_account().features().len(), 0); @@ -631,7 +599,7 @@ fn mint_and_burn_at_the_same_time() { account_id_1, 1, SimpleTokenScheme::new(100, 0, 200).unwrap(), - Some(vec![(&token_id.to_string(), 100)]), + Some((&token_id.to_string(), 100)), )]); let account_output = AccountOutputBuilder::new_with_amount(2_000_000, account_id_1) .add_unlock_condition(AddressUnlockCondition::new( @@ -651,7 +619,7 @@ fn mint_and_burn_at_the_same_time() { account_id_1, 1, SimpleTokenScheme::new(120, 0, 200).unwrap(), - Some(vec![(&token_id.to_string(), 110)]), + Some((&token_id.to_string(), 110)), )]); let selected = InputSelection::new( @@ -683,7 +651,7 @@ fn take_amount_from_account_and_foundry_to_fund_basic() { account_id_1, 1, SimpleTokenScheme::new(100, 0, 200).unwrap(), - Some(vec![(&token_id.to_string(), 100)]), + Some((&token_id.to_string(), 100)), ), ]); let account_output = AccountOutputBuilder::new_with_amount(2_000_000, account_id_1) @@ -737,15 +705,7 @@ fn create_native_token_but_burn_account() { let token_id = TokenId::from(foundry_id); let inputs = build_inputs([ - Account( - 2_000_000, - account_id_1, - BECH32_ADDRESS_ED25519_0, - None, - None, - None, - None, - ), + Account(2_000_000, account_id_1, BECH32_ADDRESS_ED25519_0, None, None, None), Foundry( 1_000_000, account_id_1, @@ -759,7 +719,7 @@ fn create_native_token_but_burn_account() { account_id_1, 1, SimpleTokenScheme::new(100, 0, 100).unwrap(), - Some(vec![(&token_id.to_string(), 100)]), + Some((&token_id.to_string(), 100)), )]); let selected = InputSelection::new( @@ -796,15 +756,7 @@ fn melted_tokens_not_provided() { let token_id_1 = TokenId::from(foundry_id); let inputs = build_inputs([ - Account( - 2_000_000, - account_id_1, - BECH32_ADDRESS_ED25519_0, - None, - None, - None, - None, - ), + Account(2_000_000, account_id_1, BECH32_ADDRESS_ED25519_0, None, None, None), Foundry( 1_000_000, account_id_1, @@ -846,15 +798,7 @@ fn burned_tokens_not_provided() { let token_id_1 = TokenId::from(foundry_id); let inputs = build_inputs([ - Account( - 2_000_000, - account_id_1, - BECH32_ADDRESS_ED25519_0, - None, - None, - None, - None, - ), + Account(2_000_000, account_id_1, BECH32_ADDRESS_ED25519_0, None, None, None), Foundry( 1_000_000, account_id_1, @@ -955,7 +899,7 @@ fn melt_and_burn_native_tokens() { account_id, 1, SimpleTokenScheme::new(1000, 0, 1000).unwrap(), - Some(vec![(&token_id.to_string(), 1000)]), + Some((&token_id.to_string(), 1000)), ), ]); let account_output = AccountOutputBuilder::new_with_amount(1_000_000, account_id) @@ -995,9 +939,10 @@ fn melt_and_burn_native_tokens() { assert_eq!(selected.outputs.len(), 3); // Account state index is increased selected.outputs.iter().for_each(|output| { - if let Output::Basic(basic_output) = &output { + if let Output::Basic(_basic_output) = &output { // Basic output remainder has the remaining native tokens - assert_eq!(basic_output.native_tokens().first().unwrap().amount().as_u32(), 421); + // TODO reenable when ISA supports NTs again + // assert_eq!(basic_output.native_token().unwrap().amount().as_u32(), 421); } }); } diff --git a/sdk/tests/client/input_selection/mod.rs b/sdk/tests/client/input_selection/mod.rs index ff9ee5e48e..6d1e837654 100644 --- a/sdk/tests/client/input_selection/mod.rs +++ b/sdk/tests/client/input_selection/mod.rs @@ -3,10 +3,12 @@ mod account_outputs; mod basic_outputs; -mod burn; +// TODO https://github.com/iotaledger/iota-sdk/issues/1631 +// mod burn; mod expiration; mod foundry_outputs; -mod native_tokens; +// TODO https://github.com/iotaledger/iota-sdk/issues/1631 +// mod native_tokens; mod nft_outputs; mod outputs; mod storage_deposit_return; diff --git a/sdk/tests/client/input_selection/native_tokens.rs b/sdk/tests/client/input_selection/native_tokens.rs index 6d3569f734..58ee7df991 100644 --- a/sdk/tests/client/input_selection/native_tokens.rs +++ b/sdk/tests/client/input_selection/native_tokens.rs @@ -23,7 +23,7 @@ fn two_native_tokens_one_needed() { Basic( 1_000_000, BECH32_ADDRESS_ED25519_0, - Some(vec![(TOKEN_ID_1, 100)]), + Some((TOKEN_ID_1, 100)), None, None, None, @@ -33,7 +33,7 @@ fn two_native_tokens_one_needed() { Basic( 1_000_000, BECH32_ADDRESS_ED25519_0, - Some(vec![(TOKEN_ID_1, 100), (TOKEN_ID_2, 100)]), + Some((TOKEN_ID_1, 100), (TOKEN_ID_2, 100)), None, None, None, @@ -44,7 +44,7 @@ fn two_native_tokens_one_needed() { let outputs = build_outputs([Basic( 1_000_000, BECH32_ADDRESS_ED25519_0, - Some(vec![(TOKEN_ID_1, 150)]), + Some((TOKEN_ID_1, 150)), None, None, None, @@ -84,7 +84,7 @@ fn two_native_tokens_both_needed_plus_remainder() { Basic( 1_000_000, BECH32_ADDRESS_ED25519_0, - Some(vec![(TOKEN_ID_1, 100)]), + Some((TOKEN_ID_1, 100)), None, None, None, @@ -94,7 +94,7 @@ fn two_native_tokens_both_needed_plus_remainder() { Basic( 1_000_000, BECH32_ADDRESS_ED25519_0, - Some(vec![(TOKEN_ID_1, 100), (TOKEN_ID_2, 100)]), + Some((TOKEN_ID_1, 100), (TOKEN_ID_2, 100)), None, None, None, @@ -131,7 +131,7 @@ fn two_native_tokens_both_needed_plus_remainder() { output, 1_000_000, BECH32_ADDRESS_ED25519_0, - Some(vec![(TOKEN_ID_1, 50)]) + Some((TOKEN_ID_1, 50)) )); } }); @@ -145,7 +145,7 @@ fn three_inputs_two_needed_plus_remainder() { Basic( 1_000_000, BECH32_ADDRESS_ED25519_0, - Some(vec![(TOKEN_ID_1, 100)]), + Some((TOKEN_ID_1, 100)), None, None, None, @@ -155,7 +155,7 @@ fn three_inputs_two_needed_plus_remainder() { Basic( 1_000_000, BECH32_ADDRESS_ED25519_0, - Some(vec![(TOKEN_ID_1, 100)]), + Some((TOKEN_ID_1, 100)), None, None, None, @@ -165,7 +165,7 @@ fn three_inputs_two_needed_plus_remainder() { Basic( 1_000_000, BECH32_ADDRESS_ED25519_0, - Some(vec![(TOKEN_ID_1, 100)]), + Some((TOKEN_ID_1, 100)), None, None, None, @@ -202,7 +202,7 @@ fn three_inputs_two_needed_plus_remainder() { output, 1_000_000, BECH32_ADDRESS_ED25519_0, - Some(vec![(TOKEN_ID_1, 80)]) + Some((TOKEN_ID_1, 80)) )); } }); @@ -216,7 +216,7 @@ fn three_inputs_two_needed_no_remainder() { Basic( 1_000_000, BECH32_ADDRESS_ED25519_0, - Some(vec![(TOKEN_ID_1, 100)]), + Some((TOKEN_ID_1, 100)), None, None, None, @@ -226,7 +226,7 @@ fn three_inputs_two_needed_no_remainder() { Basic( 1_000_000, BECH32_ADDRESS_ED25519_0, - Some(vec![(TOKEN_ID_1, 100)]), + Some((TOKEN_ID_1, 100)), None, None, None, @@ -236,7 +236,7 @@ fn three_inputs_two_needed_no_remainder() { Basic( 1_000_000, BECH32_ADDRESS_ED25519_0, - Some(vec![(TOKEN_ID_1, 100)]), + Some((TOKEN_ID_1, 100)), None, None, None, @@ -275,7 +275,7 @@ fn insufficient_native_tokens_one_input() { let inputs = build_inputs([Basic( 1_000_000, BECH32_ADDRESS_ED25519_0, - Some(vec![(TOKEN_ID_1, 100)]), + Some((TOKEN_ID_1, 100)), None, None, None, @@ -285,7 +285,7 @@ fn insufficient_native_tokens_one_input() { let outputs = build_outputs([Basic( 1_000_000, BECH32_ADDRESS_ED25519_0, - Some(vec![(TOKEN_ID_1, 150)]), + Some((TOKEN_ID_1, 150)), None, None, None, @@ -318,7 +318,7 @@ fn insufficient_native_tokens_three_inputs() { Basic( 1_000_000, BECH32_ADDRESS_ED25519_0, - Some(vec![(TOKEN_ID_1, 100)]), + Some((TOKEN_ID_1, 100)), None, None, None, @@ -328,7 +328,7 @@ fn insufficient_native_tokens_three_inputs() { Basic( 1_000_000, BECH32_ADDRESS_ED25519_0, - Some(vec![(TOKEN_ID_1, 100)]), + Some((TOKEN_ID_1, 100)), None, None, None, @@ -338,7 +338,7 @@ fn insufficient_native_tokens_three_inputs() { Basic( 1_000_000, BECH32_ADDRESS_ED25519_0, - Some(vec![(TOKEN_ID_1, 100)]), + Some((TOKEN_ID_1, 100)), None, None, None, @@ -349,7 +349,7 @@ fn insufficient_native_tokens_three_inputs() { let outputs = build_outputs([Basic( 1_000_000, BECH32_ADDRESS_ED25519_0, - Some(vec![(TOKEN_ID_1, 301)]), + Some((TOKEN_ID_1, 301)), None, None, None, @@ -381,7 +381,7 @@ fn burn_and_send_at_the_same_time() { let inputs = build_inputs([Basic( 2_000_000, BECH32_ADDRESS_ED25519_0, - Some(vec![(TOKEN_ID_1, 100), (TOKEN_ID_2, 100)]), + Some((TOKEN_ID_1, 100), (TOKEN_ID_2, 100)), None, None, None, @@ -418,7 +418,7 @@ fn burn_and_send_at_the_same_time() { output, 1_000_000, BECH32_ADDRESS_ED25519_0, - Some(vec![(TOKEN_ID_1, 40)]) + Some((TOKEN_ID_1, 40)) )); } }); @@ -431,7 +431,7 @@ fn burn_one_input_no_output() { let inputs = build_inputs([Basic( 1_000_000, BECH32_ADDRESS_ED25519_0, - Some(vec![(TOKEN_ID_1, 100)]), + Some((TOKEN_ID_1, 100)), None, None, None, @@ -455,7 +455,7 @@ fn burn_one_input_no_output() { &selected.outputs[0], 1_000_000, BECH32_ADDRESS_ED25519_0, - Some(vec![(TOKEN_ID_1, 50)]) + Some((TOKEN_ID_1, 50)) )); } @@ -467,7 +467,7 @@ fn burn_two_inputs_no_output() { Basic( 1_000_000, BECH32_ADDRESS_ED25519_0, - Some(vec![(TOKEN_ID_1, 100)]), + Some((TOKEN_ID_1, 100)), None, None, None, @@ -477,7 +477,7 @@ fn burn_two_inputs_no_output() { Basic( 1_000_000, BECH32_ADDRESS_ED25519_0, - Some(vec![(TOKEN_ID_1, 100), (TOKEN_ID_2, 100)]), + Some((TOKEN_ID_1, 100), (TOKEN_ID_2, 100)), None, None, None, @@ -503,7 +503,7 @@ fn burn_two_inputs_no_output() { &selected.outputs[0], 1_000_000, BECH32_ADDRESS_ED25519_0, - Some(vec![(TOKEN_ID_1, 50)]) + Some((TOKEN_ID_1, 50)) )); } @@ -514,7 +514,7 @@ fn burn_one_input_two_tokens_no_output() { let inputs = build_inputs([Basic( 1_000_000, BECH32_ADDRESS_ED25519_0, - Some(vec![(TOKEN_ID_1, 100), (TOKEN_ID_2, 100)]), + Some((TOKEN_ID_1, 100), (TOKEN_ID_2, 100)), None, None, None, @@ -550,7 +550,7 @@ fn multiple_native_tokens_1() { Basic( 1_000_000, BECH32_ADDRESS_ED25519_0, - Some(vec![(TOKEN_ID_1, 100)]), + Some((TOKEN_ID_1, 100)), None, None, None, @@ -560,7 +560,7 @@ fn multiple_native_tokens_1() { Basic( 1_000_000, BECH32_ADDRESS_ED25519_0, - Some(vec![(TOKEN_ID_1, 100), (TOKEN_ID_2, 100)]), + Some((TOKEN_ID_1, 100), (TOKEN_ID_2, 100)), None, None, None, @@ -571,7 +571,7 @@ fn multiple_native_tokens_1() { let outputs = build_outputs([Basic( 1_000_000, BECH32_ADDRESS_ED25519_0, - Some(vec![(TOKEN_ID_1, 100)]), + Some((TOKEN_ID_1, 100)), None, None, None, @@ -601,7 +601,7 @@ fn multiple_native_tokens_2() { Basic( 1_000_000, BECH32_ADDRESS_ED25519_0, - Some(vec![(TOKEN_ID_1, 100)]), + Some((TOKEN_ID_1, 100)), None, None, None, @@ -611,7 +611,7 @@ fn multiple_native_tokens_2() { Basic( 1_000_000, BECH32_ADDRESS_ED25519_0, - Some(vec![(TOKEN_ID_1, 100), (TOKEN_ID_2, 100)]), + Some((TOKEN_ID_1, 100), (TOKEN_ID_2, 100)), None, None, None, @@ -622,7 +622,7 @@ fn multiple_native_tokens_2() { let outputs = build_outputs([Basic( 1_000_000, BECH32_ADDRESS_ED25519_0, - Some(vec![(TOKEN_ID_1, 150)]), + Some((TOKEN_ID_1, 150)), None, None, None, @@ -658,7 +658,7 @@ fn multiple_native_tokens_3() { Basic( 1_000_000, BECH32_ADDRESS_ED25519_0, - Some(vec![(TOKEN_ID_1, 100)]), + Some((TOKEN_ID_1, 100)), None, None, None, @@ -668,7 +668,7 @@ fn multiple_native_tokens_3() { Basic( 1_000_000, BECH32_ADDRESS_ED25519_0, - Some(vec![(TOKEN_ID_1, 100), (TOKEN_ID_2, 100)]), + Some((TOKEN_ID_1, 100), (TOKEN_ID_2, 100)), None, None, None, @@ -703,7 +703,7 @@ fn multiple_native_tokens_3() { &selected.outputs[1], 1_000_000, BECH32_ADDRESS_ED25519_0, - Some(vec![(TOKEN_ID_2, 100)]) + Some((TOKEN_ID_2, 100)) )); } @@ -724,7 +724,7 @@ fn insufficient_native_tokens() { let outputs = build_outputs([Basic( 1_000_000, BECH32_ADDRESS_ED25519_0, - Some(vec![(TOKEN_ID_1, 150)]), + Some((TOKEN_ID_1, 150)), None, None, None, @@ -756,7 +756,7 @@ fn insufficient_native_tokens_2() { let inputs = build_inputs([Basic( 1_000_000, BECH32_ADDRESS_ED25519_0, - Some(vec![(TOKEN_ID_1, 100)]), + Some((TOKEN_ID_1, 100)), None, None, None, @@ -766,7 +766,7 @@ fn insufficient_native_tokens_2() { let outputs = build_outputs([Basic( 1_000_000, BECH32_ADDRESS_ED25519_0, - Some(vec![(TOKEN_ID_1, 150)]), + Some((TOKEN_ID_1, 150)), None, None, None, @@ -798,7 +798,7 @@ fn insufficient_native_tokens_2() { // let inputs = build_inputs([Basic( // 1_000_000, // BECH32_ADDRESS_ED25519_0, -// Some(vec![(TOKEN_ID_1, 100)]), +// Some((TOKEN_ID_1, 100)), // None, // None, // None, @@ -808,7 +808,7 @@ fn insufficient_native_tokens_2() { // let outputs = build_outputs([Basic( // 1_000_000, // BECH32_ADDRESS_ED25519_0, -// Some(vec![(TOKEN_ID_1, 50)]), +// Some((TOKEN_ID_1, 50)), // None, // None, // None, @@ -842,7 +842,7 @@ fn single_output_native_token_no_remainder() { let inputs = build_inputs([Basic( 1_000_000, BECH32_ADDRESS_ED25519_0, - Some(vec![(TOKEN_ID_1, 100)]), + Some((TOKEN_ID_1, 100)), None, None, None, @@ -852,7 +852,7 @@ fn single_output_native_token_no_remainder() { let outputs = build_outputs([Basic( 1_000_000, BECH32_ADDRESS_ED25519_0, - Some(vec![(TOKEN_ID_1, 100)]), + Some((TOKEN_ID_1, 100)), None, None, None, @@ -880,7 +880,7 @@ fn single_output_native_token_remainder_1() { let inputs = build_inputs([Basic( 1_000_000, BECH32_ADDRESS_ED25519_0, - Some(vec![(TOKEN_ID_1, 100)]), + Some((TOKEN_ID_1, 100)), None, None, None, @@ -890,7 +890,7 @@ fn single_output_native_token_remainder_1() { let outputs = build_outputs([Basic( 500_000, BECH32_ADDRESS_ED25519_0, - Some(vec![(TOKEN_ID_1, 50)]), + Some((TOKEN_ID_1, 50)), None, None, None, @@ -914,7 +914,7 @@ fn single_output_native_token_remainder_1() { &selected.outputs[0], 500_000, BECH32_ADDRESS_ED25519_0, - Some(vec![(TOKEN_ID_1, 50)]) + Some((TOKEN_ID_1, 50)) )); } @@ -925,7 +925,7 @@ fn single_output_native_token_remainder_2() { let inputs = build_inputs([Basic( 1_000_000, BECH32_ADDRESS_ED25519_0, - Some(vec![(TOKEN_ID_1, 100)]), + Some((TOKEN_ID_1, 100)), None, None, None, @@ -935,7 +935,7 @@ fn single_output_native_token_remainder_2() { let outputs = build_outputs([Basic( 500_000, BECH32_ADDRESS_ED25519_0, - Some(vec![(TOKEN_ID_1, 100)]), + Some((TOKEN_ID_1, 100)), None, None, None, @@ -971,7 +971,7 @@ fn two_basic_outputs_1() { Basic( 1_000_000, BECH32_ADDRESS_ED25519_0, - Some(vec![(TOKEN_ID_1, 100)]), + Some((TOKEN_ID_1, 100)), None, None, None, @@ -1017,7 +1017,7 @@ fn two_basic_outputs_1() { &selected.outputs[1], 500_000, BECH32_ADDRESS_ED25519_0, - Some(vec![(TOKEN_ID_1, 100)]), + Some((TOKEN_ID_1, 100)), )); } @@ -1029,7 +1029,7 @@ fn two_basic_outputs_2() { Basic( 1_000_000, BECH32_ADDRESS_ED25519_0, - Some(vec![(TOKEN_ID_1, 100)]), + Some((TOKEN_ID_1, 100)), None, None, None, @@ -1050,7 +1050,7 @@ fn two_basic_outputs_2() { let outputs = build_outputs([Basic( 500_000, BECH32_ADDRESS_ED25519_0, - Some(vec![(TOKEN_ID_1, 50)]), + Some((TOKEN_ID_1, 50)), None, None, None, @@ -1075,7 +1075,7 @@ fn two_basic_outputs_2() { &selected.outputs[1], 500_000, BECH32_ADDRESS_ED25519_0, - Some(vec![(TOKEN_ID_1, 50)]), + Some((TOKEN_ID_1, 50)), )); } @@ -1087,7 +1087,7 @@ fn two_basic_outputs_3() { Basic( 1_000_000, BECH32_ADDRESS_ED25519_0, - Some(vec![(TOKEN_ID_1, 100)]), + Some((TOKEN_ID_1, 100)), None, None, None, @@ -1145,7 +1145,7 @@ fn two_basic_outputs_4() { Basic( 1_000_000, BECH32_ADDRESS_ED25519_0, - Some(vec![(TOKEN_ID_1, 100)]), + Some((TOKEN_ID_1, 100)), None, None, None, @@ -1166,7 +1166,7 @@ fn two_basic_outputs_4() { let outputs = build_outputs([Basic( 500_000, BECH32_ADDRESS_ED25519_0, - Some(vec![(TOKEN_ID_1, 100)]), + Some((TOKEN_ID_1, 100)), None, None, None, @@ -1203,7 +1203,7 @@ fn two_basic_outputs_5() { Basic( 1_000_000, BECH32_ADDRESS_ED25519_0, - Some(vec![(TOKEN_ID_1, 100)]), + Some((TOKEN_ID_1, 100)), None, None, None, @@ -1224,7 +1224,7 @@ fn two_basic_outputs_5() { let outputs = build_outputs([Basic( 500_000, BECH32_ADDRESS_ED25519_0, - Some(vec![(TOKEN_ID_1, 100)]), + Some((TOKEN_ID_1, 100)), None, None, None, @@ -1261,7 +1261,7 @@ fn two_basic_outputs_6() { Basic( 1_000_000, BECH32_ADDRESS_ED25519_0, - Some(vec![(TOKEN_ID_1, 100)]), + Some((TOKEN_ID_1, 100)), None, None, None, @@ -1306,7 +1306,7 @@ fn two_basic_outputs_6() { &selected.outputs[1], 1_500_000, BECH32_ADDRESS_ED25519_0, - Some(vec![(TOKEN_ID_1, 50)]), + Some((TOKEN_ID_1, 50)), )); } @@ -1318,7 +1318,7 @@ fn two_basic_outputs_7() { Basic( 1_000_000, BECH32_ADDRESS_ED25519_0, - Some(vec![(TOKEN_ID_1, 100)]), + Some((TOKEN_ID_1, 100)), None, None, None, @@ -1375,7 +1375,7 @@ fn two_basic_outputs_8() { Basic( 1_000_000, BECH32_ADDRESS_ED25519_0, - Some(vec![(TOKEN_ID_1, 100)]), + Some((TOKEN_ID_1, 100)), None, None, None, @@ -1429,7 +1429,7 @@ fn two_basic_outputs_native_tokens_not_needed() { Basic( 1_000_000, BECH32_ADDRESS_ED25519_0, - Some(vec![(TOKEN_ID_1, 100)]), + Some((TOKEN_ID_1, 100)), None, None, None, diff --git a/sdk/tests/client/input_selection/nft_outputs.rs b/sdk/tests/client/input_selection/nft_outputs.rs index 909024f6f2..a73866c7dc 100644 --- a/sdk/tests/client/input_selection/nft_outputs.rs +++ b/sdk/tests/client/input_selection/nft_outputs.rs @@ -38,7 +38,6 @@ fn input_nft_eq_output_nft() { None, None, None, - None, )]); let outputs = build_outputs([Nft( 1_000_000, @@ -49,7 +48,6 @@ fn input_nft_eq_output_nft() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -79,7 +77,6 @@ fn transition_nft_id_zero() { None, None, None, - None, )]); let nft_id = NftId::from(inputs[0].output_id()); let outputs = build_outputs([Nft( @@ -91,7 +88,6 @@ fn transition_nft_id_zero() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -219,7 +215,6 @@ fn mint_nft() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -258,7 +253,6 @@ fn burn_nft() { None, None, None, - None, )]); let outputs = build_outputs([Basic( 2_000_000, @@ -354,7 +348,6 @@ fn missing_input_for_nft_output() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -395,7 +388,6 @@ fn missing_input_for_nft_output_but_created() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -424,7 +416,6 @@ fn nft_in_output_and_sender() { None, None, None, - None, ), Basic(1_000_000, BECH32_ADDRESS_ED25519_0, None, None, None, None, None, None), ]); @@ -438,7 +429,6 @@ fn nft_in_output_and_sender() { None, None, None, - None, ), Basic( 1_000_000, @@ -487,13 +477,11 @@ fn missing_ed25519_sender() { None, None, None, - None, )]); let outputs = build_outputs([Nft( 1_000_000, nft_id_2, BECH32_ADDRESS_ED25519_0, - None, Some(BECH32_ADDRESS_ED25519_1), None, None, @@ -535,7 +523,6 @@ fn missing_ed25519_issuer_created() { nft_id_0, BECH32_ADDRESS_ED25519_0, None, - None, Some(BECH32_ADDRESS_ED25519_1), None, None, @@ -566,7 +553,6 @@ fn missing_ed25519_issuer_transition() { nft_id_1, BECH32_ADDRESS_ED25519_0, None, - None, Some(BECH32_ADDRESS_ED25519_1), None, None, @@ -577,7 +563,6 @@ fn missing_ed25519_issuer_transition() { nft_id_1, BECH32_ADDRESS_ED25519_0, None, - None, Some(BECH32_ADDRESS_ED25519_1), None, None, @@ -609,13 +594,11 @@ fn missing_account_sender() { None, None, None, - None, )]); let outputs = build_outputs([Nft( 1_000_000, nft_id_2, BECH32_ADDRESS_ED25519_0, - None, Some(BECH32_ADDRESS_ACCOUNT_1), None, None, @@ -657,7 +640,6 @@ fn missing_account_issuer_created() { nft_id_0, BECH32_ADDRESS_ED25519_0, None, - None, Some(BECH32_ADDRESS_ACCOUNT_1), None, None, @@ -688,7 +670,6 @@ fn missing_account_issuer_transition() { nft_id_2, BECH32_ADDRESS_ED25519_0, None, - None, Some(BECH32_ADDRESS_ACCOUNT_1), None, None, @@ -699,7 +680,6 @@ fn missing_account_issuer_transition() { nft_id_2, BECH32_ADDRESS_ED25519_0, None, - None, Some(BECH32_ADDRESS_ACCOUNT_1), None, None, @@ -731,13 +711,11 @@ fn missing_nft_sender() { None, None, None, - None, )]); let outputs = build_outputs([Nft( 1_000_000, nft_id_2, BECH32_ADDRESS_ED25519_0, - None, Some(BECH32_ADDRESS_NFT_1), None, None, @@ -779,7 +757,6 @@ fn missing_nft_issuer_created() { nft_id_0, BECH32_ADDRESS_ED25519_0, None, - None, Some(BECH32_ADDRESS_NFT_1), None, None, @@ -810,7 +787,6 @@ fn missing_nft_issuer_transition() { nft_id_2, BECH32_ADDRESS_ED25519_0, None, - None, Some(BECH32_ADDRESS_NFT_1), None, None, @@ -821,7 +797,6 @@ fn missing_nft_issuer_transition() { nft_id_2, BECH32_ADDRESS_ED25519_0, None, - None, Some(BECH32_ADDRESS_NFT_1), None, None, @@ -854,7 +829,6 @@ fn increase_nft_amount() { None, None, None, - None, ), Basic(1_000_000, BECH32_ADDRESS_ED25519_0, None, None, None, None, None, None), ]); @@ -867,7 +841,6 @@ fn increase_nft_amount() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -898,7 +871,6 @@ fn decrease_nft_amount() { None, None, None, - None, ), Basic(1_000_000, BECH32_ADDRESS_ED25519_0, None, None, None, None, None, None), ]); @@ -911,7 +883,6 @@ fn decrease_nft_amount() { None, None, None, - None, )]); let selected = InputSelection::new( @@ -954,7 +925,6 @@ fn prefer_basic_to_nft() { None, None, None, - None, ), Basic(1_000_000, BECH32_ADDRESS_ED25519_0, None, None, None, None, None, None), ]); @@ -998,7 +968,6 @@ fn take_amount_from_nft_to_fund_basic() { None, None, None, - None, ), Basic(1_000_000, BECH32_ADDRESS_ED25519_0, None, None, None, None, None, None), ]); @@ -1029,7 +998,6 @@ fn take_amount_from_nft_to_fund_basic() { if !outputs.contains(output) { assert!(output.is_nft()); assert_eq!(output.amount(), 1_800_000); - assert_eq!(output.as_nft().native_tokens().len(), 0); assert_eq!(output.as_nft().unlock_conditions().len(), 1); assert_eq!(output.as_nft().features().len(), 0); assert_eq!( @@ -1056,7 +1024,6 @@ fn nft_burn_should_validate_nft_sender() { None, None, None, - None, ), ]); let outputs = build_outputs([Basic( @@ -1100,7 +1067,6 @@ fn nft_burn_should_validate_nft_address() { None, None, None, - None, ), ]); let outputs = build_outputs([Basic( @@ -1142,7 +1108,6 @@ fn transitioned_zero_nft_id_no_longer_is_zero() { None, None, None, - None, )]); let outputs = build_outputs([Basic( 1_000_000, @@ -1172,7 +1137,6 @@ fn transitioned_zero_nft_id_no_longer_is_zero() { assert!(output.is_nft()); assert_eq!(output.amount(), 1_000_000); assert_ne!(*output.as_nft().nft_id(), nft_id_0); - assert_eq!(output.as_nft().native_tokens().len(), 0); assert_eq!(output.as_nft().unlock_conditions().len(), 1); assert_eq!(output.as_nft().features().len(), 0); assert_eq!( diff --git a/sdk/tests/client/input_selection/outputs.rs b/sdk/tests/client/input_selection/outputs.rs index 02697eadb1..4977a0eb72 100644 --- a/sdk/tests/client/input_selection/outputs.rs +++ b/sdk/tests/client/input_selection/outputs.rs @@ -81,7 +81,6 @@ fn no_outputs_but_burn() { None, None, None, - None, )]); let outputs = Vec::new(); diff --git a/sdk/tests/client/input_selection/storage_deposit_return.rs b/sdk/tests/client/input_selection/storage_deposit_return.rs index d74121fef7..55e8fb23dc 100644 --- a/sdk/tests/client/input_selection/storage_deposit_return.rs +++ b/sdk/tests/client/input_selection/storage_deposit_return.rs @@ -504,15 +504,7 @@ fn sdruc_required_non_ed25519_in_address_unlock() { None, None, ), - Account( - 1_000_000, - account_id_1, - BECH32_ADDRESS_ED25519_0, - None, - None, - None, - None, - ), + Account(1_000_000, account_id_1, BECH32_ADDRESS_ED25519_0, None, None, None), ]); let outputs = build_outputs([Basic( 1_000_000, @@ -566,15 +558,7 @@ fn useless_sdruc_non_ed25519_in_address_unlock() { None, ), Basic(1_000_000, BECH32_ADDRESS_ACCOUNT_1, None, None, None, None, None, None), - Account( - 1_000_000, - account_id_1, - BECH32_ADDRESS_ED25519_0, - None, - None, - None, - None, - ), + Account(1_000_000, account_id_1, BECH32_ADDRESS_ED25519_0, None, None, None), ]); let outputs = build_outputs([Basic( 1_000_000, diff --git a/sdk/tests/client/mod.rs b/sdk/tests/client/mod.rs index d01b8a394c..8edc869ebf 100644 --- a/sdk/tests/client/mod.rs +++ b/sdk/tests/client/mod.rs @@ -15,11 +15,7 @@ mod node_api; mod secret_manager; mod signing; -use std::{ - collections::{BTreeSet, HashMap}, - hash::Hash, - str::FromStr, -}; +use std::{collections::HashMap, hash::Hash, str::FromStr}; use crypto::keys::bip44::Bip44; use iota_sdk::{ @@ -32,8 +28,8 @@ use iota_sdk::{ AddressUnlockCondition, ExpirationUnlockCondition, ImmutableAccountAddressUnlockCondition, StorageDepositReturnUnlockCondition, TimelockUnlockCondition, UnlockCondition, }, - AccountId, AccountOutputBuilder, BasicOutputBuilder, FoundryOutputBuilder, NativeToken, NativeTokens, - NftId, NftOutputBuilder, Output, OutputId, OutputMetadata, SimpleTokenScheme, TokenId, TokenScheme, + AccountId, AccountOutputBuilder, BasicOutputBuilder, FoundryOutputBuilder, NativeToken, NftId, + NftOutputBuilder, Output, OutputId, OutputMetadata, SimpleTokenScheme, TokenId, TokenScheme, }, rand::{block::rand_block_id, slot::rand_slot_commitment_id, transaction::rand_transaction_id}, }, @@ -63,7 +59,7 @@ enum Build<'a> { Basic( u64, &'a str, - Option>, + Option<(&'a str, u64)>, Option<&'a str>, Option<(&'a str, u64)>, Option, @@ -74,29 +70,20 @@ enum Build<'a> { u64, NftId, &'a str, - Option>, Option<&'a str>, Option<&'a str>, Option<(&'a str, u64)>, Option<(&'a str, u32)>, Option, ), - Account( - u64, - AccountId, - &'a str, - Option>, - Option<&'a str>, - Option<&'a str>, - Option, - ), - Foundry(u64, AccountId, u32, SimpleTokenScheme, Option>), + Account(u64, AccountId, &'a str, Option<&'a str>, Option<&'a str>, Option), + Foundry(u64, AccountId, u32, SimpleTokenScheme, Option<(&'a str, u64)>), } fn build_basic_output( amount: u64, bech32_address: Bech32Address, - native_tokens: Option>, + native_token: Option<(&str, u64)>, bech32_sender: Option, sdruc: Option<(Bech32Address, u64)>, timelock: Option, @@ -105,12 +92,8 @@ fn build_basic_output( let mut builder = BasicOutputBuilder::new_with_amount(amount).add_unlock_condition(AddressUnlockCondition::new(bech32_address)); - if let Some(native_tokens) = native_tokens { - builder = builder.with_native_tokens( - native_tokens - .into_iter() - .map(|(id, amount)| NativeToken::new(TokenId::from_str(id).unwrap(), amount).unwrap()), - ); + if let Some((id, amount)) = native_token { + builder = builder.with_native_token(NativeToken::new(TokenId::from_str(id).unwrap(), amount).unwrap()); } if let Some(bech32_sender) = bech32_sender { @@ -137,7 +120,6 @@ fn build_nft_output( amount: u64, nft_id: NftId, bech32_address: Bech32Address, - native_tokens: Option>, bech32_sender: Option, bech32_issuer: Option, sdruc: Option<(Bech32Address, u64)>, @@ -146,14 +128,6 @@ fn build_nft_output( let mut builder = NftOutputBuilder::new_with_amount(amount, nft_id) .add_unlock_condition(AddressUnlockCondition::new(bech32_address)); - if let Some(native_tokens) = native_tokens { - builder = builder.with_native_tokens( - native_tokens - .into_iter() - .map(|(id, amount)| NativeToken::new(TokenId::from_str(id).unwrap(), amount).unwrap()), - ); - } - if let Some(bech32_sender) = bech32_sender { builder = builder.add_feature(SenderFeature::new(bech32_sender)); } @@ -178,21 +152,12 @@ fn build_account_output( amount: u64, account_id: AccountId, address: Bech32Address, - native_tokens: Option>, bech32_sender: Option, bech32_issuer: Option, ) -> Output { let mut builder = AccountOutputBuilder::new_with_amount(amount, account_id) .add_unlock_condition(AddressUnlockCondition::new(address)); - if let Some(native_tokens) = native_tokens { - builder = builder.with_native_tokens( - native_tokens - .into_iter() - .map(|(id, amount)| NativeToken::new(TokenId::from_str(id).unwrap(), amount).unwrap()), - ); - } - if let Some(bech32_sender) = bech32_sender { builder = builder.add_feature(SenderFeature::new(bech32_sender)); } @@ -209,19 +174,15 @@ fn build_foundry_output( account_id: AccountId, serial_number: u32, token_scheme: SimpleTokenScheme, - native_tokens: Option>, + native_token: Option<(&str, u64)>, ) -> Output { let mut builder = FoundryOutputBuilder::new_with_amount(amount, serial_number, TokenScheme::Simple(token_scheme)) .add_unlock_condition(ImmutableAccountAddressUnlockCondition::new(AccountAddress::new( account_id, ))); - if let Some(native_tokens) = native_tokens { - builder = builder.with_native_tokens( - native_tokens - .into_iter() - .map(|(id, amount)| NativeToken::new(TokenId::from_str(id).unwrap(), amount).unwrap()), - ); + if let Some((id, amount)) = native_token { + builder = builder.with_native_token(NativeToken::new(TokenId::from_str(id).unwrap(), amount).unwrap()); } builder.finish_output().unwrap() @@ -229,11 +190,11 @@ fn build_foundry_output( fn build_output_inner(build: Build) -> (Output, Option) { match build { - Build::Basic(amount, bech32_address, native_tokens, bech32_sender, sdruc, timelock, expiration, chain) => ( + Build::Basic(amount, bech32_address, native_token, bech32_sender, sdruc, timelock, expiration, chain) => ( build_basic_output( amount, Bech32Address::try_from_str(bech32_address).unwrap(), - native_tokens, + native_token, bech32_sender.map(|address| Bech32Address::try_from_str(address).unwrap()), sdruc.map(|(address, exp)| (Bech32Address::try_from_str(address).unwrap(), exp)), timelock, @@ -241,22 +202,11 @@ fn build_output_inner(build: Build) -> (Output, Option) { ), chain, ), - Build::Nft( - amount, - nft_id, - bech32_address, - native_tokens, - bech32_sender, - bech32_issuer, - sdruc, - expiration, - chain, - ) => ( + Build::Nft(amount, nft_id, bech32_address, bech32_sender, bech32_issuer, sdruc, expiration, chain) => ( build_nft_output( amount, nft_id, Bech32Address::try_from_str(bech32_address).unwrap(), - native_tokens, bech32_sender.map(|address| Bech32Address::try_from_str(address).unwrap()), bech32_issuer.map(|address| Bech32Address::try_from_str(address).unwrap()), sdruc.map(|(address, exp)| (Bech32Address::try_from_str(address).unwrap(), exp)), @@ -264,19 +214,18 @@ fn build_output_inner(build: Build) -> (Output, Option) { ), chain, ), - Build::Account(amount, account_id, address, native_tokens, bech32_sender, bech32_issuer, chain) => ( + Build::Account(amount, account_id, address, bech32_sender, bech32_issuer, chain) => ( build_account_output( amount, account_id, Bech32Address::try_from_str(address).unwrap(), - native_tokens, bech32_sender.map(|address| Bech32Address::try_from_str(address).unwrap()), bech32_issuer.map(|address| Bech32Address::try_from_str(address).unwrap()), ), chain, ), - Build::Foundry(amount, account_id, serial_number, token_scheme, native_tokens) => ( - build_foundry_output(amount, account_id, serial_number, token_scheme, native_tokens), + Build::Foundry(amount, account_id, serial_number, token_scheme, native_token) => ( + build_foundry_output(amount, account_id, serial_number, token_scheme, native_token), None, ), } @@ -327,12 +276,7 @@ where count(a) == count(b) } -fn is_remainder_or_return( - output: &Output, - amount: u64, - address: &str, - native_tokens: Option>, -) -> bool { +fn is_remainder_or_return(output: &Output, amount: u64, address: &str, native_token: Option<(&str, u64)>) -> bool { if let Output::Basic(output) = output { if output.amount() != amount { return false; @@ -352,19 +296,13 @@ fn is_remainder_or_return( return false; } - if let Some(native_tokens) = native_tokens { - let native_tokens = NativeTokens::from_set( - native_tokens - .into_iter() - .map(|(token_id, amount)| NativeToken::new(TokenId::from_str(token_id).unwrap(), amount).unwrap()) - .collect::>(), - ) - .unwrap(); + if let Some((token_id, amount)) = native_token { + let native_token = NativeToken::new(TokenId::from_str(token_id).unwrap(), amount).unwrap(); - if output.native_tokens() != &native_tokens { + if output.native_token().unwrap() != &native_token { return false; } - } else if output.native_tokens().len() != 0 { + } else if output.native_token().is_some() { return false; } diff --git a/sdk/tests/client/signing/account.rs b/sdk/tests/client/signing/account.rs index 9696182f7d..1299085942 100644 --- a/sdk/tests/client/signing/account.rs +++ b/sdk/tests/client/signing/account.rs @@ -55,7 +55,6 @@ async fn sign_account_state_transition() -> Result<()> { &bech32_address.to_string(), None, None, - None, Some(Bip44::new(SHIMMER_COIN_TYPE)), )]); @@ -66,7 +65,6 @@ async fn sign_account_state_transition() -> Result<()> { None, None, None, - None, )]); let transaction = Transaction::builder(protocol_parameters.network_id()) @@ -130,7 +128,6 @@ async fn account_reference_unlocks() -> Result<()> { &bech32_address.to_string(), None, None, - None, Some(Bip44::new(SHIMMER_COIN_TYPE)), ), Basic( @@ -156,15 +153,7 @@ async fn account_reference_unlocks() -> Result<()> { ]); let outputs = build_outputs([ - Account( - 1_000_000, - account_id, - &bech32_address.to_string(), - None, - None, - None, - None, - ), + Account(1_000_000, account_id, &bech32_address.to_string(), None, None, None), Basic( 2_000_000, &account_bech32_address.to_string(), diff --git a/sdk/tests/client/signing/mod.rs b/sdk/tests/client/signing/mod.rs index 55c63fddf9..fba3641404 100644 --- a/sdk/tests/client/signing/mod.rs +++ b/sdk/tests/client/signing/mod.rs @@ -87,7 +87,6 @@ async fn all_combined() -> Result<()> { None, None, None, - None, ), Account( 1_000_000, @@ -95,7 +94,6 @@ async fn all_combined() -> Result<()> { &ed25519_bech32_address_0.to_string(), None, None, - None, Some(Bip44::new(SHIMMER_COIN_TYPE)), ), Basic( @@ -206,7 +204,6 @@ async fn all_combined() -> Result<()> { None, None, None, - None, Some(Bip44::new(SHIMMER_COIN_TYPE)), ), Nft( @@ -218,7 +215,6 @@ async fn all_combined() -> Result<()> { None, None, None, - None, ), // Expirations Basic( @@ -258,7 +254,6 @@ async fn all_combined() -> Result<()> { None, None, None, - None, Some((&nft_4_bech32_address.to_string(), 50)), None, ), @@ -269,7 +264,6 @@ async fn all_combined() -> Result<()> { None, None, None, - None, Some((&nft_3_bech32_address.to_string(), 150)), None, ), @@ -283,7 +277,6 @@ async fn all_combined() -> Result<()> { None, None, None, - None, ), Account( 1_000_000, @@ -292,7 +285,6 @@ async fn all_combined() -> Result<()> { None, None, None, - None, ), Basic( 10_000_000, @@ -313,7 +305,6 @@ async fn all_combined() -> Result<()> { None, None, None, - None, ), Nft( 1_000_000, @@ -324,7 +315,6 @@ async fn all_combined() -> Result<()> { None, None, None, - None, ), Nft( 1_000_000, @@ -335,7 +325,6 @@ async fn all_combined() -> Result<()> { None, None, None, - None, ), Nft( 1_000_000, @@ -346,7 +335,6 @@ async fn all_combined() -> Result<()> { None, None, None, - None, ), ]); diff --git a/sdk/tests/client/signing/nft.rs b/sdk/tests/client/signing/nft.rs index 1d4a52c785..8ca9d544f1 100644 --- a/sdk/tests/client/signing/nft.rs +++ b/sdk/tests/client/signing/nft.rs @@ -59,7 +59,6 @@ async fn nft_reference_unlocks() -> Result<()> { None, None, None, - None, Some(Bip44::new(SHIMMER_COIN_TYPE)), ), Basic( @@ -94,7 +93,6 @@ async fn nft_reference_unlocks() -> Result<()> { None, None, None, - None, ), Basic( 2_000_000, diff --git a/sdk/tests/types/output/account.rs b/sdk/tests/types/output/account.rs index 554e5f9a8f..57f5b2474c 100644 --- a/sdk/tests/types/output/account.rs +++ b/sdk/tests/types/output/account.rs @@ -2,8 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 use iota_sdk::types::block::{ - address::AccountAddress, - output::{AccountOutput, Feature, FoundryId, MinimumOutputAmount, NativeToken, SimpleTokenScheme, TokenId}, + output::{AccountOutput, Feature, MinimumOutputAmount}, protocol::protocol_parameters, rand::output::{ feature::{rand_issuer_feature, rand_metadata_feature, rand_sender_feature}, @@ -18,7 +17,6 @@ use pretty_assertions::assert_eq; fn builder() { let protocol_parameters = protocol_parameters(); let account_id = rand_account_id(); - let foundry_id = FoundryId::build(&AccountAddress::from(account_id), 0, SimpleTokenScheme::KIND); let address_1 = rand_address_unlock_condition_different_from_account_id(&account_id); let address_2 = rand_address_unlock_condition_different_from_account_id(&account_id); let sender_1 = rand_sender_feature(); @@ -28,7 +26,6 @@ fn builder() { let amount = 500_000; let mut builder = AccountOutput::build_with_amount(amount, account_id) - .add_native_token(NativeToken::new(TokenId::from(foundry_id), 1000).unwrap()) .add_unlock_condition(address_1.clone()) .add_feature(sender_1.clone()) .replace_feature(sender_2.clone()) diff --git a/sdk/tests/types/output/basic.rs b/sdk/tests/types/output/basic.rs index 9c675541e4..42268b7afe 100644 --- a/sdk/tests/types/output/basic.rs +++ b/sdk/tests/types/output/basic.rs @@ -27,7 +27,7 @@ fn builder() { let amount = 500_000; let mut builder = BasicOutput::build_with_amount(amount) - .add_native_token(NativeToken::new(TokenId::from(foundry_id), 1000).unwrap()) + .with_native_token(NativeToken::new(TokenId::from(foundry_id), 1000).unwrap()) .add_unlock_condition(address_1.clone()) .add_feature(sender_1.clone()) .replace_feature(sender_2.clone()); diff --git a/sdk/tests/types/output/foundry.rs b/sdk/tests/types/output/foundry.rs index 00ba0bd331..f52388bbf3 100644 --- a/sdk/tests/types/output/foundry.rs +++ b/sdk/tests/types/output/foundry.rs @@ -27,7 +27,7 @@ fn builder() { let mut builder = FoundryOutput::build_with_amount(amount, 234, rand_token_scheme()) .with_serial_number(85) - .add_native_token(NativeToken::new(TokenId::from(foundry_id), 1000).unwrap()) + .with_native_token(NativeToken::new(TokenId::from(foundry_id), 1000).unwrap()) .with_unlock_conditions([account_1]) .add_feature(metadata_1.clone()) .replace_feature(metadata_2.clone()) diff --git a/sdk/tests/types/output/nft.rs b/sdk/tests/types/output/nft.rs index 3bdeac1bb2..5eb4322ecf 100644 --- a/sdk/tests/types/output/nft.rs +++ b/sdk/tests/types/output/nft.rs @@ -2,15 +2,12 @@ // SPDX-License-Identifier: Apache-2.0 use iota_sdk::types::block::{ - output::{FoundryId, MinimumOutputAmount, NativeToken, NftId, NftOutput, SimpleTokenScheme, TokenId}, + output::{MinimumOutputAmount, NftId, NftOutput}, protocol::protocol_parameters, - rand::{ - address::rand_account_address, - output::{ - feature::{rand_issuer_feature, rand_sender_feature}, - rand_nft_output, - unlock_condition::rand_address_unlock_condition, - }, + rand::output::{ + feature::{rand_issuer_feature, rand_sender_feature}, + rand_nft_output, + unlock_condition::rand_address_unlock_condition, }, }; use packable::PackableExt; @@ -19,7 +16,6 @@ use pretty_assertions::assert_eq; #[test] fn builder() { let protocol_parameters = protocol_parameters(); - let foundry_id = FoundryId::build(&rand_account_address(), 0, SimpleTokenScheme::KIND); let address_1 = rand_address_unlock_condition(); let address_2 = rand_address_unlock_condition(); let sender_1 = rand_sender_feature(); @@ -29,7 +25,6 @@ fn builder() { let amount = 500_000; let mut builder = NftOutput::build_with_amount(amount, NftId::null()) - .add_native_token(NativeToken::new(TokenId::from(foundry_id), 1000).unwrap()) .add_unlock_condition(address_1.clone()) .add_feature(sender_1) .replace_feature(sender_2.clone()) diff --git a/sdk/tests/types/transaction.rs b/sdk/tests/types/transaction.rs index 5e696ac391..de81bb75be 100644 --- a/sdk/tests/types/transaction.rs +++ b/sdk/tests/types/transaction.rs @@ -440,7 +440,7 @@ fn duplicate_output_foundry() { let foundry_id = FoundryId::build(&AccountAddress::from(account_id), 1, token_scheme.kind()); let token_id = TokenId::from(foundry_id); let foundry = FoundryOutput::build_with_amount(1_000_000, 1, token_scheme) - .add_native_token(NativeToken::new(token_id, 70).unwrap()) + .with_native_token(NativeToken::new(token_id, 70).unwrap()) .add_unlock_condition(ImmutableAccountAddressUnlockCondition::new(AccountAddress::from( account_id, ))) diff --git a/sdk/tests/wallet/claim_outputs.rs b/sdk/tests/wallet/claim_outputs.rs index ae52af1961..4971a8a5e8 100644 --- a/sdk/tests/wallet/claim_outputs.rs +++ b/sdk/tests/wallet/claim_outputs.rs @@ -6,7 +6,7 @@ use iota_sdk::{ unlock_condition::{AddressUnlockCondition, ExpirationUnlockCondition}, BasicOutputBuilder, NativeToken, NftId, NftOutputBuilder, UnlockCondition, }, - wallet::{CreateNativeTokenParams, OutputsToClaim, Result, SendNativeTokensParams, SendParams, TransactionOptions}, + wallet::{CreateNativeTokenParams, OutputsToClaim, Result, SendNativeTokenParams, SendParams, TransactionOptions}, U256, }; use pretty_assertions::assert_eq; @@ -240,8 +240,8 @@ async fn claim_2_native_tokens() -> Result<()> { let tx = wallet_1 .send_native_tokens( [ - SendNativeTokensParams::new(wallet_0.address().await, [(create_tx_0.token_id, native_token_amount)])?, - SendNativeTokensParams::new(wallet_0.address().await, [(create_tx_1.token_id, native_token_amount)])?, + SendNativeTokenParams::new(wallet_0.address().await, (create_tx_0.token_id, native_token_amount))?, + SendNativeTokenParams::new(wallet_0.address().await, (create_tx_1.token_id, native_token_amount))?, ], None, ) @@ -347,7 +347,7 @@ async fn claim_2_native_tokens_no_outputs_in_claim_account() -> Result<()> { wallet_0.address().await, wallet_0.client().get_slot_index().await? + 5000, )?) - .add_native_token(NativeToken::new(create_tx_0.token_id, native_token_amount)?) + .with_native_token(NativeToken::new(create_tx_0.token_id, native_token_amount)?) .finish_output()?, BasicOutputBuilder::new_with_minimum_amount(storage_score_params) .add_unlock_condition(AddressUnlockCondition::new(wallet_1.address().await)) @@ -355,7 +355,7 @@ async fn claim_2_native_tokens_no_outputs_in_claim_account() -> Result<()> { wallet_0.address().await, wallet_0.client().get_slot_index().await? + 5000, )?) - .add_native_token(NativeToken::new(create_tx_1.token_id, native_token_amount)?) + .with_native_token(NativeToken::new(create_tx_1.token_id, native_token_amount)?) .finish_output()?, ], None, diff --git a/sdk/tests/wallet/output_preparation.rs b/sdk/tests/wallet/output_preparation.rs index 8a2e294a03..4ab33ba562 100644 --- a/sdk/tests/wallet/output_preparation.rs +++ b/sdk/tests/wallet/output_preparation.rs @@ -74,11 +74,14 @@ async fn output_preparation() -> Result<()> { OutputParams { recipient_address: recipient_address.clone(), amount: 500000, - assets: Some(Assets { - native_tokens: Some(vec![native_token]), - nft_id: None, + assets: Some(Assets { nft_id: None }), + features: Some(Features { + metadata: None, + tag: None, + issuer: None, + sender: None, + native_token: Some(native_token), }), - features: None, unlocks: None, storage_deposit: None, }, @@ -88,7 +91,7 @@ async fn output_preparation() -> Result<()> { assert_eq!(output.amount(), 500000); // only address condition assert_eq!(output.unlock_conditions().unwrap().len(), 1); - assert_eq!(output.native_tokens().unwrap().first(), Some(&native_token)); + assert_eq!(output.native_token(), Some(&native_token)); let output = wallet .prepare_output( @@ -101,6 +104,7 @@ async fn output_preparation() -> Result<()> { tag: Some(prefix_hex::encode(b"My Tag")), issuer: None, sender: None, + native_token: None, }), unlocks: None, storage_deposit: None, @@ -126,6 +130,7 @@ async fn output_preparation() -> Result<()> { tag: Some(prefix_hex::encode(b"My Tag")), issuer: None, sender: None, + native_token: None, }), unlocks: None, storage_deposit: None, @@ -154,6 +159,7 @@ async fn output_preparation() -> Result<()> { tag: Some(prefix_hex::encode(b"My Tag")), issuer: None, sender: None, + native_token: None, }), unlocks: None, storage_deposit: None, @@ -179,6 +185,7 @@ async fn output_preparation() -> Result<()> { tag: Some(prefix_hex::encode(b"My Tag")), issuer: None, sender: None, + native_token: None, }), unlocks: None, storage_deposit: None, @@ -203,7 +210,6 @@ async fn output_preparation() -> Result<()> { recipient_address: recipient_address.clone(), amount: 500000, assets: Some(Assets { - native_tokens: None, nft_id: Some(NftId::from_str( "0xa068e00a79922eaef241592a7440f131ea7f8ad9e22e580ef139415f273eff30", )?), @@ -227,7 +233,6 @@ async fn output_preparation() -> Result<()> { recipient_address: recipient_address.clone(), amount: 500000, assets: Some(Assets { - native_tokens: None, nft_id: Some(NftId::from_str( "0x0000000000000000000000000000000000000000000000000000000000000000", )?), @@ -258,15 +263,13 @@ async fn output_preparation() -> Result<()> { OutputParams { recipient_address: recipient_address.clone(), amount: 500000, - assets: Some(Assets { - native_tokens: Some(vec![native_token]), - nft_id: None, - }), + assets: Some(Assets { nft_id: None }), features: Some(Features { metadata: None, tag: None, issuer: None, sender: Some(issuer_and_sender_address.clone()), + native_token: Some(native_token), }), unlocks: None, storage_deposit: None, @@ -294,6 +297,7 @@ async fn output_preparation() -> Result<()> { tag: None, issuer: Some(issuer_and_sender_address.clone()), sender: None, + native_token: None, }), unlocks: None, storage_deposit: None, @@ -314,7 +318,6 @@ async fn output_preparation() -> Result<()> { recipient_address: recipient_address.clone(), amount: 500000, assets: Some(Assets { - native_tokens: None, nft_id: Some(NftId::from_str( "0x0000000000000000000000000000000000000000000000000000000000000000", )?), @@ -324,6 +327,7 @@ async fn output_preparation() -> Result<()> { tag: None, issuer: Some(issuer_and_sender_address.clone()), sender: Some(issuer_and_sender_address.clone()), + native_token: None, }), unlocks: Some(Unlocks { expiration_slot_index: Some(SlotIndex::from(1)), @@ -358,7 +362,6 @@ async fn output_preparation() -> Result<()> { recipient_address: recipient_address.clone(), amount: 500, assets: Some(Assets { - native_tokens: None, nft_id: Some(NftId::from_str( "0x0000000000000000000000000000000000000000000000000000000000000000", )?), @@ -368,6 +371,7 @@ async fn output_preparation() -> Result<()> { tag: None, issuer: None, sender: None, + native_token: None, }), unlocks: Some(Unlocks { expiration_slot_index: Some(SlotIndex::from(1)), @@ -394,6 +398,7 @@ async fn output_preparation() -> Result<()> { tag: Some(prefix_hex::encode(b"My Tag")), issuer: None, sender: None, + native_token: None, }), unlocks: None, storage_deposit: Some(StorageDeposit { @@ -559,15 +564,13 @@ async fn prepare_nft_output_features_update() -> Result<()> { OutputParams { recipient_address: wallet_address, amount: 1_000_000, - assets: Some(Assets { - native_tokens: None, - nft_id: Some(nft_id), - }), + assets: Some(Assets { nft_id: Some(nft_id) }), features: Some(Features { metadata: Some("0x2a".to_string()), tag: None, issuer: None, sender: None, + native_token: None, }), unlocks: None, storage_deposit: None, @@ -771,10 +774,7 @@ async fn prepare_output_only_single_nft() -> Result<()> { OutputParams { recipient_address: wallet_0_address, amount: nft_data.output.amount(), - assets: Some(Assets { - native_tokens: None, - nft_id: Some(nft_id), - }), + assets: Some(Assets { nft_id: Some(nft_id) }), features: None, unlocks: None, storage_deposit: None, @@ -832,10 +832,7 @@ async fn prepare_existing_nft_output_gift() -> Result<()> { OutputParams { recipient_address: address, amount: 0, - assets: Some(Assets { - native_tokens: None, - nft_id: Some(nft_id), - }), + assets: Some(Assets { nft_id: Some(nft_id) }), features: None, unlocks: None, storage_deposit: Some(StorageDeposit {