mirror of
https://github.com/logos-blockchain/lssa.git
synced 2026-01-02 05:13:08 +00:00
Merge branch 'main' into Pravdyvy/amm-wallet-integration
This commit is contained in:
commit
2d1ee4b279
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -2658,6 +2658,7 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"borsh",
|
"borsh",
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
|
"env_logger",
|
||||||
"hex",
|
"hex",
|
||||||
"hex-literal 1.1.0",
|
"hex-literal 1.1.0",
|
||||||
"log",
|
"log",
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -347,11 +347,14 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
|||||||
|
|
||||||
assert_eq!(definition_acc.program_owner, Program::token().id());
|
assert_eq!(definition_acc.program_owner, Program::token().id());
|
||||||
// The data of a token definition account has the following layout:
|
// The data of a token definition account has the following layout:
|
||||||
// [ 0x00 || name (6 bytes) || total supply (little endian 16 bytes) ]
|
// [ 0x00 || name (6 bytes) || total supply (little endian 16 bytes) || metadata id (32
|
||||||
|
// bytes)]
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
definition_acc.data.as_ref(),
|
definition_acc.data.as_ref(),
|
||||||
&[
|
&[
|
||||||
0, 65, 32, 78, 65, 77, 69, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
0, 65, 32, 78, 65, 77, 69, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -434,6 +437,94 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
|||||||
u128::from_le_bytes(recipient_acc.data[33..].try_into().unwrap()),
|
u128::from_le_bytes(recipient_acc.data[33..].try_into().unwrap()),
|
||||||
7
|
7
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Burn 3 tokens from `recipient_acc`
|
||||||
|
let subcommand = TokenProgramAgnosticSubcommand::Burn {
|
||||||
|
definition: make_public_account_input_from_str(&definition_account_id.to_string()),
|
||||||
|
holder: make_public_account_input_from_str(&recipient_account_id.to_string()),
|
||||||
|
amount: 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
wallet::cli::execute_subcommand(Command::Token(subcommand))
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
info!("Waiting for next block creation");
|
||||||
|
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
|
||||||
|
|
||||||
|
// Check the status of the token definition account is the expected after the execution
|
||||||
|
let definition_acc = seq_client
|
||||||
|
.get_account(definition_account_id.to_string())
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.account;
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
definition_acc.data.as_ref(),
|
||||||
|
&[
|
||||||
|
0, 65, 32, 78, 65, 77, 69, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
// Check the status of the account at `recipient_account_id` is the expected after the
|
||||||
|
// execution
|
||||||
|
let recipient_acc = seq_client
|
||||||
|
.get_account(recipient_account_id.to_string())
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.account;
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
u128::from_le_bytes(recipient_acc.data[33..].try_into().unwrap()),
|
||||||
|
4
|
||||||
|
);
|
||||||
|
|
||||||
|
// Mint 10 tokens at `recipient_acc`
|
||||||
|
let subcommand = TokenProgramAgnosticSubcommand::Mint {
|
||||||
|
definition: make_public_account_input_from_str(&definition_account_id.to_string()),
|
||||||
|
holder: Some(make_public_account_input_from_str(
|
||||||
|
&recipient_account_id.to_string(),
|
||||||
|
)),
|
||||||
|
holder_npk: None,
|
||||||
|
holder_ipk: None,
|
||||||
|
amount: 10,
|
||||||
|
};
|
||||||
|
|
||||||
|
wallet::cli::execute_subcommand(Command::Token(subcommand))
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
info!("Waiting for next block creation");
|
||||||
|
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
|
||||||
|
|
||||||
|
// Check the status of the token definition account is the expected after the execution
|
||||||
|
let definition_acc = seq_client
|
||||||
|
.get_account(definition_account_id.to_string())
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.account;
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
definition_acc.data.as_ref(),
|
||||||
|
&[
|
||||||
|
0, 65, 32, 78, 65, 77, 69, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
// Check the status of the account at `recipient_account_id` is the expected after the
|
||||||
|
// execution
|
||||||
|
let recipient_acc = seq_client
|
||||||
|
.get_account(recipient_account_id.to_string())
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.account;
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
u128::from_le_bytes(recipient_acc.data[33..].try_into().unwrap()),
|
||||||
|
14
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This test creates a new private token using the token program. After creating the token, the
|
/// This test creates a new private token using the token program. After creating the token, the
|
||||||
@ -506,11 +597,14 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
|||||||
|
|
||||||
assert_eq!(definition_acc.program_owner, Program::token().id());
|
assert_eq!(definition_acc.program_owner, Program::token().id());
|
||||||
// The data of a token definition account has the following layout:
|
// The data of a token definition account has the following layout:
|
||||||
// [ 0x00 || name (6 bytes) || total supply (little endian 16 bytes) ]
|
// [ 0x00 || name (6 bytes) || total supply (little endian 16 bytes) || metadata id (32
|
||||||
|
// bytes)]
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
definition_acc.data.as_ref(),
|
definition_acc.data.as_ref(),
|
||||||
&[
|
&[
|
||||||
0, 65, 32, 78, 65, 77, 69, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
0, 65, 32, 78, 65, 77, 69, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -590,6 +684,194 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
|||||||
.get_private_account_commitment(&recipient_account_id)
|
.get_private_account_commitment(&recipient_account_id)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert!(verify_commitment_is_in_state(new_commitment2, &seq_client).await);
|
assert!(verify_commitment_is_in_state(new_commitment2, &seq_client).await);
|
||||||
|
|
||||||
|
// Burn 3 tokens from `recipient_acc`
|
||||||
|
let subcommand = TokenProgramAgnosticSubcommand::Burn {
|
||||||
|
definition: make_public_account_input_from_str(&definition_account_id.to_string()),
|
||||||
|
holder: make_private_account_input_from_str(&recipient_account_id.to_string()),
|
||||||
|
amount: 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
wallet::cli::execute_subcommand(Command::Token(subcommand))
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
info!("Waiting for next block creation");
|
||||||
|
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
|
||||||
|
|
||||||
|
// Check the status of the token definition account is the expected after the execution
|
||||||
|
let definition_acc = seq_client
|
||||||
|
.get_account(definition_account_id.to_string())
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.account;
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
definition_acc.data.as_ref(),
|
||||||
|
&[
|
||||||
|
0, 65, 32, 78, 65, 77, 69, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
let wallet_config = fetch_config().await.unwrap();
|
||||||
|
let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let new_commitment2 = wallet_storage
|
||||||
|
.get_private_account_commitment(&recipient_account_id)
|
||||||
|
.unwrap();
|
||||||
|
assert!(verify_commitment_is_in_state(new_commitment2, &seq_client).await);
|
||||||
|
|
||||||
|
// Check the status of the account at `recipient_account_id` is the expected after the
|
||||||
|
// execution
|
||||||
|
let recipient_acc = wallet_storage
|
||||||
|
.get_account_private(&recipient_account_id)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
u128::from_le_bytes(recipient_acc.data[33..].try_into().unwrap()),
|
||||||
|
11
|
||||||
|
);
|
||||||
|
|
||||||
|
// Mint 10 tokens at `recipient_acc`
|
||||||
|
let subcommand = TokenProgramAgnosticSubcommand::Mint {
|
||||||
|
definition: make_public_account_input_from_str(&definition_account_id.to_string()),
|
||||||
|
holder: Some(make_private_account_input_from_str(
|
||||||
|
&recipient_account_id.to_string(),
|
||||||
|
)),
|
||||||
|
holder_npk: None,
|
||||||
|
holder_ipk: None,
|
||||||
|
amount: 10,
|
||||||
|
};
|
||||||
|
|
||||||
|
wallet::cli::execute_subcommand(Command::Token(subcommand))
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
info!("Waiting for next block creation");
|
||||||
|
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
|
||||||
|
|
||||||
|
// Check the status of the token definition account is the expected after the execution
|
||||||
|
let definition_acc = seq_client
|
||||||
|
.get_account(definition_account_id.to_string())
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.account;
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
definition_acc.data.as_ref(),
|
||||||
|
&[
|
||||||
|
0, 65, 32, 78, 65, 77, 69, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
let wallet_config = fetch_config().await.unwrap();
|
||||||
|
let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let new_commitment2 = wallet_storage
|
||||||
|
.get_private_account_commitment(&recipient_account_id)
|
||||||
|
.unwrap();
|
||||||
|
assert!(verify_commitment_is_in_state(new_commitment2, &seq_client).await);
|
||||||
|
|
||||||
|
// Check the status of the account at `recipient_account_id` is the expected after the
|
||||||
|
// execution
|
||||||
|
let recipient_acc = wallet_storage
|
||||||
|
.get_account_private(&recipient_account_id)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
u128::from_le_bytes(recipient_acc.data[33..].try_into().unwrap()),
|
||||||
|
21
|
||||||
|
);
|
||||||
|
|
||||||
|
// Now the same mint, but in foreign way
|
||||||
|
|
||||||
|
// Create new account for receiving a mint transaction
|
||||||
|
let SubcommandReturnValue::RegisterAccount {
|
||||||
|
account_id: recipient_account_id2,
|
||||||
|
} = wallet::cli::execute_subcommand(Command::Account(AccountSubcommand::New(
|
||||||
|
NewSubcommand::Private { cci: None },
|
||||||
|
)))
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
else {
|
||||||
|
panic!("invalid subcommand return value");
|
||||||
|
};
|
||||||
|
|
||||||
|
let wallet_config = fetch_config().await.unwrap();
|
||||||
|
let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let (holder_keys, _) = wallet_storage
|
||||||
|
.storage
|
||||||
|
.user_data
|
||||||
|
.get_private_account(&recipient_account_id2)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// Mint 9 tokens at `recipient_acc2`
|
||||||
|
let subcommand = TokenProgramAgnosticSubcommand::Mint {
|
||||||
|
definition: make_public_account_input_from_str(&definition_account_id.to_string()),
|
||||||
|
holder: None,
|
||||||
|
holder_npk: Some(hex::encode(holder_keys.nullifer_public_key.0)),
|
||||||
|
holder_ipk: Some(hex::encode(
|
||||||
|
holder_keys.incoming_viewing_public_key.0.clone(),
|
||||||
|
)),
|
||||||
|
amount: 9,
|
||||||
|
};
|
||||||
|
|
||||||
|
wallet::cli::execute_subcommand(Command::Token(subcommand))
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
info!("Waiting for next block creation");
|
||||||
|
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
|
||||||
|
|
||||||
|
// Sync to claim holder
|
||||||
|
let command = Command::Account(AccountSubcommand::SyncPrivate {});
|
||||||
|
|
||||||
|
wallet::cli::execute_subcommand(command).await.unwrap();
|
||||||
|
|
||||||
|
// Check the status of the token definition account is the expected after the execution
|
||||||
|
let definition_acc = seq_client
|
||||||
|
.get_account(definition_account_id.to_string())
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.account;
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
definition_acc.data.as_ref(),
|
||||||
|
&[
|
||||||
|
0, 65, 32, 78, 65, 77, 69, 53, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
let wallet_config = fetch_config().await.unwrap();
|
||||||
|
let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let new_commitment2 = wallet_storage
|
||||||
|
.get_private_account_commitment(&recipient_account_id2)
|
||||||
|
.unwrap();
|
||||||
|
assert!(verify_commitment_is_in_state(new_commitment2, &seq_client).await);
|
||||||
|
|
||||||
|
// Check the status of the account at `recipient_account_id2` is the expected after the
|
||||||
|
// execution
|
||||||
|
let recipient_acc = wallet_storage
|
||||||
|
.get_account_private(&recipient_account_id2)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
u128::from_le_bytes(recipient_acc.data[33..].try_into().unwrap()),
|
||||||
|
9
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This test creates a new private token using the token program. All accounts are private
|
/// This test creates a new private token using the token program. All accounts are private
|
||||||
@ -663,8 +945,8 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
|||||||
.account;
|
.account;
|
||||||
|
|
||||||
assert_eq!(supply_acc.program_owner, Program::token().id());
|
assert_eq!(supply_acc.program_owner, Program::token().id());
|
||||||
// The data of a token definition account has the following layout:
|
// The data of a token holding account has the following layout:
|
||||||
// [ 0x00 || name (6 bytes) || total supply (little endian 16 bytes) ]
|
// [ 0x01 || definition id (32 bytes) || balance (little endian 16 bytes) ]
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
supply_acc.data.as_ref(),
|
supply_acc.data.as_ref(),
|
||||||
&[
|
&[
|
||||||
@ -673,6 +955,287 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
|||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Create new account for receiving a mint transaction
|
||||||
|
let SubcommandReturnValue::RegisterAccount {
|
||||||
|
account_id: recipient_account_id_pr,
|
||||||
|
} = wallet::cli::execute_subcommand(Command::Account(AccountSubcommand::New(
|
||||||
|
NewSubcommand::Private { cci: None },
|
||||||
|
)))
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
else {
|
||||||
|
panic!("invalid subcommand return value");
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create new account for receiving a mint transaction
|
||||||
|
let SubcommandReturnValue::RegisterAccount {
|
||||||
|
account_id: recipient_account_id_pub,
|
||||||
|
} = wallet::cli::execute_subcommand(Command::Account(AccountSubcommand::New(
|
||||||
|
NewSubcommand::Public { cci: None },
|
||||||
|
)))
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
else {
|
||||||
|
panic!("invalid subcommand return value");
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mint 10 tokens at `recipient_acc_pub`
|
||||||
|
let subcommand = TokenProgramAgnosticSubcommand::Mint {
|
||||||
|
definition: make_private_account_input_from_str(&definition_account_id.to_string()),
|
||||||
|
holder: Some(make_public_account_input_from_str(
|
||||||
|
&recipient_account_id_pub.to_string(),
|
||||||
|
)),
|
||||||
|
holder_npk: None,
|
||||||
|
holder_ipk: None,
|
||||||
|
amount: 10,
|
||||||
|
};
|
||||||
|
|
||||||
|
wallet::cli::execute_subcommand(Command::Token(subcommand))
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
info!("Waiting for next block creation");
|
||||||
|
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
|
||||||
|
|
||||||
|
let wallet_config = fetch_config().await.unwrap();
|
||||||
|
let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// Check the status of the token definition account is the expected after the execution
|
||||||
|
let definition_acc = wallet_storage
|
||||||
|
.get_account_private(&definition_account_id)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
definition_acc.data.as_ref(),
|
||||||
|
&[
|
||||||
|
0, 65, 32, 78, 65, 77, 69, 47, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
// Check the status of the account at `recipient_account_id_pub` is the expected after the
|
||||||
|
// execution
|
||||||
|
let recipient_acc_pub = seq_client
|
||||||
|
.get_account(recipient_account_id_pub.to_string())
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.account;
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
u128::from_le_bytes(recipient_acc_pub.data[33..].try_into().unwrap()),
|
||||||
|
10
|
||||||
|
);
|
||||||
|
|
||||||
|
let (holder_keys, _) = wallet_storage
|
||||||
|
.storage
|
||||||
|
.user_data
|
||||||
|
.get_private_account(&recipient_account_id_pr)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// Mint 5 tokens at `recipient_acc_pr`
|
||||||
|
let subcommand = TokenProgramAgnosticSubcommand::Mint {
|
||||||
|
definition: make_private_account_input_from_str(&definition_account_id.to_string()),
|
||||||
|
holder: None,
|
||||||
|
holder_npk: Some(hex::encode(holder_keys.nullifer_public_key.0)),
|
||||||
|
holder_ipk: Some(hex::encode(
|
||||||
|
holder_keys.incoming_viewing_public_key.0.clone(),
|
||||||
|
)),
|
||||||
|
amount: 5,
|
||||||
|
};
|
||||||
|
|
||||||
|
wallet::cli::execute_subcommand(Command::Token(subcommand))
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
info!("Waiting for next block creation");
|
||||||
|
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
|
||||||
|
|
||||||
|
// Sync to claim holder
|
||||||
|
let command = Command::Account(AccountSubcommand::SyncPrivate {});
|
||||||
|
|
||||||
|
wallet::cli::execute_subcommand(command).await.unwrap();
|
||||||
|
|
||||||
|
let wallet_config = fetch_config().await.unwrap();
|
||||||
|
let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// Check the status of the token definition account is the expected after the execution
|
||||||
|
let definition_acc = wallet_storage
|
||||||
|
.get_account_private(&definition_account_id)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
definition_acc.data.as_ref(),
|
||||||
|
&[
|
||||||
|
0, 65, 32, 78, 65, 77, 69, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
let new_commitment2 = wallet_storage
|
||||||
|
.get_private_account_commitment(&recipient_account_id_pr)
|
||||||
|
.unwrap();
|
||||||
|
assert!(verify_commitment_is_in_state(new_commitment2, &seq_client).await);
|
||||||
|
|
||||||
|
// Check the status of the account at `recipient_account_id_pr` is the expected after the
|
||||||
|
// execution
|
||||||
|
let recipient_acc_pr = wallet_storage
|
||||||
|
.get_account_private(&recipient_account_id_pr)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
u128::from_le_bytes(recipient_acc_pr.data[33..].try_into().unwrap()),
|
||||||
|
5
|
||||||
|
);
|
||||||
|
|
||||||
|
// Mint 5 tokens at `recipient_acc_pr`
|
||||||
|
let subcommand = TokenProgramAgnosticSubcommand::Mint {
|
||||||
|
definition: make_private_account_input_from_str(&definition_account_id.to_string()),
|
||||||
|
holder: Some(make_private_account_input_from_str(
|
||||||
|
&recipient_account_id_pr.to_string(),
|
||||||
|
)),
|
||||||
|
holder_npk: None,
|
||||||
|
holder_ipk: None,
|
||||||
|
amount: 5,
|
||||||
|
};
|
||||||
|
|
||||||
|
wallet::cli::execute_subcommand(Command::Token(subcommand))
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
info!("Waiting for next block creation");
|
||||||
|
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
|
||||||
|
|
||||||
|
let wallet_config = fetch_config().await.unwrap();
|
||||||
|
let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// Check the status of the token definition account is the expected after the execution
|
||||||
|
let definition_acc = wallet_storage
|
||||||
|
.get_account_private(&definition_account_id)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
definition_acc.data.as_ref(),
|
||||||
|
&[
|
||||||
|
0, 65, 32, 78, 65, 77, 69, 57, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
let new_commitment2 = wallet_storage
|
||||||
|
.get_private_account_commitment(&recipient_account_id_pr)
|
||||||
|
.unwrap();
|
||||||
|
assert!(verify_commitment_is_in_state(new_commitment2, &seq_client).await);
|
||||||
|
|
||||||
|
// Check the status of the account at `recipient_account_id_pr` is the expected after the
|
||||||
|
// execution
|
||||||
|
let recipient_acc = wallet_storage
|
||||||
|
.get_account_private(&recipient_account_id_pr)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
u128::from_le_bytes(recipient_acc.data[33..].try_into().unwrap()),
|
||||||
|
10
|
||||||
|
);
|
||||||
|
|
||||||
|
// Burn 5 tokens at `recipient_acc_pub`
|
||||||
|
let subcommand = TokenProgramAgnosticSubcommand::Burn {
|
||||||
|
definition: make_private_account_input_from_str(&definition_account_id.to_string()),
|
||||||
|
holder: make_public_account_input_from_str(&recipient_account_id_pub.to_string()),
|
||||||
|
amount: 5,
|
||||||
|
};
|
||||||
|
|
||||||
|
wallet::cli::execute_subcommand(Command::Token(subcommand))
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
info!("Waiting for next block creation");
|
||||||
|
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
|
||||||
|
|
||||||
|
let wallet_config = fetch_config().await.unwrap();
|
||||||
|
let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// Check the status of the token definition account is the expected after the execution
|
||||||
|
let definition_acc = wallet_storage
|
||||||
|
.get_account_private(&definition_account_id)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
definition_acc.data.as_ref(),
|
||||||
|
&[
|
||||||
|
0, 65, 32, 78, 65, 77, 69, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
// Check the status of the account at `recipient_account_id_pub` is the expected after the
|
||||||
|
// execution
|
||||||
|
let recipient_acc_pub = seq_client
|
||||||
|
.get_account(recipient_account_id_pub.to_string())
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.account;
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
u128::from_le_bytes(recipient_acc_pub.data[33..].try_into().unwrap()),
|
||||||
|
5
|
||||||
|
);
|
||||||
|
|
||||||
|
// Burn 5 tokens at `recipient_acc_pr`
|
||||||
|
let subcommand = TokenProgramAgnosticSubcommand::Burn {
|
||||||
|
definition: make_private_account_input_from_str(&definition_account_id.to_string()),
|
||||||
|
holder: make_private_account_input_from_str(&recipient_account_id_pr.to_string()),
|
||||||
|
amount: 5,
|
||||||
|
};
|
||||||
|
|
||||||
|
wallet::cli::execute_subcommand(Command::Token(subcommand))
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
info!("Waiting for next block creation");
|
||||||
|
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
|
||||||
|
|
||||||
|
let wallet_config = fetch_config().await.unwrap();
|
||||||
|
let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// Check the status of the token definition account is the expected after the execution
|
||||||
|
let definition_acc = wallet_storage
|
||||||
|
.get_account_private(&definition_account_id)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
definition_acc.data.as_ref(),
|
||||||
|
&[
|
||||||
|
0, 65, 32, 78, 65, 77, 69, 47, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
let new_commitment2 = wallet_storage
|
||||||
|
.get_private_account_commitment(&recipient_account_id_pr)
|
||||||
|
.unwrap();
|
||||||
|
assert!(verify_commitment_is_in_state(new_commitment2, &seq_client).await);
|
||||||
|
|
||||||
|
// Check the status of the account at `recipient_account_id_pr` is the expected after the
|
||||||
|
// execution
|
||||||
|
let recipient_acc = wallet_storage
|
||||||
|
.get_account_private(&recipient_account_id_pr)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
u128::from_le_bytes(recipient_acc.data[33..].try_into().unwrap()),
|
||||||
|
5
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This test creates a new private token using the token program. All accounts are private
|
/// This test creates a new private token using the token program. All accounts are private
|
||||||
@ -754,17 +1317,20 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
|||||||
|
|
||||||
assert_eq!(definition_acc.program_owner, Program::token().id());
|
assert_eq!(definition_acc.program_owner, Program::token().id());
|
||||||
// The data of a token definition account has the following layout:
|
// The data of a token definition account has the following layout:
|
||||||
// [ 0x00 || name (6 bytes) || total supply (little endian 16 bytes) ]
|
// [ 0x00 || name (6 bytes) || total supply (little endian 16 bytes) || metadata id (32
|
||||||
|
// bytes)]
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
definition_acc.data.as_ref(),
|
definition_acc.data.as_ref(),
|
||||||
&[
|
&[
|
||||||
0, 65, 32, 78, 65, 77, 69, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
0, 65, 32, 78, 65, 77, 69, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(supply_acc.program_owner, Program::token().id());
|
assert_eq!(supply_acc.program_owner, Program::token().id());
|
||||||
// The data of a token definition account has the following layout:
|
// The data of a token holding account has the following layout:
|
||||||
// [ 0x00 || name (6 bytes) || total supply (little endian 16 bytes) ]
|
// [ 0x01 || definition id (32 bytes) || balance (little endian 16 bytes) ]
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
supply_acc.data.as_ref(),
|
supply_acc.data.as_ref(),
|
||||||
&[
|
&[
|
||||||
@ -844,11 +1410,14 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
|||||||
|
|
||||||
assert_eq!(definition_acc.program_owner, Program::token().id());
|
assert_eq!(definition_acc.program_owner, Program::token().id());
|
||||||
// The data of a token definition account has the following layout:
|
// The data of a token definition account has the following layout:
|
||||||
// [ 0x00 || name (6 bytes) || total supply (little endian 16 bytes) ]
|
// [ 0x00 || name (6 bytes) || total supply (little endian 16 bytes) || metadata id (32
|
||||||
|
// bytes)]
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
definition_acc.data.as_ref(),
|
definition_acc.data.as_ref(),
|
||||||
&[
|
&[
|
||||||
0, 65, 32, 78, 65, 77, 69, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
0, 65, 32, 78, 65, 77, 69, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -980,11 +1549,14 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
|||||||
|
|
||||||
assert_eq!(definition_acc.program_owner, Program::token().id());
|
assert_eq!(definition_acc.program_owner, Program::token().id());
|
||||||
// The data of a token definition account has the following layout:
|
// The data of a token definition account has the following layout:
|
||||||
// [ 0x00 || name (6 bytes) || total supply (little endian 16 bytes) ]
|
// [ 0x00 || name (6 bytes) || total supply (little endian 16 bytes) || metadata id (32
|
||||||
|
// bytes)]
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
definition_acc.data.as_ref(),
|
definition_acc.data.as_ref(),
|
||||||
&[
|
&[
|
||||||
0, 65, 32, 78, 65, 77, 69, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
0, 65, 32, 78, 65, 77, 69, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -1116,11 +1688,14 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
|||||||
|
|
||||||
assert_eq!(definition_acc.program_owner, Program::token().id());
|
assert_eq!(definition_acc.program_owner, Program::token().id());
|
||||||
// The data of a token definition account has the following layout:
|
// The data of a token definition account has the following layout:
|
||||||
// [ 0x00 || name (6 bytes) || total supply (little endian 16 bytes) ]
|
// [ 0x00 || name (6 bytes) || total supply (little endian 16 bytes) || metadata id (32
|
||||||
|
// bytes)]
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
definition_acc.data.as_ref(),
|
definition_acc.data.as_ref(),
|
||||||
&[
|
&[
|
||||||
0, 65, 32, 78, 65, 77, 69, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
0, 65, 32, 78, 65, 77, 69, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@ -25,6 +25,7 @@ risc0-binfmt = "3.0.2"
|
|||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
test_program_methods.workspace = true
|
test_program_methods.workspace = true
|
||||||
hex-literal = "1.0.0"
|
hex-literal = "1.0.0"
|
||||||
|
env_logger.workspace = true
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = []
|
default = []
|
||||||
|
|||||||
@ -6,14 +6,15 @@ edition = "2024"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
risc0-zkvm.workspace = true
|
risc0-zkvm.workspace = true
|
||||||
borsh.workspace = true
|
borsh.workspace = true
|
||||||
serde = { workspace = true }
|
serde.workspace = true
|
||||||
thiserror.workspace = true
|
thiserror.workspace = true
|
||||||
chacha20 = { version = "0.9", default-features = false }
|
bytemuck.workspace = true
|
||||||
bytemuck = { workspace = true }
|
|
||||||
k256 = { workspace = true, optional = true }
|
k256 = { workspace = true, optional = true }
|
||||||
base58 = { workspace = true, optional = true }
|
base58 = { workspace = true, optional = true }
|
||||||
anyhow = { workspace = true, optional = true }
|
anyhow = { workspace = true, optional = true }
|
||||||
|
|
||||||
|
chacha20 = { version = "0.9", default-features = false }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
serde_json.workspace = true
|
serde_json.workspace = true
|
||||||
|
|
||||||
|
|||||||
@ -15,7 +15,7 @@ pub type Nonce = u128;
|
|||||||
|
|
||||||
/// Account to be used both in public and private contexts
|
/// Account to be used both in public and private contexts
|
||||||
#[derive(
|
#[derive(
|
||||||
Serialize, Deserialize, Clone, Default, PartialEq, Eq, BorshSerialize, BorshDeserialize,
|
Clone, Default, Eq, PartialEq, Serialize, Deserialize, BorshSerialize, BorshDeserialize,
|
||||||
)]
|
)]
|
||||||
#[cfg_attr(any(feature = "host", test), derive(Debug))]
|
#[cfg_attr(any(feature = "host", test), derive(Debug))]
|
||||||
pub struct Account {
|
pub struct Account {
|
||||||
@ -25,7 +25,7 @@ pub struct Account {
|
|||||||
pub nonce: Nonce,
|
pub nonce: Nonce,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, PartialEq, Eq)]
|
#[derive(Clone, Eq, PartialEq, Serialize, Deserialize)]
|
||||||
#[cfg_attr(any(feature = "host", test), derive(Debug))]
|
#[cfg_attr(any(feature = "host", test), derive(Debug))]
|
||||||
pub struct AccountWithMetadata {
|
pub struct AccountWithMetadata {
|
||||||
pub account: Account,
|
pub account: Account,
|
||||||
@ -45,6 +45,7 @@ impl AccountWithMetadata {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(
|
#[derive(
|
||||||
|
Default,
|
||||||
Copy,
|
Copy,
|
||||||
Clone,
|
Clone,
|
||||||
Serialize,
|
Serialize,
|
||||||
@ -54,7 +55,6 @@ impl AccountWithMetadata {
|
|||||||
Hash,
|
Hash,
|
||||||
BorshSerialize,
|
BorshSerialize,
|
||||||
BorshDeserialize,
|
BorshDeserialize,
|
||||||
Default,
|
|
||||||
)]
|
)]
|
||||||
#[cfg_attr(any(feature = "host", test), derive(Debug, PartialOrd, Ord))]
|
#[cfg_attr(any(feature = "host", test), derive(Debug, PartialOrd, Ord))]
|
||||||
pub struct AccountId {
|
pub struct AccountId {
|
||||||
|
|||||||
@ -97,8 +97,6 @@ impl Program {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn amm() -> Self {
|
pub fn amm() -> Self {
|
||||||
// This unwrap wont panic since the `AMM_ELF` comes from risc0 build of
|
|
||||||
// `program_methods`
|
|
||||||
Self::new(AMM_ELF.to_vec()).expect("The AMM program must be a valid Risc0 program")
|
Self::new(AMM_ELF.to_vec()).expect("The AMM program must be a valid Risc0 program")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
1670
nssa/src/state.rs
1670
nssa/src/state.rs
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -82,7 +82,7 @@ fn main() {
|
|||||||
let winner_token_holding_post = winner_token_holding.account.clone();
|
let winner_token_holding_post = winner_token_holding.account.clone();
|
||||||
pinata_definition_post.data = data.next_data();
|
pinata_definition_post.data = data.next_data();
|
||||||
|
|
||||||
let mut instruction_data: [u8; 23] = [0; 23];
|
let mut instruction_data = vec![0; 23];
|
||||||
instruction_data[0] = 1;
|
instruction_data[0] = 1;
|
||||||
instruction_data[1..17].copy_from_slice(&PRIZE.to_le_bytes());
|
instruction_data[1..17].copy_from_slice(&PRIZE.to_le_bytes());
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -289,6 +289,8 @@ impl WalletSubcommand for AccountSubcommand {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use nssa::AccountId;
|
||||||
|
|
||||||
use crate::cli::account::{TokedDefinitionAccountView, TokenDefinition};
|
use crate::cli::account::{TokedDefinitionAccountView, TokenDefinition};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -297,6 +299,7 @@ mod tests {
|
|||||||
account_type: 1,
|
account_type: 1,
|
||||||
name: [137, 12, 14, 3, 5, 4],
|
name: [137, 12, 14, 3, 5, 4],
|
||||||
total_supply: 100,
|
total_supply: 100,
|
||||||
|
metadata_id: AccountId::new([0; 32]),
|
||||||
};
|
};
|
||||||
|
|
||||||
let token_def_view: TokedDefinitionAccountView = token_def.into();
|
let token_def_view: TokedDefinitionAccountView = token_def.into();
|
||||||
@ -310,6 +313,7 @@ mod tests {
|
|||||||
account_type: 1,
|
account_type: 1,
|
||||||
name: [240, 159, 146, 150, 66, 66],
|
name: [240, 159, 146, 150, 66, 66],
|
||||||
total_supply: 100,
|
total_supply: 100,
|
||||||
|
metadata_id: AccountId::new([0; 32]),
|
||||||
};
|
};
|
||||||
|
|
||||||
let token_def_view: TokedDefinitionAccountView = token_def.into();
|
let token_def_view: TokedDefinitionAccountView = token_def.into();
|
||||||
@ -323,6 +327,7 @@ mod tests {
|
|||||||
account_type: 1,
|
account_type: 1,
|
||||||
name: [78, 65, 77, 69, 0, 0],
|
name: [78, 65, 77, 69, 0, 0],
|
||||||
total_supply: 100,
|
total_supply: 100,
|
||||||
|
metadata_id: AccountId::new([0; 32]),
|
||||||
};
|
};
|
||||||
|
|
||||||
let token_def_view: TokedDefinitionAccountView = token_def.into();
|
let token_def_view: TokedDefinitionAccountView = token_def.into();
|
||||||
|
|||||||
@ -50,6 +50,48 @@ pub enum TokenProgramAgnosticSubcommand {
|
|||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
amount: u128,
|
amount: u128,
|
||||||
},
|
},
|
||||||
|
/// Burn tokens on `holder`, modify `definition`.
|
||||||
|
///
|
||||||
|
/// `holder` is owned
|
||||||
|
///
|
||||||
|
/// Also if `definition` is private then it is owned, because
|
||||||
|
/// we can not modify foreign accounts.
|
||||||
|
Burn {
|
||||||
|
/// definition - valid 32 byte base58 string with privacy prefix
|
||||||
|
#[arg(long)]
|
||||||
|
definition: String,
|
||||||
|
/// holder - valid 32 byte base58 string with privacy prefix
|
||||||
|
#[arg(long)]
|
||||||
|
holder: String,
|
||||||
|
/// amount - amount of balance to burn
|
||||||
|
#[arg(long)]
|
||||||
|
amount: u128,
|
||||||
|
},
|
||||||
|
/// Mint tokens on `holder`, modify `definition`.
|
||||||
|
///
|
||||||
|
/// `definition` is owned
|
||||||
|
///
|
||||||
|
/// If `holder` is private, then `holder` and (`holder_npk` , `holder_ipk`) is a mutually
|
||||||
|
/// exclusive patterns.
|
||||||
|
///
|
||||||
|
/// First is used for owned accounts, second otherwise.
|
||||||
|
Mint {
|
||||||
|
/// definition - valid 32 byte base58 string with privacy prefix
|
||||||
|
#[arg(long)]
|
||||||
|
definition: String,
|
||||||
|
/// holder - valid 32 byte base58 string with privacy prefix
|
||||||
|
#[arg(long)]
|
||||||
|
holder: Option<String>,
|
||||||
|
/// holder_npk - valid 32 byte hex string
|
||||||
|
#[arg(long)]
|
||||||
|
holder_npk: Option<String>,
|
||||||
|
/// to_ipk - valid 33 byte hex string
|
||||||
|
#[arg(long)]
|
||||||
|
holder_ipk: Option<String>,
|
||||||
|
/// amount - amount of balance to mint
|
||||||
|
#[arg(long)]
|
||||||
|
amount: u128,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WalletSubcommand for TokenProgramAgnosticSubcommand {
|
impl WalletSubcommand for TokenProgramAgnosticSubcommand {
|
||||||
@ -202,6 +244,150 @@ impl WalletSubcommand for TokenProgramAgnosticSubcommand {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
underlying_subcommand.handle_subcommand(wallet_core).await
|
||||||
|
}
|
||||||
|
TokenProgramAgnosticSubcommand::Burn {
|
||||||
|
definition,
|
||||||
|
holder,
|
||||||
|
amount,
|
||||||
|
} => {
|
||||||
|
let underlying_subcommand = {
|
||||||
|
let (definition, definition_privacy) =
|
||||||
|
parse_addr_with_privacy_prefix(&definition)?;
|
||||||
|
let (holder, holder_privacy) = parse_addr_with_privacy_prefix(&holder)?;
|
||||||
|
|
||||||
|
match (definition_privacy, holder_privacy) {
|
||||||
|
(AccountPrivacyKind::Public, AccountPrivacyKind::Public) => {
|
||||||
|
TokenProgramSubcommand::Public(
|
||||||
|
TokenProgramSubcommandPublic::BurnToken {
|
||||||
|
definition_account_id: definition,
|
||||||
|
holder_account_id: holder,
|
||||||
|
amount,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
(AccountPrivacyKind::Private, AccountPrivacyKind::Private) => {
|
||||||
|
TokenProgramSubcommand::Private(
|
||||||
|
TokenProgramSubcommandPrivate::BurnTokenPrivateOwned {
|
||||||
|
definition_account_id: definition,
|
||||||
|
holder_account_id: holder,
|
||||||
|
amount,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
(AccountPrivacyKind::Private, AccountPrivacyKind::Public) => {
|
||||||
|
TokenProgramSubcommand::Deshielded(
|
||||||
|
TokenProgramSubcommandDeshielded::BurnTokenDeshieldedOwned {
|
||||||
|
definition_account_id: definition,
|
||||||
|
holder_account_id: holder,
|
||||||
|
amount,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
(AccountPrivacyKind::Public, AccountPrivacyKind::Private) => {
|
||||||
|
TokenProgramSubcommand::Shielded(
|
||||||
|
TokenProgramSubcommandShielded::BurnTokenShielded {
|
||||||
|
definition_account_id: definition,
|
||||||
|
holder_account_id: holder,
|
||||||
|
amount,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
underlying_subcommand.handle_subcommand(wallet_core).await
|
||||||
|
}
|
||||||
|
TokenProgramAgnosticSubcommand::Mint {
|
||||||
|
definition,
|
||||||
|
holder,
|
||||||
|
holder_npk,
|
||||||
|
holder_ipk,
|
||||||
|
amount,
|
||||||
|
} => {
|
||||||
|
let underlying_subcommand = match (holder, holder_npk, holder_ipk) {
|
||||||
|
(None, None, None) => {
|
||||||
|
anyhow::bail!(
|
||||||
|
"Provide either account account_id of holder or their public keys"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
(Some(_), Some(_), Some(_)) => {
|
||||||
|
anyhow::bail!(
|
||||||
|
"Provide only one variant: either account_id of holder or their public keys"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
(_, Some(_), None) | (_, None, Some(_)) => {
|
||||||
|
anyhow::bail!("List of public keys is uncomplete");
|
||||||
|
}
|
||||||
|
(Some(holder), None, None) => {
|
||||||
|
let (definition, definition_privacy) =
|
||||||
|
parse_addr_with_privacy_prefix(&definition)?;
|
||||||
|
let (holder, holder_privacy) = parse_addr_with_privacy_prefix(&holder)?;
|
||||||
|
|
||||||
|
match (definition_privacy, holder_privacy) {
|
||||||
|
(AccountPrivacyKind::Public, AccountPrivacyKind::Public) => {
|
||||||
|
TokenProgramSubcommand::Public(
|
||||||
|
TokenProgramSubcommandPublic::MintToken {
|
||||||
|
definition_account_id: definition,
|
||||||
|
holder_account_id: holder,
|
||||||
|
amount,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
(AccountPrivacyKind::Private, AccountPrivacyKind::Private) => {
|
||||||
|
TokenProgramSubcommand::Private(
|
||||||
|
TokenProgramSubcommandPrivate::MintTokenPrivateOwned {
|
||||||
|
definition_account_id: definition,
|
||||||
|
holder_account_id: holder,
|
||||||
|
amount,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
(AccountPrivacyKind::Private, AccountPrivacyKind::Public) => {
|
||||||
|
TokenProgramSubcommand::Deshielded(
|
||||||
|
TokenProgramSubcommandDeshielded::MintTokenDeshielded {
|
||||||
|
definition_account_id: definition,
|
||||||
|
holder_account_id: holder,
|
||||||
|
amount,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
(AccountPrivacyKind::Public, AccountPrivacyKind::Private) => {
|
||||||
|
TokenProgramSubcommand::Shielded(
|
||||||
|
TokenProgramSubcommandShielded::MintTokenShieldedOwned {
|
||||||
|
definition_account_id: definition,
|
||||||
|
holder_account_id: holder,
|
||||||
|
amount,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(None, Some(holder_npk), Some(holder_ipk)) => {
|
||||||
|
let (definition, definition_privacy) =
|
||||||
|
parse_addr_with_privacy_prefix(&definition)?;
|
||||||
|
|
||||||
|
match definition_privacy {
|
||||||
|
AccountPrivacyKind::Private => TokenProgramSubcommand::Private(
|
||||||
|
TokenProgramSubcommandPrivate::MintTokenPrivateForeign {
|
||||||
|
definition_account_id: definition,
|
||||||
|
holder_npk,
|
||||||
|
holder_ipk,
|
||||||
|
amount,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
AccountPrivacyKind::Public => TokenProgramSubcommand::Shielded(
|
||||||
|
TokenProgramSubcommandShielded::MintTokenShieldedForeign {
|
||||||
|
definition_account_id: definition,
|
||||||
|
holder_npk,
|
||||||
|
holder_ipk,
|
||||||
|
amount,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
underlying_subcommand.handle_subcommand(wallet_core).await
|
underlying_subcommand.handle_subcommand(wallet_core).await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -240,6 +426,24 @@ pub enum TokenProgramSubcommandPublic {
|
|||||||
#[arg(short, long)]
|
#[arg(short, long)]
|
||||||
balance_to_move: u128,
|
balance_to_move: u128,
|
||||||
},
|
},
|
||||||
|
// Burn tokens using the token program
|
||||||
|
BurnToken {
|
||||||
|
#[arg(short, long)]
|
||||||
|
definition_account_id: String,
|
||||||
|
#[arg(short, long)]
|
||||||
|
holder_account_id: String,
|
||||||
|
#[arg(short, long)]
|
||||||
|
amount: u128,
|
||||||
|
},
|
||||||
|
// Transfer tokens using the token program
|
||||||
|
MintToken {
|
||||||
|
#[arg(short, long)]
|
||||||
|
definition_account_id: String,
|
||||||
|
#[arg(short, long)]
|
||||||
|
holder_account_id: String,
|
||||||
|
#[arg(short, long)]
|
||||||
|
amount: u128,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represents generic private CLI subcommand for a wallet working with token_program
|
/// Represents generic private CLI subcommand for a wallet working with token_program
|
||||||
@ -267,6 +471,35 @@ pub enum TokenProgramSubcommandPrivate {
|
|||||||
#[arg(short, long)]
|
#[arg(short, long)]
|
||||||
balance_to_move: u128,
|
balance_to_move: u128,
|
||||||
},
|
},
|
||||||
|
// Burn tokens using the token program
|
||||||
|
BurnTokenPrivateOwned {
|
||||||
|
#[arg(short, long)]
|
||||||
|
definition_account_id: String,
|
||||||
|
#[arg(short, long)]
|
||||||
|
holder_account_id: String,
|
||||||
|
#[arg(short, long)]
|
||||||
|
amount: u128,
|
||||||
|
},
|
||||||
|
// Transfer tokens using the token program
|
||||||
|
MintTokenPrivateOwned {
|
||||||
|
#[arg(short, long)]
|
||||||
|
definition_account_id: String,
|
||||||
|
#[arg(short, long)]
|
||||||
|
holder_account_id: String,
|
||||||
|
#[arg(short, long)]
|
||||||
|
amount: u128,
|
||||||
|
},
|
||||||
|
// Transfer tokens using the token program
|
||||||
|
MintTokenPrivateForeign {
|
||||||
|
#[arg(short, long)]
|
||||||
|
definition_account_id: String,
|
||||||
|
#[arg(short, long)]
|
||||||
|
holder_npk: String,
|
||||||
|
#[arg(short, long)]
|
||||||
|
holder_ipk: String,
|
||||||
|
#[arg(short, long)]
|
||||||
|
amount: u128,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represents deshielded public CLI subcommand for a wallet working with token_program
|
/// Represents deshielded public CLI subcommand for a wallet working with token_program
|
||||||
@ -281,6 +514,24 @@ pub enum TokenProgramSubcommandDeshielded {
|
|||||||
#[arg(short, long)]
|
#[arg(short, long)]
|
||||||
balance_to_move: u128,
|
balance_to_move: u128,
|
||||||
},
|
},
|
||||||
|
// Burn tokens using the token program
|
||||||
|
BurnTokenDeshieldedOwned {
|
||||||
|
#[arg(short, long)]
|
||||||
|
definition_account_id: String,
|
||||||
|
#[arg(short, long)]
|
||||||
|
holder_account_id: String,
|
||||||
|
#[arg(short, long)]
|
||||||
|
amount: u128,
|
||||||
|
},
|
||||||
|
// Transfer tokens using the token program
|
||||||
|
MintTokenDeshielded {
|
||||||
|
#[arg(short, long)]
|
||||||
|
definition_account_id: String,
|
||||||
|
#[arg(short, long)]
|
||||||
|
holder_account_id: String,
|
||||||
|
#[arg(short, long)]
|
||||||
|
amount: u128,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represents generic shielded CLI subcommand for a wallet working with token_program
|
/// Represents generic shielded CLI subcommand for a wallet working with token_program
|
||||||
@ -308,6 +559,35 @@ pub enum TokenProgramSubcommandShielded {
|
|||||||
#[arg(short, long)]
|
#[arg(short, long)]
|
||||||
balance_to_move: u128,
|
balance_to_move: u128,
|
||||||
},
|
},
|
||||||
|
// Burn tokens using the token program
|
||||||
|
BurnTokenShielded {
|
||||||
|
#[arg(short, long)]
|
||||||
|
definition_account_id: String,
|
||||||
|
#[arg(short, long)]
|
||||||
|
holder_account_id: String,
|
||||||
|
#[arg(short, long)]
|
||||||
|
amount: u128,
|
||||||
|
},
|
||||||
|
// Transfer tokens using the token program
|
||||||
|
MintTokenShieldedOwned {
|
||||||
|
#[arg(short, long)]
|
||||||
|
definition_account_id: String,
|
||||||
|
#[arg(short, long)]
|
||||||
|
holder_account_id: String,
|
||||||
|
#[arg(short, long)]
|
||||||
|
amount: u128,
|
||||||
|
},
|
||||||
|
// Transfer tokens using the token program
|
||||||
|
MintTokenShieldedForeign {
|
||||||
|
#[arg(short, long)]
|
||||||
|
definition_account_id: String,
|
||||||
|
#[arg(short, long)]
|
||||||
|
holder_npk: String,
|
||||||
|
#[arg(short, long)]
|
||||||
|
holder_ipk: String,
|
||||||
|
#[arg(short, long)]
|
||||||
|
amount: u128,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represents generic initialization subcommand for a wallet working with token_program
|
/// Represents generic initialization subcommand for a wallet working with token_program
|
||||||
@ -387,6 +667,34 @@ impl WalletSubcommand for TokenProgramSubcommandPublic {
|
|||||||
.await?;
|
.await?;
|
||||||
Ok(SubcommandReturnValue::Empty)
|
Ok(SubcommandReturnValue::Empty)
|
||||||
}
|
}
|
||||||
|
TokenProgramSubcommandPublic::BurnToken {
|
||||||
|
definition_account_id,
|
||||||
|
holder_account_id,
|
||||||
|
amount,
|
||||||
|
} => {
|
||||||
|
Token(wallet_core)
|
||||||
|
.send_burn_transaction(
|
||||||
|
definition_account_id.parse().unwrap(),
|
||||||
|
holder_account_id.parse().unwrap(),
|
||||||
|
amount,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
Ok(SubcommandReturnValue::Empty)
|
||||||
|
}
|
||||||
|
TokenProgramSubcommandPublic::MintToken {
|
||||||
|
definition_account_id,
|
||||||
|
holder_account_id,
|
||||||
|
amount,
|
||||||
|
} => {
|
||||||
|
Token(wallet_core)
|
||||||
|
.send_mint_transaction(
|
||||||
|
definition_account_id.parse().unwrap(),
|
||||||
|
holder_account_id.parse().unwrap(),
|
||||||
|
amount,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
Ok(SubcommandReturnValue::Empty)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -486,6 +794,139 @@ impl WalletSubcommand for TokenProgramSubcommandPrivate {
|
|||||||
|
|
||||||
println!("Stored persistent accounts at {path:#?}");
|
println!("Stored persistent accounts at {path:#?}");
|
||||||
|
|
||||||
|
Ok(SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash })
|
||||||
|
}
|
||||||
|
TokenProgramSubcommandPrivate::BurnTokenPrivateOwned {
|
||||||
|
definition_account_id,
|
||||||
|
holder_account_id,
|
||||||
|
amount,
|
||||||
|
} => {
|
||||||
|
let definition_account_id: AccountId = definition_account_id.parse().unwrap();
|
||||||
|
let holder_account_id: AccountId = holder_account_id.parse().unwrap();
|
||||||
|
|
||||||
|
let (res, [secret_definition, secret_holder]) = Token(wallet_core)
|
||||||
|
.send_burn_transaction_private_owned_account(
|
||||||
|
definition_account_id,
|
||||||
|
holder_account_id,
|
||||||
|
amount,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
println!("Results of tx send are {res:#?}");
|
||||||
|
|
||||||
|
let tx_hash = res.tx_hash;
|
||||||
|
let transfer_tx = wallet_core
|
||||||
|
.poll_native_token_transfer(tx_hash.clone())
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx {
|
||||||
|
let acc_decode_data = vec![
|
||||||
|
Decode(secret_definition, definition_account_id),
|
||||||
|
Decode(secret_holder, holder_account_id),
|
||||||
|
];
|
||||||
|
|
||||||
|
wallet_core.decode_insert_privacy_preserving_transaction_results(
|
||||||
|
tx,
|
||||||
|
&acc_decode_data,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let path = wallet_core.store_persistent_data().await?;
|
||||||
|
|
||||||
|
println!("Stored persistent accounts at {path:#?}");
|
||||||
|
|
||||||
|
Ok(SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash })
|
||||||
|
}
|
||||||
|
TokenProgramSubcommandPrivate::MintTokenPrivateOwned {
|
||||||
|
definition_account_id,
|
||||||
|
holder_account_id,
|
||||||
|
amount,
|
||||||
|
} => {
|
||||||
|
let definition_account_id: AccountId = definition_account_id.parse().unwrap();
|
||||||
|
let holder_account_id: AccountId = holder_account_id.parse().unwrap();
|
||||||
|
|
||||||
|
let (res, [secret_definition, secret_holder]) = Token(wallet_core)
|
||||||
|
.send_mint_transaction_private_owned_account(
|
||||||
|
definition_account_id,
|
||||||
|
holder_account_id,
|
||||||
|
amount,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
println!("Results of tx send are {res:#?}");
|
||||||
|
|
||||||
|
let tx_hash = res.tx_hash;
|
||||||
|
let transfer_tx = wallet_core
|
||||||
|
.poll_native_token_transfer(tx_hash.clone())
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx {
|
||||||
|
let acc_decode_data = vec![
|
||||||
|
Decode(secret_definition, definition_account_id),
|
||||||
|
Decode(secret_holder, holder_account_id),
|
||||||
|
];
|
||||||
|
|
||||||
|
wallet_core.decode_insert_privacy_preserving_transaction_results(
|
||||||
|
tx,
|
||||||
|
&acc_decode_data,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let path = wallet_core.store_persistent_data().await?;
|
||||||
|
|
||||||
|
println!("Stored persistent accounts at {path:#?}");
|
||||||
|
|
||||||
|
Ok(SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash })
|
||||||
|
}
|
||||||
|
TokenProgramSubcommandPrivate::MintTokenPrivateForeign {
|
||||||
|
definition_account_id,
|
||||||
|
holder_npk,
|
||||||
|
holder_ipk,
|
||||||
|
amount,
|
||||||
|
} => {
|
||||||
|
let definition_account_id: AccountId = definition_account_id.parse().unwrap();
|
||||||
|
|
||||||
|
let holder_npk_res = hex::decode(holder_npk)?;
|
||||||
|
let mut holder_npk = [0; 32];
|
||||||
|
holder_npk.copy_from_slice(&holder_npk_res);
|
||||||
|
let holder_npk = nssa_core::NullifierPublicKey(holder_npk);
|
||||||
|
|
||||||
|
let holder_ipk_res = hex::decode(holder_ipk)?;
|
||||||
|
let mut holder_ipk = [0u8; 33];
|
||||||
|
holder_ipk.copy_from_slice(&holder_ipk_res);
|
||||||
|
let holder_ipk = nssa_core::encryption::shared_key_derivation::Secp256k1Point(
|
||||||
|
holder_ipk.to_vec(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let (res, [secret_definition, _]) = Token(wallet_core)
|
||||||
|
.send_mint_transaction_private_foreign_account(
|
||||||
|
definition_account_id,
|
||||||
|
holder_npk,
|
||||||
|
holder_ipk,
|
||||||
|
amount,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
println!("Results of tx send are {res:#?}");
|
||||||
|
|
||||||
|
let tx_hash = res.tx_hash;
|
||||||
|
let transfer_tx = wallet_core
|
||||||
|
.poll_native_token_transfer(tx_hash.clone())
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx {
|
||||||
|
let acc_decode_data = vec![Decode(secret_definition, definition_account_id)];
|
||||||
|
|
||||||
|
wallet_core.decode_insert_privacy_preserving_transaction_results(
|
||||||
|
tx,
|
||||||
|
&acc_decode_data,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let path = wallet_core.store_persistent_data().await?;
|
||||||
|
|
||||||
|
println!("Stored persistent accounts at {path:#?}");
|
||||||
|
|
||||||
Ok(SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash })
|
Ok(SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -534,6 +975,82 @@ impl WalletSubcommand for TokenProgramSubcommandDeshielded {
|
|||||||
|
|
||||||
println!("Stored persistent accounts at {path:#?}");
|
println!("Stored persistent accounts at {path:#?}");
|
||||||
|
|
||||||
|
Ok(SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash })
|
||||||
|
}
|
||||||
|
TokenProgramSubcommandDeshielded::BurnTokenDeshieldedOwned {
|
||||||
|
definition_account_id,
|
||||||
|
holder_account_id,
|
||||||
|
amount,
|
||||||
|
} => {
|
||||||
|
let definition_account_id: AccountId = definition_account_id.parse().unwrap();
|
||||||
|
let holder_account_id: AccountId = holder_account_id.parse().unwrap();
|
||||||
|
|
||||||
|
let (res, secret_definition) = Token(wallet_core)
|
||||||
|
.send_burn_transaction_deshielded_owned_account(
|
||||||
|
definition_account_id,
|
||||||
|
holder_account_id,
|
||||||
|
amount,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
println!("Results of tx send are {res:#?}");
|
||||||
|
|
||||||
|
let tx_hash = res.tx_hash;
|
||||||
|
let transfer_tx = wallet_core
|
||||||
|
.poll_native_token_transfer(tx_hash.clone())
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx {
|
||||||
|
let acc_decode_data = vec![Decode(secret_definition, definition_account_id)];
|
||||||
|
|
||||||
|
wallet_core.decode_insert_privacy_preserving_transaction_results(
|
||||||
|
tx,
|
||||||
|
&acc_decode_data,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let path = wallet_core.store_persistent_data().await?;
|
||||||
|
|
||||||
|
println!("Stored persistent accounts at {path:#?}");
|
||||||
|
|
||||||
|
Ok(SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash })
|
||||||
|
}
|
||||||
|
TokenProgramSubcommandDeshielded::MintTokenDeshielded {
|
||||||
|
definition_account_id,
|
||||||
|
holder_account_id,
|
||||||
|
amount,
|
||||||
|
} => {
|
||||||
|
let definition_account_id: AccountId = definition_account_id.parse().unwrap();
|
||||||
|
let holder_account_id: AccountId = holder_account_id.parse().unwrap();
|
||||||
|
|
||||||
|
let (res, secret_definition) = Token(wallet_core)
|
||||||
|
.send_mint_transaction_deshielded(
|
||||||
|
definition_account_id,
|
||||||
|
holder_account_id,
|
||||||
|
amount,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
println!("Results of tx send are {res:#?}");
|
||||||
|
|
||||||
|
let tx_hash = res.tx_hash;
|
||||||
|
let transfer_tx = wallet_core
|
||||||
|
.poll_native_token_transfer(tx_hash.clone())
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx {
|
||||||
|
let acc_decode_data = vec![Decode(secret_definition, definition_account_id)];
|
||||||
|
|
||||||
|
wallet_core.decode_insert_privacy_preserving_transaction_results(
|
||||||
|
tx,
|
||||||
|
&acc_decode_data,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let path = wallet_core.store_persistent_data().await?;
|
||||||
|
|
||||||
|
println!("Stored persistent accounts at {path:#?}");
|
||||||
|
|
||||||
Ok(SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash })
|
Ok(SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -627,6 +1144,128 @@ impl WalletSubcommand for TokenProgramSubcommandShielded {
|
|||||||
|
|
||||||
println!("Stored persistent accounts at {path:#?}");
|
println!("Stored persistent accounts at {path:#?}");
|
||||||
|
|
||||||
|
Ok(SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash })
|
||||||
|
}
|
||||||
|
TokenProgramSubcommandShielded::BurnTokenShielded {
|
||||||
|
definition_account_id,
|
||||||
|
holder_account_id,
|
||||||
|
amount,
|
||||||
|
} => {
|
||||||
|
let definition_account_id: AccountId = definition_account_id.parse().unwrap();
|
||||||
|
let holder_account_id: AccountId = holder_account_id.parse().unwrap();
|
||||||
|
|
||||||
|
let (res, secret_holder) = Token(wallet_core)
|
||||||
|
.send_burn_transaction_shielded(
|
||||||
|
definition_account_id,
|
||||||
|
holder_account_id,
|
||||||
|
amount,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
println!("Results of tx send are {res:#?}");
|
||||||
|
|
||||||
|
let tx_hash = res.tx_hash;
|
||||||
|
let transfer_tx = wallet_core
|
||||||
|
.poll_native_token_transfer(tx_hash.clone())
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx {
|
||||||
|
let acc_decode_data = vec![Decode(secret_holder, holder_account_id)];
|
||||||
|
|
||||||
|
wallet_core.decode_insert_privacy_preserving_transaction_results(
|
||||||
|
tx,
|
||||||
|
&acc_decode_data,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let path = wallet_core.store_persistent_data().await?;
|
||||||
|
|
||||||
|
println!("Stored persistent accounts at {path:#?}");
|
||||||
|
|
||||||
|
Ok(SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash })
|
||||||
|
}
|
||||||
|
TokenProgramSubcommandShielded::MintTokenShieldedOwned {
|
||||||
|
definition_account_id,
|
||||||
|
holder_account_id,
|
||||||
|
amount,
|
||||||
|
} => {
|
||||||
|
let definition_account_id: AccountId = definition_account_id.parse().unwrap();
|
||||||
|
let holder_account_id: AccountId = holder_account_id.parse().unwrap();
|
||||||
|
|
||||||
|
let (res, secret_holder) = Token(wallet_core)
|
||||||
|
.send_mint_transaction_shielded_owned_account(
|
||||||
|
definition_account_id,
|
||||||
|
holder_account_id,
|
||||||
|
amount,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
println!("Results of tx send are {res:#?}");
|
||||||
|
|
||||||
|
let tx_hash = res.tx_hash;
|
||||||
|
let transfer_tx = wallet_core
|
||||||
|
.poll_native_token_transfer(tx_hash.clone())
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx {
|
||||||
|
let acc_decode_data = vec![Decode(secret_holder, holder_account_id)];
|
||||||
|
|
||||||
|
wallet_core.decode_insert_privacy_preserving_transaction_results(
|
||||||
|
tx,
|
||||||
|
&acc_decode_data,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let path = wallet_core.store_persistent_data().await?;
|
||||||
|
|
||||||
|
println!("Stored persistent accounts at {path:#?}");
|
||||||
|
|
||||||
|
Ok(SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash })
|
||||||
|
}
|
||||||
|
TokenProgramSubcommandShielded::MintTokenShieldedForeign {
|
||||||
|
definition_account_id,
|
||||||
|
holder_npk,
|
||||||
|
holder_ipk,
|
||||||
|
amount,
|
||||||
|
} => {
|
||||||
|
let definition_account_id: AccountId = definition_account_id.parse().unwrap();
|
||||||
|
|
||||||
|
let holder_npk_res = hex::decode(holder_npk)?;
|
||||||
|
let mut holder_npk = [0; 32];
|
||||||
|
holder_npk.copy_from_slice(&holder_npk_res);
|
||||||
|
let holder_npk = nssa_core::NullifierPublicKey(holder_npk);
|
||||||
|
|
||||||
|
let holder_ipk_res = hex::decode(holder_ipk)?;
|
||||||
|
let mut holder_ipk = [0u8; 33];
|
||||||
|
holder_ipk.copy_from_slice(&holder_ipk_res);
|
||||||
|
let holder_ipk = nssa_core::encryption::shared_key_derivation::Secp256k1Point(
|
||||||
|
holder_ipk.to_vec(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let (res, _) = Token(wallet_core)
|
||||||
|
.send_mint_transaction_shielded_foreign_account(
|
||||||
|
definition_account_id,
|
||||||
|
holder_npk,
|
||||||
|
holder_ipk,
|
||||||
|
amount,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
println!("Results of tx send are {res:#?}");
|
||||||
|
|
||||||
|
let tx_hash = res.tx_hash;
|
||||||
|
let transfer_tx = wallet_core
|
||||||
|
.poll_native_token_transfer(tx_hash.clone())
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx {
|
||||||
|
println!("Transaction data is {:?}", tx.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
let path = wallet_core.store_persistent_data().await?;
|
||||||
|
|
||||||
|
println!("Stored persistent accounts at {path:#?}");
|
||||||
|
|
||||||
Ok(SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash })
|
Ok(SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,7 +18,9 @@ use nssa::{
|
|||||||
circuit::ProgramWithDependencies, message::EncryptedAccountData,
|
circuit::ProgramWithDependencies, message::EncryptedAccountData,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use nssa_core::{Commitment, MembershipProof, SharedSecretKey, program::InstructionData};
|
use nssa_core::{
|
||||||
|
Commitment, MembershipProof, SharedSecretKey, account::Data, program::InstructionData,
|
||||||
|
};
|
||||||
pub use privacy_preserving_tx::PrivacyPreservingAccount;
|
pub use privacy_preserving_tx::PrivacyPreservingAccount;
|
||||||
use tokio::io::AsyncWriteExt;
|
use tokio::io::AsyncWriteExt;
|
||||||
|
|
||||||
@ -45,45 +47,67 @@ pub enum AccDecodeData {
|
|||||||
Decode(nssa_core::SharedSecretKey, AccountId),
|
Decode(nssa_core::SharedSecretKey, AccountId),
|
||||||
}
|
}
|
||||||
|
|
||||||
const TOKEN_DEFINITION_TYPE: u8 = 0;
|
const TOKEN_DEFINITION_DATA_SIZE: usize = 55;
|
||||||
const TOKEN_DEFINITION_DATA_SIZE: usize = 23;
|
|
||||||
|
|
||||||
const TOKEN_HOLDING_TYPE: u8 = 1;
|
const TOKEN_HOLDING_TYPE: u8 = 1;
|
||||||
const TOKEN_HOLDING_DATA_SIZE: usize = 49;
|
const TOKEN_HOLDING_DATA_SIZE: usize = 49;
|
||||||
|
const TOKEN_STANDARD_FUNGIBLE_TOKEN: u8 = 0;
|
||||||
|
const TOKEN_STANDARD_NONFUNGIBLE: u8 = 2;
|
||||||
|
|
||||||
struct TokenDefinition {
|
struct TokenDefinition {
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
account_type: u8,
|
account_type: u8,
|
||||||
name: [u8; 6],
|
name: [u8; 6],
|
||||||
total_supply: u128,
|
total_supply: u128,
|
||||||
|
#[allow(unused)]
|
||||||
|
metadata_id: AccountId,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct TokenHolding {
|
struct TokenHolding {
|
||||||
pub account_type: u8,
|
#[allow(unused)]
|
||||||
pub definition_id: AccountId,
|
account_type: u8,
|
||||||
pub balance: u128,
|
definition_id: AccountId,
|
||||||
|
balance: u128,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TokenDefinition {
|
impl TokenDefinition {
|
||||||
fn parse(data: &[u8]) -> Option<Self> {
|
fn parse(data: &Data) -> Option<Self> {
|
||||||
if data.len() != TOKEN_DEFINITION_DATA_SIZE || data[0] != TOKEN_DEFINITION_TYPE {
|
let data = Vec::<u8>::from(data.clone());
|
||||||
|
|
||||||
|
if data.len() != TOKEN_DEFINITION_DATA_SIZE {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
let account_type = data[0];
|
let account_type = data[0];
|
||||||
let name = data[1..7].try_into().unwrap();
|
let name = data[1..7].try_into().expect("Name must be a 6 bytes");
|
||||||
let total_supply = u128::from_le_bytes(data[7..].try_into().unwrap());
|
let total_supply = u128::from_le_bytes(
|
||||||
|
data[7..23]
|
||||||
|
.try_into()
|
||||||
|
.expect("Total supply must be 16 bytes little-endian"),
|
||||||
|
);
|
||||||
|
let metadata_id = AccountId::new(
|
||||||
|
data[23..TOKEN_DEFINITION_DATA_SIZE]
|
||||||
|
.try_into()
|
||||||
|
.expect("Token Program expects valid Account Id for Metadata"),
|
||||||
|
);
|
||||||
|
|
||||||
Some(Self {
|
let this = Some(Self {
|
||||||
account_type,
|
account_type,
|
||||||
name,
|
name,
|
||||||
total_supply,
|
total_supply,
|
||||||
})
|
metadata_id,
|
||||||
|
});
|
||||||
|
|
||||||
|
match account_type {
|
||||||
|
TOKEN_STANDARD_NONFUNGIBLE if total_supply != 1 => None,
|
||||||
|
TOKEN_STANDARD_FUNGIBLE_TOKEN if metadata_id != AccountId::new([0; 32]) => None,
|
||||||
|
_ => this,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TokenHolding {
|
impl TokenHolding {
|
||||||
pub fn parse(data: &[u8]) -> Option<Self> {
|
fn parse(data: &[u8]) -> Option<Self> {
|
||||||
if data.len() != TOKEN_HOLDING_DATA_SIZE || data[0] != TOKEN_HOLDING_TYPE {
|
if data.len() != TOKEN_HOLDING_DATA_SIZE || data[0] != TOKEN_HOLDING_TYPE {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -1,9 +1,6 @@
|
|||||||
use common::{error::ExecutionFailureKind, rpc_primitives::requests::SendTxResponse};
|
use common::{error::ExecutionFailureKind, rpc_primitives::requests::SendTxResponse};
|
||||||
use nssa::{AccountId, program::Program};
|
use nssa::{AccountId, program::Program};
|
||||||
use nssa_core::{
|
use nssa_core::{NullifierPublicKey, SharedSecretKey, encryption::IncomingViewingPublicKey};
|
||||||
NullifierPublicKey, SharedSecretKey, encryption::IncomingViewingPublicKey,
|
|
||||||
program::InstructionData,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::{PrivacyPreservingAccount, WalletCore};
|
use crate::{PrivacyPreservingAccount, WalletCore};
|
||||||
|
|
||||||
@ -20,7 +17,7 @@ impl Token<'_> {
|
|||||||
let account_ids = vec![definition_account_id, supply_account_id];
|
let account_ids = vec![definition_account_id, supply_account_id];
|
||||||
let program_id = nssa::program::Program::token().id();
|
let program_id = nssa::program::Program::token().id();
|
||||||
// Instruction must be: [0x00 || total_supply (little-endian 16 bytes) || name (6 bytes)]
|
// Instruction must be: [0x00 || total_supply (little-endian 16 bytes) || name (6 bytes)]
|
||||||
let mut instruction = [0; 23];
|
let mut instruction = vec![0u8; 23];
|
||||||
instruction[1..17].copy_from_slice(&total_supply.to_le_bytes());
|
instruction[1..17].copy_from_slice(&total_supply.to_le_bytes());
|
||||||
instruction[17..].copy_from_slice(&name);
|
instruction[17..].copy_from_slice(&name);
|
||||||
let message = nssa::public_transaction::Message::try_new(
|
let message = nssa::public_transaction::Message::try_new(
|
||||||
@ -45,7 +42,9 @@ impl Token<'_> {
|
|||||||
name: [u8; 6],
|
name: [u8; 6],
|
||||||
total_supply: u128,
|
total_supply: u128,
|
||||||
) -> Result<(SendTxResponse, SharedSecretKey), ExecutionFailureKind> {
|
) -> Result<(SendTxResponse, SharedSecretKey), ExecutionFailureKind> {
|
||||||
let (instruction_data, program) = token_program_preparation_definition(name, total_supply);
|
let instruction = token_program_preparation_definition(name, total_supply);
|
||||||
|
let instruction_data =
|
||||||
|
Program::serialize_instruction(instruction).expect("Instruction should serialize");
|
||||||
|
|
||||||
self.0
|
self.0
|
||||||
.send_privacy_preserving_tx(
|
.send_privacy_preserving_tx(
|
||||||
@ -54,7 +53,7 @@ impl Token<'_> {
|
|||||||
PrivacyPreservingAccount::PrivateOwned(supply_account_id),
|
PrivacyPreservingAccount::PrivateOwned(supply_account_id),
|
||||||
],
|
],
|
||||||
&instruction_data,
|
&instruction_data,
|
||||||
&program.into(),
|
&Program::token().into(),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.map(|(resp, secrets)| {
|
.map(|(resp, secrets)| {
|
||||||
@ -73,7 +72,9 @@ impl Token<'_> {
|
|||||||
name: [u8; 6],
|
name: [u8; 6],
|
||||||
total_supply: u128,
|
total_supply: u128,
|
||||||
) -> Result<(SendTxResponse, SharedSecretKey), ExecutionFailureKind> {
|
) -> Result<(SendTxResponse, SharedSecretKey), ExecutionFailureKind> {
|
||||||
let (instruction_data, program) = token_program_preparation_definition(name, total_supply);
|
let instruction = token_program_preparation_definition(name, total_supply);
|
||||||
|
let instruction_data =
|
||||||
|
Program::serialize_instruction(instruction).expect("Instruction should serialize");
|
||||||
|
|
||||||
self.0
|
self.0
|
||||||
.send_privacy_preserving_tx(
|
.send_privacy_preserving_tx(
|
||||||
@ -82,7 +83,7 @@ impl Token<'_> {
|
|||||||
PrivacyPreservingAccount::Public(supply_account_id),
|
PrivacyPreservingAccount::Public(supply_account_id),
|
||||||
],
|
],
|
||||||
&instruction_data,
|
&instruction_data,
|
||||||
&program.into(),
|
&Program::token().into(),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.map(|(resp, secrets)| {
|
.map(|(resp, secrets)| {
|
||||||
@ -101,7 +102,9 @@ impl Token<'_> {
|
|||||||
name: [u8; 6],
|
name: [u8; 6],
|
||||||
total_supply: u128,
|
total_supply: u128,
|
||||||
) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> {
|
) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> {
|
||||||
let (instruction_data, program) = token_program_preparation_definition(name, total_supply);
|
let instruction = token_program_preparation_definition(name, total_supply);
|
||||||
|
let instruction_data =
|
||||||
|
Program::serialize_instruction(instruction).expect("Instruction should serialize");
|
||||||
|
|
||||||
self.0
|
self.0
|
||||||
.send_privacy_preserving_tx(
|
.send_privacy_preserving_tx(
|
||||||
@ -110,7 +113,7 @@ impl Token<'_> {
|
|||||||
PrivacyPreservingAccount::PrivateOwned(supply_account_id),
|
PrivacyPreservingAccount::PrivateOwned(supply_account_id),
|
||||||
],
|
],
|
||||||
&instruction_data,
|
&instruction_data,
|
||||||
&program.into(),
|
&Program::token().into(),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.map(|(resp, secrets)| {
|
.map(|(resp, secrets)| {
|
||||||
@ -131,7 +134,7 @@ impl Token<'_> {
|
|||||||
let program_id = nssa::program::Program::token().id();
|
let program_id = nssa::program::Program::token().id();
|
||||||
// Instruction must be: [0x01 || amount (little-endian 16 bytes) || 0x00 || 0x00 || 0x00 ||
|
// Instruction must be: [0x01 || amount (little-endian 16 bytes) || 0x00 || 0x00 || 0x00 ||
|
||||||
// 0x00 || 0x00 || 0x00].
|
// 0x00 || 0x00 || 0x00].
|
||||||
let mut instruction = [0; 23];
|
let mut instruction = vec![0u8; 23];
|
||||||
instruction[0] = 0x01;
|
instruction[0] = 0x01;
|
||||||
instruction[1..17].copy_from_slice(&amount.to_le_bytes());
|
instruction[1..17].copy_from_slice(&amount.to_le_bytes());
|
||||||
let Ok(nonces) = self.0.get_accounts_nonces(vec![sender_account_id]).await else {
|
let Ok(nonces) = self.0.get_accounts_nonces(vec![sender_account_id]).await else {
|
||||||
@ -167,7 +170,9 @@ impl Token<'_> {
|
|||||||
recipient_account_id: AccountId,
|
recipient_account_id: AccountId,
|
||||||
amount: u128,
|
amount: u128,
|
||||||
) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> {
|
) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> {
|
||||||
let (instruction_data, program) = token_program_preparation_transfer(amount);
|
let instruction = token_program_preparation_transfer(amount);
|
||||||
|
let instruction_data =
|
||||||
|
Program::serialize_instruction(instruction).expect("Instruction should serialize");
|
||||||
|
|
||||||
self.0
|
self.0
|
||||||
.send_privacy_preserving_tx(
|
.send_privacy_preserving_tx(
|
||||||
@ -176,7 +181,7 @@ impl Token<'_> {
|
|||||||
PrivacyPreservingAccount::PrivateOwned(recipient_account_id),
|
PrivacyPreservingAccount::PrivateOwned(recipient_account_id),
|
||||||
],
|
],
|
||||||
&instruction_data,
|
&instruction_data,
|
||||||
&program.into(),
|
&Program::token().into(),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.map(|(resp, secrets)| {
|
.map(|(resp, secrets)| {
|
||||||
@ -194,7 +199,9 @@ impl Token<'_> {
|
|||||||
recipient_ipk: IncomingViewingPublicKey,
|
recipient_ipk: IncomingViewingPublicKey,
|
||||||
amount: u128,
|
amount: u128,
|
||||||
) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> {
|
) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> {
|
||||||
let (instruction_data, program) = token_program_preparation_transfer(amount);
|
let instruction = token_program_preparation_transfer(amount);
|
||||||
|
let instruction_data =
|
||||||
|
Program::serialize_instruction(instruction).expect("Instruction should serialize");
|
||||||
|
|
||||||
self.0
|
self.0
|
||||||
.send_privacy_preserving_tx(
|
.send_privacy_preserving_tx(
|
||||||
@ -206,7 +213,7 @@ impl Token<'_> {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
&instruction_data,
|
&instruction_data,
|
||||||
&program.into(),
|
&Program::token().into(),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.map(|(resp, secrets)| {
|
.map(|(resp, secrets)| {
|
||||||
@ -223,7 +230,9 @@ impl Token<'_> {
|
|||||||
recipient_account_id: AccountId,
|
recipient_account_id: AccountId,
|
||||||
amount: u128,
|
amount: u128,
|
||||||
) -> Result<(SendTxResponse, SharedSecretKey), ExecutionFailureKind> {
|
) -> Result<(SendTxResponse, SharedSecretKey), ExecutionFailureKind> {
|
||||||
let (instruction_data, program) = token_program_preparation_transfer(amount);
|
let instruction = token_program_preparation_transfer(amount);
|
||||||
|
let instruction_data =
|
||||||
|
Program::serialize_instruction(instruction).expect("Instruction should serialize");
|
||||||
|
|
||||||
self.0
|
self.0
|
||||||
.send_privacy_preserving_tx(
|
.send_privacy_preserving_tx(
|
||||||
@ -232,7 +241,7 @@ impl Token<'_> {
|
|||||||
PrivacyPreservingAccount::Public(recipient_account_id),
|
PrivacyPreservingAccount::Public(recipient_account_id),
|
||||||
],
|
],
|
||||||
&instruction_data,
|
&instruction_data,
|
||||||
&program.into(),
|
&Program::token().into(),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.map(|(resp, secrets)| {
|
.map(|(resp, secrets)| {
|
||||||
@ -250,7 +259,9 @@ impl Token<'_> {
|
|||||||
recipient_account_id: AccountId,
|
recipient_account_id: AccountId,
|
||||||
amount: u128,
|
amount: u128,
|
||||||
) -> Result<(SendTxResponse, SharedSecretKey), ExecutionFailureKind> {
|
) -> Result<(SendTxResponse, SharedSecretKey), ExecutionFailureKind> {
|
||||||
let (instruction_data, program) = token_program_preparation_transfer(amount);
|
let instruction = token_program_preparation_transfer(amount);
|
||||||
|
let instruction_data =
|
||||||
|
Program::serialize_instruction(instruction).expect("Instruction should serialize");
|
||||||
|
|
||||||
self.0
|
self.0
|
||||||
.send_privacy_preserving_tx(
|
.send_privacy_preserving_tx(
|
||||||
@ -259,7 +270,7 @@ impl Token<'_> {
|
|||||||
PrivacyPreservingAccount::PrivateOwned(recipient_account_id),
|
PrivacyPreservingAccount::PrivateOwned(recipient_account_id),
|
||||||
],
|
],
|
||||||
&instruction_data,
|
&instruction_data,
|
||||||
&program.into(),
|
&Program::token().into(),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.map(|(resp, secrets)| {
|
.map(|(resp, secrets)| {
|
||||||
@ -278,7 +289,9 @@ impl Token<'_> {
|
|||||||
recipient_ipk: IncomingViewingPublicKey,
|
recipient_ipk: IncomingViewingPublicKey,
|
||||||
amount: u128,
|
amount: u128,
|
||||||
) -> Result<(SendTxResponse, SharedSecretKey), ExecutionFailureKind> {
|
) -> Result<(SendTxResponse, SharedSecretKey), ExecutionFailureKind> {
|
||||||
let (instruction_data, program) = token_program_preparation_transfer(amount);
|
let instruction = token_program_preparation_transfer(amount);
|
||||||
|
let instruction_data =
|
||||||
|
Program::serialize_instruction(instruction).expect("Instruction should serialize");
|
||||||
|
|
||||||
self.0
|
self.0
|
||||||
.send_privacy_preserving_tx(
|
.send_privacy_preserving_tx(
|
||||||
@ -290,7 +303,7 @@ impl Token<'_> {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
&instruction_data,
|
&instruction_data,
|
||||||
&program.into(),
|
&Program::token().into(),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.map(|(resp, secrets)| {
|
.map(|(resp, secrets)| {
|
||||||
@ -301,30 +314,354 @@ impl Token<'_> {
|
|||||||
(resp, first)
|
(resp, first)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn send_burn_transaction(
|
||||||
|
&self,
|
||||||
|
definition_account_id: AccountId,
|
||||||
|
holder_account_id: AccountId,
|
||||||
|
amount: u128,
|
||||||
|
) -> Result<SendTxResponse, ExecutionFailureKind> {
|
||||||
|
let account_ids = vec![definition_account_id, holder_account_id];
|
||||||
|
let instruction = token_program_preparation_burn(amount);
|
||||||
|
|
||||||
|
let Ok(nonces) = self.0.get_accounts_nonces(vec![holder_account_id]).await else {
|
||||||
|
return Err(ExecutionFailureKind::SequencerError);
|
||||||
|
};
|
||||||
|
let message = nssa::public_transaction::Message::try_new(
|
||||||
|
Program::token().id(),
|
||||||
|
account_ids,
|
||||||
|
nonces,
|
||||||
|
instruction,
|
||||||
|
)
|
||||||
|
.expect("Instruction should serialize");
|
||||||
|
|
||||||
|
let signing_key = self
|
||||||
|
.0
|
||||||
|
.storage
|
||||||
|
.user_data
|
||||||
|
.get_pub_account_signing_key(&holder_account_id)
|
||||||
|
.ok_or(ExecutionFailureKind::KeyNotFoundError)?;
|
||||||
|
let witness_set =
|
||||||
|
nssa::public_transaction::WitnessSet::for_message(&message, &[signing_key]);
|
||||||
|
|
||||||
|
let tx = nssa::PublicTransaction::new(message, witness_set);
|
||||||
|
|
||||||
|
Ok(self.0.sequencer_client.send_tx_public(tx).await?)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn send_burn_transaction_private_owned_account(
|
||||||
|
&self,
|
||||||
|
definition_account_id: AccountId,
|
||||||
|
holder_account_id: AccountId,
|
||||||
|
amount: u128,
|
||||||
|
) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> {
|
||||||
|
let instruction = token_program_preparation_burn(amount);
|
||||||
|
let instruction_data =
|
||||||
|
Program::serialize_instruction(instruction).expect("Instruction should serialize");
|
||||||
|
|
||||||
|
self.0
|
||||||
|
.send_privacy_preserving_tx(
|
||||||
|
vec![
|
||||||
|
PrivacyPreservingAccount::PrivateOwned(definition_account_id),
|
||||||
|
PrivacyPreservingAccount::PrivateOwned(holder_account_id),
|
||||||
|
],
|
||||||
|
&instruction_data,
|
||||||
|
&Program::token().into(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.map(|(resp, secrets)| {
|
||||||
|
let mut iter = secrets.into_iter();
|
||||||
|
let first = iter.next().expect("expected definition's secret");
|
||||||
|
let second = iter.next().expect("expected holder's secret");
|
||||||
|
(resp, [first, second])
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn send_burn_transaction_deshielded_owned_account(
|
||||||
|
&self,
|
||||||
|
definition_account_id: AccountId,
|
||||||
|
holder_account_id: AccountId,
|
||||||
|
amount: u128,
|
||||||
|
) -> Result<(SendTxResponse, SharedSecretKey), ExecutionFailureKind> {
|
||||||
|
let instruction = token_program_preparation_burn(amount);
|
||||||
|
let instruction_data =
|
||||||
|
Program::serialize_instruction(instruction).expect("Instruction should serialize");
|
||||||
|
|
||||||
|
self.0
|
||||||
|
.send_privacy_preserving_tx(
|
||||||
|
vec![
|
||||||
|
PrivacyPreservingAccount::PrivateOwned(definition_account_id),
|
||||||
|
PrivacyPreservingAccount::Public(holder_account_id),
|
||||||
|
],
|
||||||
|
&instruction_data,
|
||||||
|
&Program::token().into(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.map(|(resp, secrets)| {
|
||||||
|
let first = secrets
|
||||||
|
.into_iter()
|
||||||
|
.next()
|
||||||
|
.expect("expected definition's secret");
|
||||||
|
(resp, first)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn send_burn_transaction_shielded(
|
||||||
|
&self,
|
||||||
|
definition_account_id: AccountId,
|
||||||
|
holder_account_id: AccountId,
|
||||||
|
amount: u128,
|
||||||
|
) -> Result<(SendTxResponse, SharedSecretKey), ExecutionFailureKind> {
|
||||||
|
let instruction = token_program_preparation_burn(amount);
|
||||||
|
let instruction_data =
|
||||||
|
Program::serialize_instruction(instruction).expect("Instruction should serialize");
|
||||||
|
|
||||||
|
self.0
|
||||||
|
.send_privacy_preserving_tx(
|
||||||
|
vec![
|
||||||
|
PrivacyPreservingAccount::Public(definition_account_id),
|
||||||
|
PrivacyPreservingAccount::PrivateOwned(holder_account_id),
|
||||||
|
],
|
||||||
|
&instruction_data,
|
||||||
|
&Program::token().into(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.map(|(resp, secrets)| {
|
||||||
|
let first = secrets
|
||||||
|
.into_iter()
|
||||||
|
.next()
|
||||||
|
.expect("expected holder's secret");
|
||||||
|
(resp, first)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn send_mint_transaction(
|
||||||
|
&self,
|
||||||
|
definition_account_id: AccountId,
|
||||||
|
holder_account_id: AccountId,
|
||||||
|
amount: u128,
|
||||||
|
) -> Result<SendTxResponse, ExecutionFailureKind> {
|
||||||
|
let account_ids = vec![definition_account_id, holder_account_id];
|
||||||
|
let instruction = token_program_preparation_mint(amount);
|
||||||
|
|
||||||
|
let Ok(nonces) = self
|
||||||
|
.0
|
||||||
|
.get_accounts_nonces(vec![definition_account_id])
|
||||||
|
.await
|
||||||
|
else {
|
||||||
|
return Err(ExecutionFailureKind::SequencerError);
|
||||||
|
};
|
||||||
|
let message = nssa::public_transaction::Message::try_new(
|
||||||
|
Program::token().id(),
|
||||||
|
account_ids,
|
||||||
|
nonces,
|
||||||
|
instruction,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let Some(signing_key) = self
|
||||||
|
.0
|
||||||
|
.storage
|
||||||
|
.user_data
|
||||||
|
.get_pub_account_signing_key(&definition_account_id)
|
||||||
|
else {
|
||||||
|
return Err(ExecutionFailureKind::KeyNotFoundError);
|
||||||
|
};
|
||||||
|
let witness_set =
|
||||||
|
nssa::public_transaction::WitnessSet::for_message(&message, &[signing_key]);
|
||||||
|
|
||||||
|
let tx = nssa::PublicTransaction::new(message, witness_set);
|
||||||
|
|
||||||
|
Ok(self.0.sequencer_client.send_tx_public(tx).await?)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn send_mint_transaction_private_owned_account(
|
||||||
|
&self,
|
||||||
|
definition_account_id: AccountId,
|
||||||
|
holder_account_id: AccountId,
|
||||||
|
amount: u128,
|
||||||
|
) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> {
|
||||||
|
let instruction = token_program_preparation_mint(amount);
|
||||||
|
let instruction_data =
|
||||||
|
Program::serialize_instruction(instruction).expect("Instruction should serialize");
|
||||||
|
|
||||||
|
self.0
|
||||||
|
.send_privacy_preserving_tx(
|
||||||
|
vec![
|
||||||
|
PrivacyPreservingAccount::PrivateOwned(definition_account_id),
|
||||||
|
PrivacyPreservingAccount::PrivateOwned(holder_account_id),
|
||||||
|
],
|
||||||
|
&instruction_data,
|
||||||
|
&Program::token().into(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.map(|(resp, secrets)| {
|
||||||
|
let mut iter = secrets.into_iter();
|
||||||
|
let first = iter.next().expect("expected definition's secret");
|
||||||
|
let second = iter.next().expect("expected holder's secret");
|
||||||
|
(resp, [first, second])
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn send_mint_transaction_private_foreign_account(
|
||||||
|
&self,
|
||||||
|
definition_account_id: AccountId,
|
||||||
|
holder_npk: NullifierPublicKey,
|
||||||
|
holder_ipk: IncomingViewingPublicKey,
|
||||||
|
amount: u128,
|
||||||
|
) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> {
|
||||||
|
let instruction = token_program_preparation_mint(amount);
|
||||||
|
let instruction_data =
|
||||||
|
Program::serialize_instruction(instruction).expect("Instruction should serialize");
|
||||||
|
|
||||||
|
self.0
|
||||||
|
.send_privacy_preserving_tx(
|
||||||
|
vec![
|
||||||
|
PrivacyPreservingAccount::PrivateOwned(definition_account_id),
|
||||||
|
PrivacyPreservingAccount::PrivateForeign {
|
||||||
|
npk: holder_npk,
|
||||||
|
ipk: holder_ipk,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
&instruction_data,
|
||||||
|
&Program::token().into(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.map(|(resp, secrets)| {
|
||||||
|
let mut iter = secrets.into_iter();
|
||||||
|
let first = iter.next().expect("expected definition's secret");
|
||||||
|
let second = iter.next().expect("expected holder's secret");
|
||||||
|
(resp, [first, second])
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn send_mint_transaction_deshielded(
|
||||||
|
&self,
|
||||||
|
definition_account_id: AccountId,
|
||||||
|
holder_account_id: AccountId,
|
||||||
|
amount: u128,
|
||||||
|
) -> Result<(SendTxResponse, SharedSecretKey), ExecutionFailureKind> {
|
||||||
|
let instruction = token_program_preparation_mint(amount);
|
||||||
|
let instruction_data =
|
||||||
|
Program::serialize_instruction(instruction).expect("Instruction should serialize");
|
||||||
|
|
||||||
|
self.0
|
||||||
|
.send_privacy_preserving_tx(
|
||||||
|
vec![
|
||||||
|
PrivacyPreservingAccount::PrivateOwned(definition_account_id),
|
||||||
|
PrivacyPreservingAccount::Public(holder_account_id),
|
||||||
|
],
|
||||||
|
&instruction_data,
|
||||||
|
&Program::token().into(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.map(|(resp, secrets)| {
|
||||||
|
let first = secrets
|
||||||
|
.into_iter()
|
||||||
|
.next()
|
||||||
|
.expect("expected definition's secret");
|
||||||
|
(resp, first)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn send_mint_transaction_shielded_owned_account(
|
||||||
|
&self,
|
||||||
|
definition_account_id: AccountId,
|
||||||
|
holder_account_id: AccountId,
|
||||||
|
amount: u128,
|
||||||
|
) -> Result<(SendTxResponse, SharedSecretKey), ExecutionFailureKind> {
|
||||||
|
let instruction = token_program_preparation_mint(amount);
|
||||||
|
let instruction_data =
|
||||||
|
Program::serialize_instruction(instruction).expect("Instruction should serialize");
|
||||||
|
|
||||||
|
self.0
|
||||||
|
.send_privacy_preserving_tx(
|
||||||
|
vec![
|
||||||
|
PrivacyPreservingAccount::Public(definition_account_id),
|
||||||
|
PrivacyPreservingAccount::PrivateOwned(holder_account_id),
|
||||||
|
],
|
||||||
|
&instruction_data,
|
||||||
|
&Program::token().into(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.map(|(resp, secrets)| {
|
||||||
|
let first = secrets
|
||||||
|
.into_iter()
|
||||||
|
.next()
|
||||||
|
.expect("expected holder's secret");
|
||||||
|
(resp, first)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn send_mint_transaction_shielded_foreign_account(
|
||||||
|
&self,
|
||||||
|
definition_account_id: AccountId,
|
||||||
|
holder_npk: NullifierPublicKey,
|
||||||
|
holder_ipk: IncomingViewingPublicKey,
|
||||||
|
amount: u128,
|
||||||
|
) -> Result<(SendTxResponse, SharedSecretKey), ExecutionFailureKind> {
|
||||||
|
let instruction = token_program_preparation_mint(amount);
|
||||||
|
let instruction_data =
|
||||||
|
Program::serialize_instruction(instruction).expect("Instruction should serialize");
|
||||||
|
|
||||||
|
self.0
|
||||||
|
.send_privacy_preserving_tx(
|
||||||
|
vec![
|
||||||
|
PrivacyPreservingAccount::Public(definition_account_id),
|
||||||
|
PrivacyPreservingAccount::PrivateForeign {
|
||||||
|
npk: holder_npk,
|
||||||
|
ipk: holder_ipk,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
&instruction_data,
|
||||||
|
&Program::token().into(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.map(|(resp, secrets)| {
|
||||||
|
let first = secrets
|
||||||
|
.into_iter()
|
||||||
|
.next()
|
||||||
|
.expect("expected holder's secret");
|
||||||
|
(resp, first)
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn token_program_preparation_transfer(amount: u128) -> (InstructionData, Program) {
|
fn token_program_preparation_transfer(amount: u128) -> Vec<u8> {
|
||||||
// Instruction must be: [0x01 || amount (little-endian 16 bytes) || 0x00 || 0x00 || 0x00 ||
|
// Instruction must be: [0x01 || amount (little-endian 16 bytes) || 0x00 || 0x00 || 0x00 ||
|
||||||
// 0x00 || 0x00 || 0x00].
|
// 0x00 || 0x00 || 0x00].
|
||||||
let mut instruction = [0; 23];
|
let mut instruction = vec![0u8; 23];
|
||||||
instruction[0] = 0x01;
|
instruction[0] = 0x01;
|
||||||
instruction[1..17].copy_from_slice(&amount.to_le_bytes());
|
instruction[1..17].copy_from_slice(&amount.to_le_bytes());
|
||||||
let instruction_data = Program::serialize_instruction(instruction).unwrap();
|
|
||||||
let program = Program::token();
|
|
||||||
|
|
||||||
(instruction_data, program)
|
instruction
|
||||||
}
|
}
|
||||||
|
|
||||||
fn token_program_preparation_definition(
|
fn token_program_preparation_definition(name: [u8; 6], total_supply: u128) -> Vec<u8> {
|
||||||
name: [u8; 6],
|
|
||||||
total_supply: u128,
|
|
||||||
) -> (InstructionData, Program) {
|
|
||||||
// Instruction must be: [0x00 || total_supply (little-endian 16 bytes) || name (6 bytes)]
|
// Instruction must be: [0x00 || total_supply (little-endian 16 bytes) || name (6 bytes)]
|
||||||
let mut instruction = [0; 23];
|
let mut instruction = vec![0u8; 23];
|
||||||
instruction[1..17].copy_from_slice(&total_supply.to_le_bytes());
|
instruction[1..17].copy_from_slice(&total_supply.to_le_bytes());
|
||||||
instruction[17..].copy_from_slice(&name);
|
instruction[17..].copy_from_slice(&name);
|
||||||
let instruction_data = Program::serialize_instruction(instruction).unwrap();
|
|
||||||
let program = Program::token();
|
|
||||||
|
|
||||||
(instruction_data, program)
|
instruction
|
||||||
|
}
|
||||||
|
|
||||||
|
fn token_program_preparation_burn(amount: u128) -> Vec<u8> {
|
||||||
|
// Instruction must be: [0x03 || amount (little-endian 16 bytes) || 0x00 || 0x00 || 0x00 ||
|
||||||
|
// 0x00 || 0x00 || 0x00].
|
||||||
|
let mut instruction = vec![0; 23];
|
||||||
|
instruction[0] = 0x03;
|
||||||
|
instruction[1..17].copy_from_slice(&amount.to_le_bytes());
|
||||||
|
|
||||||
|
instruction
|
||||||
|
}
|
||||||
|
|
||||||
|
fn token_program_preparation_mint(amount: u128) -> Vec<u8> {
|
||||||
|
// Instruction must be: [0x04 || amount (little-endian 16 bytes) || 0x00 || 0x00 || 0x00 ||
|
||||||
|
// 0x00 || 0x00 || 0x00].
|
||||||
|
let mut instruction = vec![0; 23];
|
||||||
|
instruction[0] = 0x04;
|
||||||
|
instruction[1..17].copy_from_slice(&amount.to_le_bytes());
|
||||||
|
|
||||||
|
instruction
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user