mirror of
https://github.com/logos-blockchain/lez-programs.git
synced 2026-05-18 15:09:51 +00:00
refactor!: Update dependencies and implement new required features across multiple modules
- Updated `nssa_core` and `spel-framework` dependencies to their respective release candidates in `Cargo.toml` and `Cargo.lock` files for `amm`, `ata`, and `token` modules. - Enhanced the `new_definition` function in `amm/src/new_definition.rs` to include new claim logic and updated PDA seed calculations. - Modified tests in `integration_tests/tests/amm.rs`, `integration_tests/tests/ata.rs`, and `integration_tests/tests/token.rs` to accommodate changes in transaction handling and account initialization. - Refactored account initialization logic in `ata/src/create.rs` and `token/src/initialize.rs` to include authorization claims. - Updated various functions in `token/src/mint.rs`, `token/src/new_definition.rs`, and `token/src/transfer.rs` to utilize the new claim system for account states. - Adjusted the IDL generation tool to use the latest version of `spel-framework-core`.
This commit is contained in:
parent
6c86b5b9ce
commit
471abef719
18
Cargo.lock
generated
18
Cargo.lock
generated
@ -598,6 +598,15 @@ dependencies = [
|
||||
"inout",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clock_core"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/logos-blockchain/logos-execution-zone.git?tag=v0.2.0-rc1#35d8df0d031315219f94d1546ceb862b0e5b208f"
|
||||
dependencies = [
|
||||
"borsh",
|
||||
"nssa_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cobs"
|
||||
version = "0.3.0"
|
||||
@ -1821,10 +1830,11 @@ checksum = "a5b0c77c1b780822bc749a33e39aeb2c07584ab93332303babeabb645298a76e"
|
||||
[[package]]
|
||||
name = "nssa"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/logos-blockchain/logos-execution-zone.git?rev=ffcbc15972adbf557939bf3e2852af276422631b#ffcbc15972adbf557939bf3e2852af276422631b"
|
||||
source = "git+https://github.com/logos-blockchain/logos-execution-zone.git?tag=v0.2.0-rc1#35d8df0d031315219f94d1546ceb862b0e5b208f"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"borsh",
|
||||
"clock_core",
|
||||
"hex",
|
||||
"k256",
|
||||
"log",
|
||||
@ -1842,7 +1852,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "nssa_core"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/logos-blockchain/logos-execution-zone.git?rev=ffcbc15972adbf557939bf3e2852af276422631b#ffcbc15972adbf557939bf3e2852af276422631b"
|
||||
source = "git+https://github.com/logos-blockchain/logos-execution-zone.git?tag=v0.2.0-rc1#35d8df0d031315219f94d1546ceb862b0e5b208f"
|
||||
dependencies = [
|
||||
"base58",
|
||||
"borsh",
|
||||
@ -2962,8 +2972,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "spel-framework-core"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/logos-co/spel.git?rev=57201f64b4542bb3f592bc9a0aa654c47aa908a6#57201f64b4542bb3f592bc9a0aa654c47aa908a6"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/logos-co/spel.git?tag=v0.2.0-rc.2#9005e9fbbd78b0530412f9987273f753ed32eb2d"
|
||||
dependencies = [
|
||||
"borsh",
|
||||
"nssa_core",
|
||||
|
||||
@ -20,8 +20,8 @@ exclude = [
|
||||
resolver = "2"
|
||||
|
||||
[workspace.dependencies]
|
||||
nssa_core = { git = "https://github.com/logos-blockchain/logos-execution-zone.git", rev = "ffcbc15972adbf557939bf3e2852af276422631b", features = ["host"] }
|
||||
nssa = { git = "https://github.com/logos-blockchain/logos-execution-zone.git", rev = "ffcbc15972adbf557939bf3e2852af276422631b", features = ["test-utils"] }
|
||||
nssa_core = { git = "https://github.com/logos-blockchain/logos-execution-zone.git", tag = "v0.2.0-rc1", features = ["host"] }
|
||||
nssa = { git = "https://github.com/logos-blockchain/logos-execution-zone.git", tag = "v0.2.0-rc1", features = ["test-utils"] }
|
||||
token_core = { path = "token/core" }
|
||||
token_program = { path = "token" }
|
||||
amm_core = { path = "amm/core" }
|
||||
@ -33,4 +33,3 @@ borsh = { version = "1.0", features = ["derive"] }
|
||||
risc0-zkvm = { version = "=3.0.5" }
|
||||
serde_json = "1.0"
|
||||
tokio = { version = "1.28.2", features = ["net", "rt-multi-thread", "sync", "macros"] }
|
||||
|
||||
|
||||
@ -4,6 +4,6 @@ version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
nssa_core = { git = "https://github.com/logos-blockchain/logos-execution-zone.git", rev = "ffcbc15972adbf557939bf3e2852af276422631b", features = ["host"] }
|
||||
nssa_core = { git = "https://github.com/logos-blockchain/logos-execution-zone.git", tag = "v0.2.0-rc1", features = ["host"] }
|
||||
amm_core = { path = "core" }
|
||||
token_core = { path = "../token/core" }
|
||||
|
||||
@ -4,7 +4,7 @@ version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
nssa_core = { git = "https://github.com/logos-blockchain/logos-execution-zone.git", rev = "ffcbc15972adbf557939bf3e2852af276422631b", features = ["host"] }
|
||||
nssa_core = { git = "https://github.com/logos-blockchain/logos-execution-zone.git", tag = "v0.2.0-rc1", features = ["host"] }
|
||||
token_core = { path = "../../token/core" }
|
||||
borsh = { version = "1.5", features = ["derive"] }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
|
||||
@ -29,7 +29,7 @@ pub enum Instruction {
|
||||
/// pool.account_id)`
|
||||
/// - User Holding Account for Token A (authorized)
|
||||
/// - User Holding Account for Token B (authorized)
|
||||
/// - User Holding Account for Pool Liquidity
|
||||
/// - User Holding Account for Pool Liquidity (authorized when uninitialized)
|
||||
NewDefinition {
|
||||
token_a_amount: u128,
|
||||
token_b_amount: u128,
|
||||
|
||||
14
amm/methods/guest/Cargo.lock
generated
14
amm/methods/guest/Cargo.lock
generated
@ -1778,7 +1778,7 @@ checksum = "a5b0c77c1b780822bc749a33e39aeb2c07584ab93332303babeabb645298a76e"
|
||||
[[package]]
|
||||
name = "nssa_core"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/logos-blockchain/logos-execution-zone.git?rev=ffcbc15972adbf557939bf3e2852af276422631b#ffcbc15972adbf557939bf3e2852af276422631b"
|
||||
source = "git+https://github.com/logos-blockchain/logos-execution-zone.git?tag=v0.2.0-rc1#35d8df0d031315219f94d1546ceb862b0e5b208f"
|
||||
dependencies = [
|
||||
"base58",
|
||||
"borsh",
|
||||
@ -2897,8 +2897,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "spel-framework"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/logos-co/spel.git?rev=57201f64b4542bb3f592bc9a0aa654c47aa908a6#57201f64b4542bb3f592bc9a0aa654c47aa908a6"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/logos-co/spel.git?tag=v0.2.0-rc.2#9005e9fbbd78b0530412f9987273f753ed32eb2d"
|
||||
dependencies = [
|
||||
"borsh",
|
||||
"nssa_core",
|
||||
@ -2908,8 +2908,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "spel-framework-core"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/logos-co/spel.git?rev=57201f64b4542bb3f592bc9a0aa654c47aa908a6#57201f64b4542bb3f592bc9a0aa654c47aa908a6"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/logos-co/spel.git?tag=v0.2.0-rc.2#9005e9fbbd78b0530412f9987273f753ed32eb2d"
|
||||
dependencies = [
|
||||
"borsh",
|
||||
"nssa_core",
|
||||
@ -2921,8 +2921,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "spel-framework-macros"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/logos-co/spel.git?rev=57201f64b4542bb3f592bc9a0aa654c47aa908a6#57201f64b4542bb3f592bc9a0aa654c47aa908a6"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/logos-co/spel.git?tag=v0.2.0-rc.2#9005e9fbbd78b0530412f9987273f753ed32eb2d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
||||
@ -10,8 +10,8 @@ name = "amm"
|
||||
path = "src/bin/amm.rs"
|
||||
|
||||
[dependencies]
|
||||
spel-framework = { git = "https://github.com/logos-co/spel.git", rev = "57201f64b4542bb3f592bc9a0aa654c47aa908a6", package = "spel-framework" }
|
||||
nssa_core = { git = "https://github.com/logos-blockchain/logos-execution-zone.git", rev = "ffcbc15972adbf557939bf3e2852af276422631b" }
|
||||
spel-framework = { git = "https://github.com/logos-co/spel.git", tag = "v0.2.0-rc.2", package = "spel-framework" }
|
||||
nssa_core = { git = "https://github.com/logos-blockchain/logos-execution-zone.git", tag = "v0.2.0-rc1" }
|
||||
risc0-zkvm = { version = "=3.0.5", default-features = false }
|
||||
amm_core = { path = "../../core" }
|
||||
amm_program = { path = "../..", package = "amm_program" }
|
||||
|
||||
@ -16,6 +16,7 @@ mod amm {
|
||||
use super::*;
|
||||
|
||||
/// Initializes a new Pool (or re-initializes an existing zero-supply Pool).
|
||||
/// A fresh user LP holding must be explicitly authorized by the caller.
|
||||
#[instruction]
|
||||
pub fn new_definition(
|
||||
pool: AccountWithMetadata,
|
||||
|
||||
@ -2,12 +2,13 @@ use std::num::NonZeroU128;
|
||||
|
||||
use amm_core::{
|
||||
assert_supported_fee_tier, compute_liquidity_token_pda, compute_liquidity_token_pda_seed,
|
||||
compute_lp_lock_holding_pda, compute_pool_pda, compute_vault_pda, PoolDefinition,
|
||||
compute_lp_lock_holding_pda, compute_lp_lock_holding_pda_seed, compute_pool_pda,
|
||||
compute_pool_pda_seed, compute_vault_pda, compute_vault_pda_seed, PoolDefinition,
|
||||
MINIMUM_LIQUIDITY,
|
||||
};
|
||||
use nssa_core::{
|
||||
account::{Account, AccountWithMetadata, Data},
|
||||
program::{AccountPostState, ChainedCall, ProgramId},
|
||||
program::{AccountPostState, ChainedCall, Claim, ProgramId},
|
||||
};
|
||||
use token_core::TokenDefinition;
|
||||
|
||||
@ -78,6 +79,10 @@ pub fn new_definition(
|
||||
Account::default(),
|
||||
"Pool account must be uninitialized"
|
||||
);
|
||||
assert!(
|
||||
user_holding_lp.account != Account::default() || user_holding_lp.is_authorized,
|
||||
"Fresh user LP holding requires user authorization"
|
||||
);
|
||||
|
||||
// LP Token minting calculation
|
||||
let initial_lp = token_a_amount
|
||||
@ -106,40 +111,63 @@ pub fn new_definition(
|
||||
};
|
||||
|
||||
pool_post.data = Data::from(&pool_post_definition);
|
||||
let pool_post: AccountPostState = AccountPostState::new_claimed(pool_post.clone());
|
||||
let pool_post: AccountPostState = AccountPostState::new_claimed(
|
||||
pool_post.clone(),
|
||||
Claim::Pda(compute_pool_pda_seed(
|
||||
definition_token_a_id,
|
||||
definition_token_b_id,
|
||||
)),
|
||||
);
|
||||
|
||||
let token_program_id = user_holding_a.account.program_owner;
|
||||
|
||||
// Chain call for Token A (user_holding_a -> Vault_A)
|
||||
let mut vault_a_authorized = vault_a.clone();
|
||||
vault_a_authorized.is_authorized = true;
|
||||
let call_token_a = ChainedCall::new(
|
||||
token_program_id,
|
||||
vec![user_holding_a.clone(), vault_a.clone()],
|
||||
vec![user_holding_a.clone(), vault_a_authorized],
|
||||
&token_core::Instruction::Transfer {
|
||||
amount_to_transfer: token_a_amount.into(),
|
||||
},
|
||||
);
|
||||
)
|
||||
.with_pda_seeds(vec![compute_vault_pda_seed(
|
||||
pool.account_id,
|
||||
definition_token_a_id,
|
||||
)]);
|
||||
// Chain call for Token B (user_holding_b -> Vault_B)
|
||||
let mut vault_b_authorized = vault_b.clone();
|
||||
vault_b_authorized.is_authorized = true;
|
||||
let call_token_b = ChainedCall::new(
|
||||
token_program_id,
|
||||
vec![user_holding_b.clone(), vault_b.clone()],
|
||||
vec![user_holding_b.clone(), vault_b_authorized],
|
||||
&token_core::Instruction::Transfer {
|
||||
amount_to_transfer: token_b_amount.into(),
|
||||
},
|
||||
);
|
||||
)
|
||||
.with_pda_seeds(vec![compute_vault_pda_seed(
|
||||
pool.account_id,
|
||||
definition_token_b_id,
|
||||
)]);
|
||||
|
||||
// Chain call for liquidity token lock holding
|
||||
let mut pool_lp_auth = pool_definition_lp.clone();
|
||||
pool_lp_auth.is_authorized = true;
|
||||
let mut lp_lock_holding_auth = lp_lock_holding.clone();
|
||||
lp_lock_holding_auth.is_authorized = true;
|
||||
|
||||
let call_token_lp_lock = ChainedCall::new(
|
||||
token_program_id,
|
||||
vec![pool_lp_auth.clone(), lp_lock_holding.clone()],
|
||||
vec![pool_lp_auth.clone(), lp_lock_holding_auth],
|
||||
&token_core::Instruction::NewFungibleDefinition {
|
||||
name: String::from("LP Token"),
|
||||
total_supply: MINIMUM_LIQUIDITY,
|
||||
},
|
||||
)
|
||||
.with_pda_seeds(vec![compute_liquidity_token_pda_seed(pool.account_id)]);
|
||||
.with_pda_seeds(vec![
|
||||
compute_liquidity_token_pda_seed(pool.account_id),
|
||||
compute_lp_lock_holding_pda_seed(pool.account_id),
|
||||
]);
|
||||
|
||||
let mut pool_lp_after_lock = pool_lp_auth.clone();
|
||||
pool_lp_after_lock.account.program_owner = token_program_id;
|
||||
|
||||
@ -4,13 +4,13 @@ use std::num::NonZero;
|
||||
|
||||
use amm_core::{
|
||||
compute_liquidity_token_pda, compute_liquidity_token_pda_seed, compute_lp_lock_holding_pda,
|
||||
compute_pool_pda, compute_vault_pda, compute_vault_pda_seed, PoolDefinition,
|
||||
FEE_BPS_DENOMINATOR, FEE_TIER_BPS_1, FEE_TIER_BPS_100, FEE_TIER_BPS_30, FEE_TIER_BPS_5,
|
||||
MINIMUM_LIQUIDITY,
|
||||
compute_lp_lock_holding_pda_seed, compute_pool_pda, compute_pool_pda_seed, compute_vault_pda,
|
||||
compute_vault_pda_seed, PoolDefinition, FEE_BPS_DENOMINATOR, FEE_TIER_BPS_1, FEE_TIER_BPS_100,
|
||||
FEE_TIER_BPS_30, FEE_TIER_BPS_5, MINIMUM_LIQUIDITY,
|
||||
};
|
||||
use nssa_core::{
|
||||
account::{Account, AccountId, AccountWithMetadata, Data, Nonce},
|
||||
program::{ChainedCall, ProgramId},
|
||||
program::{ChainedCall, Claim, ProgramId},
|
||||
};
|
||||
use token_core::{TokenDefinition, TokenHolding};
|
||||
|
||||
@ -489,46 +489,57 @@ impl ChainedCallForTests {
|
||||
}
|
||||
|
||||
fn cc_new_definition_token_a() -> ChainedCall {
|
||||
let mut vault_a_auth = AccountWithMetadataForTests::vault_a_init();
|
||||
vault_a_auth.is_authorized = true;
|
||||
|
||||
ChainedCall::new(
|
||||
TOKEN_PROGRAM_ID,
|
||||
vec![
|
||||
AccountWithMetadataForTests::user_holding_a(),
|
||||
AccountWithMetadataForTests::vault_a_init(),
|
||||
],
|
||||
vec![AccountWithMetadataForTests::user_holding_a(), vault_a_auth],
|
||||
&token_core::Instruction::Transfer {
|
||||
amount_to_transfer: BalanceForTests::vault_a_reserve_init(),
|
||||
},
|
||||
)
|
||||
.with_pda_seeds(vec![compute_vault_pda_seed(
|
||||
IdForTests::pool_definition_id(),
|
||||
IdForTests::token_a_definition_id(),
|
||||
)])
|
||||
}
|
||||
|
||||
fn cc_new_definition_token_b() -> ChainedCall {
|
||||
let mut vault_b_auth = AccountWithMetadataForTests::vault_b_init();
|
||||
vault_b_auth.is_authorized = true;
|
||||
|
||||
ChainedCall::new(
|
||||
TOKEN_PROGRAM_ID,
|
||||
vec![
|
||||
AccountWithMetadataForTests::user_holding_b(),
|
||||
AccountWithMetadataForTests::vault_b_init(),
|
||||
],
|
||||
vec![AccountWithMetadataForTests::user_holding_b(), vault_b_auth],
|
||||
&token_core::Instruction::Transfer {
|
||||
amount_to_transfer: BalanceForTests::vault_b_reserve_init(),
|
||||
},
|
||||
)
|
||||
.with_pda_seeds(vec![compute_vault_pda_seed(
|
||||
IdForTests::pool_definition_id(),
|
||||
IdForTests::token_b_definition_id(),
|
||||
)])
|
||||
}
|
||||
|
||||
fn cc_new_definition_token_lp_lock() -> ChainedCall {
|
||||
let mut pool_lp_auth = AccountForTests::pool_lp_uninit();
|
||||
pool_lp_auth.is_authorized = true;
|
||||
let mut lp_lock_holding_auth = AccountForTests::lp_lock_holding_uninit();
|
||||
lp_lock_holding_auth.is_authorized = true;
|
||||
|
||||
ChainedCall::new(
|
||||
TOKEN_PROGRAM_ID,
|
||||
vec![pool_lp_auth, AccountForTests::lp_lock_holding_uninit()],
|
||||
vec![pool_lp_auth, lp_lock_holding_auth],
|
||||
&token_core::Instruction::NewFungibleDefinition {
|
||||
name: String::from("LP Token"),
|
||||
total_supply: MINIMUM_LIQUIDITY,
|
||||
},
|
||||
)
|
||||
.with_pda_seeds(vec![compute_liquidity_token_pda_seed(
|
||||
IdForTests::pool_definition_id(),
|
||||
)])
|
||||
.with_pda_seeds(vec![
|
||||
compute_liquidity_token_pda_seed(IdForTests::pool_definition_id()),
|
||||
compute_lp_lock_holding_pda_seed(IdForTests::pool_definition_id()),
|
||||
])
|
||||
}
|
||||
|
||||
fn cc_new_definition_token_lp_user() -> ChainedCall {
|
||||
@ -2068,6 +2079,13 @@ fn test_call_new_definition_chained_call_successful() {
|
||||
let pool_post = post_states[0].clone();
|
||||
|
||||
assert!(AccountWithMetadataForTests::pool_definition_init().account == *pool_post.account());
|
||||
assert_eq!(
|
||||
pool_post.required_claim(),
|
||||
Some(Claim::Pda(compute_pool_pda_seed(
|
||||
IdForTests::token_a_definition_id(),
|
||||
IdForTests::token_b_definition_id(),
|
||||
)))
|
||||
);
|
||||
|
||||
let chained_call_lp_lock = chained_calls[0].clone();
|
||||
let chained_call_lp_user = chained_calls[1].clone();
|
||||
@ -2752,20 +2770,20 @@ fn test_new_definition_lp_symmetric_amounts() {
|
||||
|
||||
let mut pool_lp_auth = AccountForTests::pool_lp_uninit();
|
||||
pool_lp_auth.is_authorized = true;
|
||||
let mut lp_lock_holding_auth = AccountForTests::lp_lock_holding_uninit();
|
||||
lp_lock_holding_auth.is_authorized = true;
|
||||
let expected_lp_lock_call = ChainedCall::new(
|
||||
TOKEN_PROGRAM_ID,
|
||||
vec![
|
||||
pool_lp_auth.clone(),
|
||||
AccountForTests::lp_lock_holding_uninit(),
|
||||
],
|
||||
vec![pool_lp_auth.clone(), lp_lock_holding_auth],
|
||||
&token_core::Instruction::NewFungibleDefinition {
|
||||
name: String::from("LP Token"),
|
||||
total_supply: MINIMUM_LIQUIDITY,
|
||||
},
|
||||
)
|
||||
.with_pda_seeds(vec![compute_liquidity_token_pda_seed(
|
||||
IdForTests::pool_definition_id(),
|
||||
)]);
|
||||
.with_pda_seeds(vec![
|
||||
compute_liquidity_token_pda_seed(IdForTests::pool_definition_id()),
|
||||
compute_lp_lock_holding_pda_seed(IdForTests::pool_definition_id()),
|
||||
]);
|
||||
|
||||
let expected_lp_user_call = ChainedCall::new(
|
||||
TOKEN_PROGRAM_ID,
|
||||
@ -2814,21 +2832,21 @@ fn test_minimum_liquidity_lock_and_remove_all_user_lp() {
|
||||
|
||||
let mut pool_lp_auth = AccountForTests::pool_lp_uninit();
|
||||
pool_lp_auth.is_authorized = true;
|
||||
let mut lp_lock_holding_auth = AccountForTests::lp_lock_holding_uninit();
|
||||
lp_lock_holding_auth.is_authorized = true;
|
||||
|
||||
let expected_lock_call = ChainedCall::new(
|
||||
TOKEN_PROGRAM_ID,
|
||||
vec![
|
||||
pool_lp_auth.clone(),
|
||||
AccountForTests::lp_lock_holding_uninit(),
|
||||
],
|
||||
vec![pool_lp_auth.clone(), lp_lock_holding_auth],
|
||||
&token_core::Instruction::NewFungibleDefinition {
|
||||
name: String::from("LP Token"),
|
||||
total_supply: MINIMUM_LIQUIDITY,
|
||||
},
|
||||
)
|
||||
.with_pda_seeds(vec![compute_liquidity_token_pda_seed(
|
||||
IdForTests::pool_definition_id(),
|
||||
)]);
|
||||
.with_pda_seeds(vec![
|
||||
compute_liquidity_token_pda_seed(IdForTests::pool_definition_id()),
|
||||
compute_lp_lock_holding_pda_seed(IdForTests::pool_definition_id()),
|
||||
]);
|
||||
let expected_user_call = ChainedCall::new(
|
||||
TOKEN_PROGRAM_ID,
|
||||
vec![
|
||||
|
||||
@ -4,6 +4,6 @@ version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
nssa_core = { git = "https://github.com/logos-blockchain/logos-execution-zone.git", rev = "ffcbc15972adbf557939bf3e2852af276422631b", features = ["host"] }
|
||||
nssa_core = { git = "https://github.com/logos-blockchain/logos-execution-zone.git", tag = "v0.2.0-rc1", features = ["host"] }
|
||||
ata_core = { path = "core" }
|
||||
token_core = { path = "../token/core" }
|
||||
|
||||
@ -4,7 +4,7 @@ version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
nssa_core = { git = "https://github.com/logos-blockchain/logos-execution-zone.git", rev = "ffcbc15972adbf557939bf3e2852af276422631b", features = ["host"] }
|
||||
nssa_core = { git = "https://github.com/logos-blockchain/logos-execution-zone.git", tag = "v0.2.0-rc1", features = ["host"] }
|
||||
borsh = { version = "1.5", features = ["derive"] }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
risc0-zkvm = { version = "=3.0.5", default-features = false }
|
||||
|
||||
@ -18,13 +18,13 @@ pub enum Instruction {
|
||||
/// `token_program_id` is derived from `token_definition.account.program_owner`.
|
||||
Create { ata_program_id: ProgramId },
|
||||
|
||||
/// Transfer tokens FROM owner's ATA to a recipient holding account.
|
||||
/// Uses PDA seeds to authorize the ATA in the chained Token::Transfer call.
|
||||
/// Transfer tokens FROM owner's ATA to a recipient token holding account.
|
||||
/// Uses ATA PDA seeds to authorize the chained Token::Transfer call.
|
||||
///
|
||||
/// Required accounts (3):
|
||||
/// - Owner account (authorized)
|
||||
/// - Sender ATA (owner's token holding)
|
||||
/// - Recipient token holding (any account; auto-created if default)
|
||||
/// - Recipient token holding (must be initialized)
|
||||
///
|
||||
/// `token_program_id` is derived from `sender_ata.account.program_owner`.
|
||||
Transfer {
|
||||
|
||||
14
ata/methods/guest/Cargo.lock
generated
14
ata/methods/guest/Cargo.lock
generated
@ -1777,7 +1777,7 @@ checksum = "a5b0c77c1b780822bc749a33e39aeb2c07584ab93332303babeabb645298a76e"
|
||||
[[package]]
|
||||
name = "nssa_core"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/logos-blockchain/logos-execution-zone.git?rev=ffcbc15972adbf557939bf3e2852af276422631b#ffcbc15972adbf557939bf3e2852af276422631b"
|
||||
source = "git+https://github.com/logos-blockchain/logos-execution-zone.git?tag=v0.2.0-rc1#35d8df0d031315219f94d1546ceb862b0e5b208f"
|
||||
dependencies = [
|
||||
"base58",
|
||||
"borsh",
|
||||
@ -2896,8 +2896,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "spel-framework"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/logos-co/spel.git?rev=57201f64b4542bb3f592bc9a0aa654c47aa908a6#57201f64b4542bb3f592bc9a0aa654c47aa908a6"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/logos-co/spel.git?tag=v0.2.0-rc.2#9005e9fbbd78b0530412f9987273f753ed32eb2d"
|
||||
dependencies = [
|
||||
"borsh",
|
||||
"nssa_core",
|
||||
@ -2907,8 +2907,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "spel-framework-core"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/logos-co/spel.git?rev=57201f64b4542bb3f592bc9a0aa654c47aa908a6#57201f64b4542bb3f592bc9a0aa654c47aa908a6"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/logos-co/spel.git?tag=v0.2.0-rc.2#9005e9fbbd78b0530412f9987273f753ed32eb2d"
|
||||
dependencies = [
|
||||
"borsh",
|
||||
"nssa_core",
|
||||
@ -2920,8 +2920,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "spel-framework-macros"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/logos-co/spel.git?rev=57201f64b4542bb3f592bc9a0aa654c47aa908a6#57201f64b4542bb3f592bc9a0aa654c47aa908a6"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/logos-co/spel.git?tag=v0.2.0-rc.2#9005e9fbbd78b0530412f9987273f753ed32eb2d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
||||
@ -10,8 +10,8 @@ name = "ata"
|
||||
path = "src/bin/ata.rs"
|
||||
|
||||
[dependencies]
|
||||
spel-framework = { git = "https://github.com/logos-co/spel.git", rev = "57201f64b4542bb3f592bc9a0aa654c47aa908a6", package = "spel-framework" }
|
||||
nssa_core = { git = "https://github.com/logos-blockchain/logos-execution-zone.git", rev = "ffcbc15972adbf557939bf3e2852af276422631b" }
|
||||
spel-framework = { git = "https://github.com/logos-co/spel.git", tag = "v0.2.0-rc.2", package = "spel-framework" }
|
||||
nssa_core = { git = "https://github.com/logos-blockchain/logos-execution-zone.git", tag = "v0.2.0-rc1" }
|
||||
risc0-zkvm = { version = "=3.0.5", default-features = false }
|
||||
ata_core = { path = "../../core" }
|
||||
ata_program = { path = "../..", package = "ata_program" }
|
||||
|
||||
@ -28,7 +28,8 @@ mod ata {
|
||||
Ok(SpelOutput::with_chained_calls(post_states, chained_calls))
|
||||
}
|
||||
|
||||
/// Transfer tokens FROM owner's ATA to a recipient holding account.
|
||||
/// Transfer tokens FROM owner's ATA to a recipient token holding account.
|
||||
/// The recipient holding account must already be initialized.
|
||||
#[instruction]
|
||||
pub fn transfer(
|
||||
owner: AccountWithMetadata,
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
use nssa_core::{
|
||||
account::{Account, AccountWithMetadata},
|
||||
program::{AccountPostState, ChainedCall, ProgramId},
|
||||
program::{AccountPostState, ChainedCall, Claim, ProgramId},
|
||||
};
|
||||
|
||||
pub fn create_associated_token_account(
|
||||
@ -9,9 +9,12 @@ pub fn create_associated_token_account(
|
||||
ata_account: AccountWithMetadata,
|
||||
ata_program_id: ProgramId,
|
||||
) -> (Vec<AccountPostState>, Vec<ChainedCall>) {
|
||||
// No authorization check needed: create is idempotent, so anyone can call it safely.
|
||||
// No explicit owner authorization check is needed here: ATA creation is idempotent, so the
|
||||
// call itself may proceed without `owner.is_authorized`. If the owner account is still
|
||||
// default, the returned post-state will still carry `Claim::Authorized` so the runtime can
|
||||
// claim that owner account when needed.
|
||||
let token_program_id = token_definition.account.program_owner;
|
||||
ata_core::verify_ata_and_get_seed(
|
||||
let seed = ata_core::verify_ata_and_get_seed(
|
||||
&ata_account,
|
||||
&owner,
|
||||
token_definition.account_id,
|
||||
@ -22,7 +25,7 @@ pub fn create_associated_token_account(
|
||||
if ata_account.account != Account::default() {
|
||||
return (
|
||||
vec![
|
||||
AccountPostState::new_claimed_if_default(owner.account.clone()),
|
||||
AccountPostState::new_claimed_if_default(owner.account.clone(), Claim::Authorized),
|
||||
AccountPostState::new(token_definition.account.clone()),
|
||||
AccountPostState::new(ata_account.account.clone()),
|
||||
],
|
||||
@ -31,14 +34,17 @@ pub fn create_associated_token_account(
|
||||
}
|
||||
|
||||
let post_states = vec![
|
||||
AccountPostState::new_claimed_if_default(owner.account.clone()),
|
||||
AccountPostState::new_claimed_if_default(owner.account.clone(), Claim::Authorized),
|
||||
AccountPostState::new(token_definition.account.clone()),
|
||||
AccountPostState::new(ata_account.account.clone()),
|
||||
];
|
||||
let mut ata_account_auth = ata_account.clone();
|
||||
ata_account_auth.is_authorized = true;
|
||||
let chained_call = ChainedCall::new(
|
||||
token_program_id,
|
||||
vec![token_definition.clone(), ata_account.clone()],
|
||||
vec![token_definition.clone(), ata_account_auth],
|
||||
&token_core::Instruction::InitializeAccount,
|
||||
);
|
||||
)
|
||||
.with_pda_seeds(vec![seed]);
|
||||
(post_states, vec![chained_call])
|
||||
}
|
||||
|
||||
@ -1,5 +1,8 @@
|
||||
use ata_core::{compute_ata_seed, get_associated_token_account_id};
|
||||
use nssa_core::account::{Account, AccountId, AccountWithMetadata, Data};
|
||||
use nssa_core::{
|
||||
account::{Account, AccountId, AccountWithMetadata, Data},
|
||||
program::{ChainedCall, Claim},
|
||||
};
|
||||
use token_core::{TokenDefinition, TokenHolding};
|
||||
|
||||
const ATA_PROGRAM_ID: nssa_core::program::ProgramId = [1u32; 8];
|
||||
@ -79,8 +82,18 @@ fn create_emits_chained_call_for_uninitialized_ata() {
|
||||
);
|
||||
|
||||
assert_eq!(post_states.len(), 3);
|
||||
assert_eq!(chained_calls.len(), 1);
|
||||
assert_eq!(chained_calls[0].program_id, TOKEN_PROGRAM_ID);
|
||||
assert_eq!(post_states[0].required_claim(), Some(Claim::Authorized));
|
||||
|
||||
let mut authorized_ata = uninitialized_ata_account();
|
||||
authorized_ata.is_authorized = true;
|
||||
let expected_call = ChainedCall::new(
|
||||
TOKEN_PROGRAM_ID,
|
||||
vec![definition_account(), authorized_ata],
|
||||
&token_core::Instruction::InitializeAccount,
|
||||
)
|
||||
.with_pda_seeds(vec![compute_ata_seed(owner_id(), definition_id())]);
|
||||
|
||||
assert_eq!(chained_calls, vec![expected_call]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@ -16,7 +16,7 @@ pub fn transfer_from_associated_token_account(
|
||||
let definition_id = TokenHolding::try_from(&sender_ata.account.data)
|
||||
.expect("Sender ATA must hold a valid token")
|
||||
.definition_id();
|
||||
let seed =
|
||||
let sender_seed =
|
||||
ata_core::verify_ata_and_get_seed(&sender_ata, &owner, definition_id, ata_program_id);
|
||||
|
||||
let post_states = vec![
|
||||
@ -29,11 +29,11 @@ pub fn transfer_from_associated_token_account(
|
||||
|
||||
let chained_call = ChainedCall::new(
|
||||
token_program_id,
|
||||
vec![sender_ata_auth, recipient.clone()],
|
||||
vec![sender_ata_auth, recipient],
|
||||
&token_core::Instruction::Transfer {
|
||||
amount_to_transfer: amount,
|
||||
},
|
||||
)
|
||||
.with_pda_seeds(vec![seed]);
|
||||
.with_pda_seeds(vec![sender_seed]);
|
||||
(post_states, vec![chained_call])
|
||||
}
|
||||
|
||||
@ -809,6 +809,18 @@ impl Accounts {
|
||||
}
|
||||
|
||||
fn user_lp_holding_new_init() -> Account {
|
||||
Account {
|
||||
program_owner: Ids::token_program(),
|
||||
balance: 0_u128,
|
||||
data: Data::from(&TokenHolding::Fungible {
|
||||
definition_id: Ids::token_lp_definition(),
|
||||
balance: Balances::lp_user_init(),
|
||||
}),
|
||||
nonce: Nonce(1),
|
||||
}
|
||||
}
|
||||
|
||||
fn user_lp_holding_new_init_precreated() -> Account {
|
||||
Account {
|
||||
program_owner: Ids::token_program(),
|
||||
balance: 0_u128,
|
||||
@ -895,7 +907,7 @@ fn deploy_programs(state: &mut V03State) {
|
||||
}
|
||||
|
||||
fn state_for_amm_tests() -> V03State {
|
||||
let mut state = V03State::new_with_genesis_accounts(&[], &[]);
|
||||
let mut state = V03State::new_with_genesis_accounts(&[], &[], 0);
|
||||
deploy_programs(&mut state);
|
||||
state.force_insert_account(Ids::pool_definition(), Accounts::pool_definition_init());
|
||||
state.force_insert_account(
|
||||
@ -919,7 +931,7 @@ fn state_for_amm_tests() -> V03State {
|
||||
}
|
||||
|
||||
fn state_for_amm_tests_with_new_def() -> V03State {
|
||||
let mut state = V03State::new_with_genesis_accounts(&[], &[]);
|
||||
let mut state = V03State::new_with_genesis_accounts(&[], &[], 0);
|
||||
deploy_programs(&mut state);
|
||||
state.force_insert_account(
|
||||
Ids::token_a_definition(),
|
||||
@ -938,7 +950,17 @@ fn current_nonce(state: &V03State, account_id: AccountId) -> Nonce {
|
||||
state.get_account_by_id(account_id).nonce
|
||||
}
|
||||
|
||||
fn try_execute_new_definition(state: &mut V03State, fees: u128) -> Result<(), NssaError> {
|
||||
fn state_for_amm_tests_with_precreated_user_lp_for_new_def() -> V03State {
|
||||
let mut state = state_for_amm_tests_with_new_def();
|
||||
state.force_insert_account(Ids::user_lp(), Accounts::user_lp_holding_init_zero());
|
||||
state
|
||||
}
|
||||
|
||||
fn try_execute_new_definition(
|
||||
state: &mut V03State,
|
||||
fees: u128,
|
||||
authorize_user_lp: bool,
|
||||
) -> Result<(), NssaError> {
|
||||
let instruction = amm_core::Instruction::NewDefinition {
|
||||
token_a_amount: Balances::vault_a_init(),
|
||||
token_b_amount: Balances::vault_b_init(),
|
||||
@ -958,23 +980,37 @@ fn try_execute_new_definition(state: &mut V03State, fees: u128) -> Result<(), Ns
|
||||
Ids::user_b(),
|
||||
Ids::user_lp(),
|
||||
],
|
||||
vec![
|
||||
current_nonce(state, Ids::user_a()),
|
||||
current_nonce(state, Ids::user_b()),
|
||||
],
|
||||
if authorize_user_lp {
|
||||
vec![
|
||||
current_nonce(state, Ids::user_a()),
|
||||
current_nonce(state, Ids::user_b()),
|
||||
current_nonce(state, Ids::user_lp()),
|
||||
]
|
||||
} else {
|
||||
vec![
|
||||
current_nonce(state, Ids::user_a()),
|
||||
current_nonce(state, Ids::user_b()),
|
||||
]
|
||||
},
|
||||
instruction,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let witness_set =
|
||||
public_transaction::WitnessSet::for_message(&message, &[&Keys::user_a(), &Keys::user_b()]);
|
||||
let witness_set = if authorize_user_lp {
|
||||
public_transaction::WitnessSet::for_message(
|
||||
&message,
|
||||
&[&Keys::user_a(), &Keys::user_b(), &Keys::user_lp()],
|
||||
)
|
||||
} else {
|
||||
public_transaction::WitnessSet::for_message(&message, &[&Keys::user_a(), &Keys::user_b()])
|
||||
};
|
||||
|
||||
let tx = PublicTransaction::new(message, witness_set);
|
||||
state.transition_from_public_transaction(&tx, 0)
|
||||
state.transition_from_public_transaction(&tx, 0, 0)
|
||||
}
|
||||
|
||||
fn execute_new_definition(state: &mut V03State, fees: u128) {
|
||||
try_execute_new_definition(state, fees).unwrap();
|
||||
try_execute_new_definition(state, fees, true).unwrap();
|
||||
}
|
||||
|
||||
fn execute_swap_a_to_b(state: &mut V03State, swap_amount_in: u128, min_amount_out: u128) {
|
||||
@ -1001,7 +1037,7 @@ fn execute_swap_a_to_b(state: &mut V03State, swap_amount_in: u128, min_amount_ou
|
||||
let witness_set = public_transaction::WitnessSet::for_message(&message, &[&Keys::user_a()]);
|
||||
|
||||
let tx = PublicTransaction::new(message, witness_set);
|
||||
state.transition_from_public_transaction(&tx, 0).unwrap();
|
||||
state.transition_from_public_transaction(&tx, 0, 0).unwrap();
|
||||
}
|
||||
|
||||
fn execute_swap_b_to_a(state: &mut V03State, swap_amount_in: u128, min_amount_out: u128) {
|
||||
@ -1028,7 +1064,7 @@ fn execute_swap_b_to_a(state: &mut V03State, swap_amount_in: u128, min_amount_ou
|
||||
let witness_set = public_transaction::WitnessSet::for_message(&message, &[&Keys::user_b()]);
|
||||
|
||||
let tx = PublicTransaction::new(message, witness_set);
|
||||
state.transition_from_public_transaction(&tx, 0).unwrap();
|
||||
state.transition_from_public_transaction(&tx, 0, 0).unwrap();
|
||||
}
|
||||
|
||||
fn execute_add_liquidity(
|
||||
@ -1066,7 +1102,7 @@ fn execute_add_liquidity(
|
||||
public_transaction::WitnessSet::for_message(&message, &[&Keys::user_a(), &Keys::user_b()]);
|
||||
|
||||
let tx = PublicTransaction::new(message, witness_set);
|
||||
state.transition_from_public_transaction(&tx, 0).unwrap();
|
||||
state.transition_from_public_transaction(&tx, 0, 0).unwrap();
|
||||
}
|
||||
|
||||
fn execute_remove_liquidity(
|
||||
@ -1100,7 +1136,7 @@ fn execute_remove_liquidity(
|
||||
let witness_set = public_transaction::WitnessSet::for_message(&message, &[&Keys::user_lp()]);
|
||||
|
||||
let tx = PublicTransaction::new(message, witness_set);
|
||||
state.transition_from_public_transaction(&tx, 0).unwrap();
|
||||
state.transition_from_public_transaction(&tx, 0, 0).unwrap();
|
||||
}
|
||||
|
||||
fn fungible_balance(account: &Account) -> u128 {
|
||||
@ -1163,7 +1199,7 @@ fn amm_remove_liquidity() {
|
||||
let witness_set = public_transaction::WitnessSet::for_message(&message, &[&Keys::user_lp()]);
|
||||
|
||||
let tx = PublicTransaction::new(message, witness_set);
|
||||
state.transition_from_public_transaction(&tx, 0).unwrap();
|
||||
state.transition_from_public_transaction(&tx, 0, 0).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
state.get_account_by_id(Ids::pool_definition()),
|
||||
@ -1225,7 +1261,7 @@ fn amm_remove_liquidity_insufficient_user_lp_fails() {
|
||||
let witness_set = public_transaction::WitnessSet::for_message(&message, &[&Keys::user_lp()]);
|
||||
|
||||
let tx = PublicTransaction::new(message, witness_set);
|
||||
assert!(state.transition_from_public_transaction(&tx, 0).is_err());
|
||||
assert!(state.transition_from_public_transaction(&tx, 0, 0).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -1270,6 +1306,88 @@ fn amm_new_definition_uninitialized_pool() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn amm_new_definition_without_user_lp_authorization_fails() {
|
||||
let mut state = state_for_amm_tests_with_new_def();
|
||||
state.force_insert_account(Ids::vault_a(), Accounts::vault_a_reinitializable());
|
||||
state.force_insert_account(Ids::vault_b(), Accounts::vault_b_reinitializable());
|
||||
|
||||
let result = try_execute_new_definition(&mut state, Balances::fee_tier(), false);
|
||||
|
||||
assert!(matches!(result, Err(NssaError::ProgramExecutionFailed(_))));
|
||||
assert_eq!(
|
||||
state.get_account_by_id(Ids::pool_definition()),
|
||||
Account::default()
|
||||
);
|
||||
assert_eq!(
|
||||
state.get_account_by_id(Ids::vault_a()),
|
||||
Accounts::vault_a_reinitializable()
|
||||
);
|
||||
assert_eq!(
|
||||
state.get_account_by_id(Ids::vault_b()),
|
||||
Accounts::vault_b_reinitializable()
|
||||
);
|
||||
assert_eq!(
|
||||
state.get_account_by_id(Ids::token_lp_definition()),
|
||||
Account::default()
|
||||
);
|
||||
assert_eq!(
|
||||
state.get_account_by_id(Ids::lp_lock_holding()),
|
||||
Account::default()
|
||||
);
|
||||
assert_eq!(
|
||||
state.get_account_by_id(Ids::user_a()),
|
||||
Accounts::user_a_holding()
|
||||
);
|
||||
assert_eq!(
|
||||
state.get_account_by_id(Ids::user_b()),
|
||||
Accounts::user_b_holding()
|
||||
);
|
||||
assert_eq!(state.get_account_by_id(Ids::user_lp()), Account::default());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn amm_new_definition_precreated_zero_balance_user_lp() {
|
||||
let mut state = state_for_amm_tests_with_precreated_user_lp_for_new_def();
|
||||
state.force_insert_account(Ids::vault_a(), Accounts::vault_a_reinitializable());
|
||||
state.force_insert_account(Ids::vault_b(), Accounts::vault_b_reinitializable());
|
||||
|
||||
try_execute_new_definition(&mut state, Balances::fee_tier(), false).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
state.get_account_by_id(Ids::pool_definition()),
|
||||
Accounts::pool_definition_new_init()
|
||||
);
|
||||
assert_eq!(
|
||||
state.get_account_by_id(Ids::vault_a()),
|
||||
Accounts::vault_a_init()
|
||||
);
|
||||
assert_eq!(
|
||||
state.get_account_by_id(Ids::vault_b()),
|
||||
Accounts::vault_b_init()
|
||||
);
|
||||
assert_eq!(
|
||||
state.get_account_by_id(Ids::token_lp_definition()),
|
||||
Accounts::token_lp_definition_new_init()
|
||||
);
|
||||
assert_eq!(
|
||||
state.get_account_by_id(Ids::lp_lock_holding()),
|
||||
Accounts::lp_lock_holding_new_init()
|
||||
);
|
||||
assert_eq!(
|
||||
state.get_account_by_id(Ids::user_a()),
|
||||
Accounts::user_a_holding_new_init()
|
||||
);
|
||||
assert_eq!(
|
||||
state.get_account_by_id(Ids::user_b()),
|
||||
Accounts::user_b_holding_new_init()
|
||||
);
|
||||
assert_eq!(
|
||||
state.get_account_by_id(Ids::user_lp()),
|
||||
Accounts::user_lp_holding_new_init_precreated()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn amm_new_definition_supports_all_fee_tiers() {
|
||||
for fees in [
|
||||
@ -1293,7 +1411,7 @@ fn amm_new_definition_supports_all_fee_tiers() {
|
||||
|
||||
#[test]
|
||||
fn amm_new_definition_rejects_unsupported_fee_tier_transaction() {
|
||||
let mut state = state_for_amm_tests_with_new_def();
|
||||
let mut state = state_for_amm_tests_with_precreated_user_lp_for_new_def();
|
||||
state.force_insert_account(Ids::vault_a(), Accounts::vault_a_reinitializable());
|
||||
state.force_insert_account(Ids::vault_b(), Accounts::vault_b_reinitializable());
|
||||
state.force_insert_account(
|
||||
@ -1304,9 +1422,8 @@ fn amm_new_definition_rejects_unsupported_fee_tier_transaction() {
|
||||
Ids::token_lp_definition(),
|
||||
Accounts::token_lp_definition_reinitializable(),
|
||||
);
|
||||
state.force_insert_account(Ids::user_lp(), Accounts::user_lp_holding_init_zero());
|
||||
|
||||
let result = try_execute_new_definition(&mut state, 2);
|
||||
let result = try_execute_new_definition(&mut state, 2, false);
|
||||
|
||||
assert!(matches!(result, Err(NssaError::ProgramExecutionFailed(_))));
|
||||
assert_eq!(
|
||||
@ -1369,7 +1486,7 @@ fn amm_add_liquidity() {
|
||||
public_transaction::WitnessSet::for_message(&message, &[&Keys::user_a(), &Keys::user_b()]);
|
||||
|
||||
let tx = PublicTransaction::new(message, witness_set);
|
||||
state.transition_from_public_transaction(&tx, 0).unwrap();
|
||||
state.transition_from_public_transaction(&tx, 0, 0).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
state.get_account_by_id(Ids::pool_definition()),
|
||||
@ -1428,7 +1545,7 @@ fn amm_swap_b_to_a() {
|
||||
let witness_set = public_transaction::WitnessSet::for_message(&message, &[&Keys::user_b()]);
|
||||
|
||||
let tx = PublicTransaction::new(message, witness_set);
|
||||
state.transition_from_public_transaction(&tx, 0).unwrap();
|
||||
state.transition_from_public_transaction(&tx, 0, 0).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
state.get_account_by_id(Ids::pool_definition()),
|
||||
@ -1479,7 +1596,7 @@ fn amm_swap_a_to_b() {
|
||||
let witness_set = public_transaction::WitnessSet::for_message(&message, &[&Keys::user_a()]);
|
||||
|
||||
let tx = PublicTransaction::new(message, witness_set);
|
||||
state.transition_from_public_transaction(&tx, 0).unwrap();
|
||||
state.transition_from_public_transaction(&tx, 0, 0).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
state.get_account_by_id(Ids::pool_definition()),
|
||||
|
||||
@ -93,6 +93,18 @@ impl Accounts {
|
||||
nonce: Nonce(0),
|
||||
}
|
||||
}
|
||||
|
||||
fn recipient_ata_init() -> Account {
|
||||
Account {
|
||||
program_owner: Ids::token_program(),
|
||||
balance: 0_u128,
|
||||
data: Data::from(&TokenHolding::Fungible {
|
||||
definition_id: Ids::token_definition(),
|
||||
balance: 0_u128,
|
||||
}),
|
||||
nonce: Nonce(0),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn deploy_programs(state: &mut V03State) {
|
||||
@ -113,16 +125,22 @@ fn deploy_programs(state: &mut V03State) {
|
||||
}
|
||||
|
||||
fn state_for_ata_tests() -> V03State {
|
||||
let mut state = V03State::new_with_genesis_accounts(&[], &[]);
|
||||
let mut state = V03State::new_with_genesis_accounts(&[], &[], 0);
|
||||
deploy_programs(&mut state);
|
||||
state.force_insert_account(Ids::token_definition(), Accounts::token_definition_init());
|
||||
state.force_insert_account(Ids::owner_ata(), Accounts::owner_ata_init());
|
||||
state
|
||||
}
|
||||
|
||||
fn state_for_ata_tests_with_precreated_recipient_ata() -> V03State {
|
||||
let mut state = state_for_ata_tests();
|
||||
state.force_insert_account(Ids::recipient_ata(), Accounts::recipient_ata_init());
|
||||
state
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ata_create() {
|
||||
let mut state = V03State::new_with_genesis_accounts(&[], &[]);
|
||||
let mut state = V03State::new_with_genesis_accounts(&[], &[], 0);
|
||||
deploy_programs(&mut state);
|
||||
state.force_insert_account(Ids::token_definition(), Accounts::token_definition_init());
|
||||
|
||||
@ -141,7 +159,7 @@ fn ata_create() {
|
||||
let witness_set = public_transaction::WitnessSet::for_message(&message, &[&Keys::owner_key()]);
|
||||
|
||||
let tx = PublicTransaction::new(message, witness_set);
|
||||
state.transition_from_public_transaction(&tx, 0).unwrap();
|
||||
state.transition_from_public_transaction(&tx, 0, 0).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
state.get_account_by_id(Ids::owner_ata()),
|
||||
@ -176,7 +194,7 @@ fn ata_create_is_idempotent() {
|
||||
let witness_set = public_transaction::WitnessSet::for_message(&message, &[&Keys::owner_key()]);
|
||||
|
||||
let tx = PublicTransaction::new(message, witness_set);
|
||||
state.transition_from_public_transaction(&tx, 0).unwrap();
|
||||
state.transition_from_public_transaction(&tx, 0, 0).unwrap();
|
||||
|
||||
// Already initialized — should remain unchanged
|
||||
assert_eq!(
|
||||
@ -195,7 +213,7 @@ fn ata_create_is_idempotent() {
|
||||
|
||||
#[test]
|
||||
fn ata_transfer() {
|
||||
let mut state = state_for_ata_tests();
|
||||
let mut state = state_for_ata_tests_with_precreated_recipient_ata();
|
||||
|
||||
let instruction = ata_core::Instruction::Transfer {
|
||||
ata_program_id: Ids::ata_program(),
|
||||
@ -213,7 +231,7 @@ fn ata_transfer() {
|
||||
let witness_set = public_transaction::WitnessSet::for_message(&message, &[&Keys::owner_key()]);
|
||||
|
||||
let tx = PublicTransaction::new(message, witness_set);
|
||||
state.transition_from_public_transaction(&tx, 0).unwrap();
|
||||
state.transition_from_public_transaction(&tx, 0, 0).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
state.get_account_by_id(Ids::owner_ata()),
|
||||
@ -262,7 +280,7 @@ fn ata_burn() {
|
||||
let witness_set = public_transaction::WitnessSet::for_message(&message, &[&Keys::owner_key()]);
|
||||
|
||||
let tx = PublicTransaction::new(message, witness_set);
|
||||
state.transition_from_public_transaction(&tx, 0).unwrap();
|
||||
state.transition_from_public_transaction(&tx, 0, 0).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
state.get_account_by_id(Ids::owner_ata()),
|
||||
@ -294,7 +312,7 @@ fn ata_burn() {
|
||||
|
||||
#[test]
|
||||
fn ata_create_from_private_owner() {
|
||||
let mut state = V03State::new_with_genesis_accounts(&[], &[]);
|
||||
let mut state = V03State::new_with_genesis_accounts(&[], &[], 0);
|
||||
deploy_programs(&mut state);
|
||||
state.force_insert_account(Ids::token_definition(), Accounts::token_definition_init());
|
||||
|
||||
@ -359,7 +377,7 @@ fn ata_create_from_private_owner() {
|
||||
let witness_set = WitnessSet::for_message(&message, proof, &[]);
|
||||
let tx = PrivacyPreservingTransaction::new(message, witness_set);
|
||||
state
|
||||
.transition_from_privacy_preserving_transaction(&tx, 0)
|
||||
.transition_from_privacy_preserving_transaction(&tx, 0, 0)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
|
||||
@ -74,6 +74,18 @@ impl Accounts {
|
||||
nonce: Nonce(0),
|
||||
}
|
||||
}
|
||||
|
||||
fn recipient_init() -> Account {
|
||||
Account {
|
||||
program_owner: Ids::token_program(),
|
||||
balance: 0_u128,
|
||||
data: Data::from(&TokenHolding::Fungible {
|
||||
definition_id: Ids::token_definition(),
|
||||
balance: 0_u128,
|
||||
}),
|
||||
nonce: Nonce(0),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn deploy_token(state: &mut V03State) {
|
||||
@ -85,7 +97,16 @@ fn deploy_token(state: &mut V03State) {
|
||||
}
|
||||
|
||||
fn state_for_token_tests() -> V03State {
|
||||
let mut state = V03State::new_with_genesis_accounts(&[], &[]);
|
||||
let mut state = V03State::new_with_genesis_accounts(&[], &[], 0);
|
||||
deploy_token(&mut state);
|
||||
state.force_insert_account(Ids::token_definition(), Accounts::token_definition_init());
|
||||
state.force_insert_account(Ids::holder(), Accounts::holder_init());
|
||||
state.force_insert_account(Ids::recipient(), Accounts::recipient_init());
|
||||
state
|
||||
}
|
||||
|
||||
fn state_for_token_tests_without_recipient() -> V03State {
|
||||
let mut state = V03State::new_with_genesis_accounts(&[], &[], 0);
|
||||
deploy_token(&mut state);
|
||||
state.force_insert_account(Ids::token_definition(), Accounts::token_definition_init());
|
||||
state.force_insert_account(Ids::holder(), Accounts::holder_init());
|
||||
@ -94,7 +115,7 @@ fn state_for_token_tests() -> V03State {
|
||||
|
||||
#[test]
|
||||
fn token_new_fungible_definition() {
|
||||
let mut state = V03State::new_with_genesis_accounts(&[], &[]);
|
||||
let mut state = V03State::new_with_genesis_accounts(&[], &[], 0);
|
||||
deploy_token(&mut state);
|
||||
|
||||
let instruction = token_core::Instruction::NewFungibleDefinition {
|
||||
@ -116,7 +137,7 @@ fn token_new_fungible_definition() {
|
||||
);
|
||||
|
||||
let tx = PublicTransaction::new(message, witness_set);
|
||||
state.transition_from_public_transaction(&tx, 0).unwrap();
|
||||
state.transition_from_public_transaction(&tx, 0, 0).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
state.get_account_by_id(Ids::token_definition()),
|
||||
@ -165,7 +186,7 @@ fn token_transfer() {
|
||||
let witness_set = public_transaction::WitnessSet::for_message(&message, &[&Keys::holder_key()]);
|
||||
|
||||
let tx = PublicTransaction::new(message, witness_set);
|
||||
state.transition_from_public_transaction(&tx, 0).unwrap();
|
||||
state.transition_from_public_transaction(&tx, 0, 0).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
state.get_account_by_id(Ids::holder()),
|
||||
@ -194,6 +215,88 @@ fn token_transfer() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn token_transfer_fresh_public_recipient_requires_authorization() {
|
||||
let mut state = state_for_token_tests_without_recipient();
|
||||
|
||||
let instruction = token_core::Instruction::Transfer {
|
||||
amount_to_transfer: 500_000_u128,
|
||||
};
|
||||
|
||||
let message = public_transaction::Message::try_new(
|
||||
Ids::token_program(),
|
||||
vec![Ids::holder(), Ids::recipient()],
|
||||
vec![Nonce(0)],
|
||||
instruction,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let witness_set = public_transaction::WitnessSet::for_message(&message, &[&Keys::holder_key()]);
|
||||
|
||||
let tx = PublicTransaction::new(message, witness_set);
|
||||
assert!(state.transition_from_public_transaction(&tx, 0, 0).is_err());
|
||||
|
||||
assert_eq!(
|
||||
state.get_account_by_id(Ids::holder()),
|
||||
Accounts::holder_init()
|
||||
);
|
||||
assert_eq!(
|
||||
state.get_account_by_id(Ids::recipient()),
|
||||
Account::default()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn token_transfer_fresh_authorized_public_recipient() {
|
||||
let mut state = state_for_token_tests_without_recipient();
|
||||
|
||||
let instruction = token_core::Instruction::Transfer {
|
||||
amount_to_transfer: 500_000_u128,
|
||||
};
|
||||
|
||||
let message = public_transaction::Message::try_new(
|
||||
Ids::token_program(),
|
||||
vec![Ids::holder(), Ids::recipient()],
|
||||
vec![Nonce(0), Nonce(0)],
|
||||
instruction,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let witness_set = public_transaction::WitnessSet::for_message(
|
||||
&message,
|
||||
&[&Keys::holder_key(), &Keys::recipient_key()],
|
||||
);
|
||||
|
||||
let tx = PublicTransaction::new(message, witness_set);
|
||||
state.transition_from_public_transaction(&tx, 0, 0).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
state.get_account_by_id(Ids::holder()),
|
||||
Account {
|
||||
program_owner: Ids::token_program(),
|
||||
balance: 0_u128,
|
||||
data: Data::from(&TokenHolding::Fungible {
|
||||
definition_id: Ids::token_definition(),
|
||||
balance: 500_000_u128,
|
||||
}),
|
||||
nonce: Nonce(1),
|
||||
}
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
state.get_account_by_id(Ids::recipient()),
|
||||
Account {
|
||||
program_owner: Ids::token_program(),
|
||||
balance: 0_u128,
|
||||
data: Data::from(&TokenHolding::Fungible {
|
||||
definition_id: Ids::token_definition(),
|
||||
balance: 500_000_u128,
|
||||
}),
|
||||
nonce: Nonce(1),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn token_burn() {
|
||||
let mut state = state_for_token_tests();
|
||||
@ -213,7 +316,7 @@ fn token_burn() {
|
||||
let witness_set = public_transaction::WitnessSet::for_message(&message, &[&Keys::holder_key()]);
|
||||
|
||||
let tx = PublicTransaction::new(message, witness_set);
|
||||
state.transition_from_public_transaction(&tx, 0).unwrap();
|
||||
state.transition_from_public_transaction(&tx, 0, 0).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
state.get_account_by_id(Ids::token_definition()),
|
||||
@ -262,7 +365,7 @@ fn token_mint() {
|
||||
let witness_set = public_transaction::WitnessSet::for_message(&message, &[&Keys::def_key()]);
|
||||
|
||||
let tx = PublicTransaction::new(message, witness_set);
|
||||
state.transition_from_public_transaction(&tx, 0).unwrap();
|
||||
state.transition_from_public_transaction(&tx, 0, 0).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
state.get_account_by_id(Ids::token_definition()),
|
||||
@ -292,6 +395,89 @@ fn token_mint() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn token_mint_fresh_public_recipient_requires_authorization() {
|
||||
let mut state = state_for_token_tests_without_recipient();
|
||||
|
||||
let instruction = token_core::Instruction::Mint {
|
||||
amount_to_mint: 500_000_u128,
|
||||
};
|
||||
|
||||
let message = public_transaction::Message::try_new(
|
||||
Ids::token_program(),
|
||||
vec![Ids::token_definition(), Ids::recipient()],
|
||||
vec![Nonce(0)],
|
||||
instruction,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let witness_set = public_transaction::WitnessSet::for_message(&message, &[&Keys::def_key()]);
|
||||
|
||||
let tx = PublicTransaction::new(message, witness_set);
|
||||
assert!(state.transition_from_public_transaction(&tx, 0, 0).is_err());
|
||||
|
||||
assert_eq!(
|
||||
state.get_account_by_id(Ids::token_definition()),
|
||||
Accounts::token_definition_init()
|
||||
);
|
||||
assert_eq!(
|
||||
state.get_account_by_id(Ids::recipient()),
|
||||
Account::default()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn token_mint_fresh_authorized_public_recipient() {
|
||||
let mut state = state_for_token_tests_without_recipient();
|
||||
|
||||
let instruction = token_core::Instruction::Mint {
|
||||
amount_to_mint: 500_000_u128,
|
||||
};
|
||||
|
||||
let message = public_transaction::Message::try_new(
|
||||
Ids::token_program(),
|
||||
vec![Ids::token_definition(), Ids::recipient()],
|
||||
vec![Nonce(0), Nonce(0)],
|
||||
instruction,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let witness_set = public_transaction::WitnessSet::for_message(
|
||||
&message,
|
||||
&[&Keys::def_key(), &Keys::recipient_key()],
|
||||
);
|
||||
|
||||
let tx = PublicTransaction::new(message, witness_set);
|
||||
state.transition_from_public_transaction(&tx, 0, 0).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
state.get_account_by_id(Ids::token_definition()),
|
||||
Account {
|
||||
program_owner: Ids::token_program(),
|
||||
balance: 0_u128,
|
||||
data: Data::from(&TokenDefinition::Fungible {
|
||||
name: String::from("Gold"),
|
||||
total_supply: 1_500_000_u128,
|
||||
metadata_id: None,
|
||||
}),
|
||||
nonce: Nonce(1),
|
||||
}
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
state.get_account_by_id(Ids::recipient()),
|
||||
Account {
|
||||
program_owner: Ids::token_program(),
|
||||
balance: 0_u128,
|
||||
data: Data::from(&TokenHolding::Fungible {
|
||||
definition_id: Ids::token_definition(),
|
||||
balance: 500_000_u128,
|
||||
}),
|
||||
nonce: Nonce(1),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
struct PrivateKeys;
|
||||
|
||||
impl PrivateKeys {
|
||||
@ -377,7 +563,7 @@ fn shielded_token_transfer(amount: u128, state: &mut V03State) -> Account {
|
||||
let witness_set = WitnessSet::for_message(&message, proof, &[&Keys::holder_key()]);
|
||||
let tx = PrivacyPreservingTransaction::new(message, witness_set);
|
||||
state
|
||||
.transition_from_privacy_preserving_transaction(&tx, 0)
|
||||
.transition_from_privacy_preserving_transaction(&tx, 0, 0)
|
||||
.unwrap();
|
||||
|
||||
Account {
|
||||
@ -476,7 +662,7 @@ fn token_private_transfer() {
|
||||
let witness_set = WitnessSet::for_message(&message, proof, &[]);
|
||||
let tx = PrivacyPreservingTransaction::new(message, witness_set);
|
||||
state
|
||||
.transition_from_privacy_preserving_transaction(&tx, 0)
|
||||
.transition_from_privacy_preserving_transaction(&tx, 0, 0)
|
||||
.unwrap();
|
||||
|
||||
let sender_nonce_after =
|
||||
@ -559,7 +745,7 @@ fn token_deshielded_transfer() {
|
||||
let witness_set = WitnessSet::for_message(&message, proof, &[]);
|
||||
let tx = PrivacyPreservingTransaction::new(message, witness_set);
|
||||
state
|
||||
.transition_from_privacy_preserving_transaction(&tx, 0)
|
||||
.transition_from_privacy_preserving_transaction(&tx, 0, 0)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
|
||||
@ -4,5 +4,5 @@ version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
nssa_core = { git = "https://github.com/logos-blockchain/logos-execution-zone.git", rev = "ffcbc15972adbf557939bf3e2852af276422631b", features = ["host"] }
|
||||
nssa_core = { git = "https://github.com/logos-blockchain/logos-execution-zone.git", tag = "v0.2.0-rc1", features = ["host"] }
|
||||
token_core = { path = "core" }
|
||||
|
||||
@ -4,6 +4,6 @@ version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
nssa_core = { git = "https://github.com/logos-blockchain/logos-execution-zone.git", rev = "ffcbc15972adbf557939bf3e2852af276422631b", features = ["host"] }
|
||||
nssa_core = { git = "https://github.com/logos-blockchain/logos-execution-zone.git", tag = "v0.2.0-rc1", features = ["host"] }
|
||||
borsh = { version = "1.5", features = ["derive"] }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
|
||||
@ -10,23 +10,24 @@ pub enum Instruction {
|
||||
/// Transfer tokens from sender to recipient.
|
||||
///
|
||||
/// Required accounts:
|
||||
/// - Sender's Token Holding account (authorized),
|
||||
/// - Recipient's Token Holding account.
|
||||
/// - Sender's Token Holding account (initialized, authorized),
|
||||
/// - Recipient's Token Holding account (initialized, or uninitialized with recipient
|
||||
/// authorization in the same transaction).
|
||||
Transfer { amount_to_transfer: u128 },
|
||||
|
||||
/// Create a new fungible token definition without metadata.
|
||||
///
|
||||
/// Required accounts:
|
||||
/// - Token Definition account (uninitialized),
|
||||
/// - Token Holding account (uninitialized).
|
||||
/// - Token Definition account (uninitialized, authorized),
|
||||
/// - Token Holding account (uninitialized, authorized).
|
||||
NewFungibleDefinition { name: String, total_supply: u128 },
|
||||
|
||||
/// Create a new fungible or non-fungible token definition with metadata.
|
||||
///
|
||||
/// Required accounts:
|
||||
/// - Token Definition account (uninitialized),
|
||||
/// - Token Holding account (uninitialized),
|
||||
/// - Token Metadata account (uninitialized).
|
||||
/// - Token Definition account (uninitialized, authorized),
|
||||
/// - Token Holding account (uninitialized, authorized),
|
||||
/// - Token Metadata account (uninitialized, authorized).
|
||||
NewDefinitionWithMetadata {
|
||||
new_definition: NewTokenDefinition,
|
||||
/// Boxed to avoid large enum variant size
|
||||
@ -37,7 +38,7 @@ pub enum Instruction {
|
||||
///
|
||||
/// Required accounts:
|
||||
/// - Token Definition account (initialized),
|
||||
/// - Token Holding account (uninitialized),
|
||||
/// - Token Holding account (uninitialized, authorized),
|
||||
InitializeAccount,
|
||||
|
||||
/// Burn tokens from the holder's account.
|
||||
@ -50,15 +51,16 @@ pub enum Instruction {
|
||||
/// Mint new tokens to the holder's account.
|
||||
///
|
||||
/// Required accounts:
|
||||
/// - Token Definition account (authorized),
|
||||
/// - Token Holding account (uninitialized or initialized).
|
||||
/// - Token Definition account (initialized, authorized),
|
||||
/// - Token Holding account (initialized, or uninitialized with holder authorization in the
|
||||
/// same transaction).
|
||||
Mint { amount_to_mint: u128 },
|
||||
|
||||
/// Print a new NFT from the master copy.
|
||||
///
|
||||
/// Required accounts:
|
||||
/// - NFT Master Token Holding account (authorized),
|
||||
/// - NFT Printed Copy Token Holding account (uninitialized).
|
||||
/// - NFT Printed Copy Token Holding account (uninitialized, authorized).
|
||||
PrintNft,
|
||||
}
|
||||
|
||||
|
||||
14
token/methods/guest/Cargo.lock
generated
14
token/methods/guest/Cargo.lock
generated
@ -1744,7 +1744,7 @@ checksum = "a5b0c77c1b780822bc749a33e39aeb2c07584ab93332303babeabb645298a76e"
|
||||
[[package]]
|
||||
name = "nssa_core"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/logos-blockchain/logos-execution-zone.git?rev=ffcbc15972adbf557939bf3e2852af276422631b#ffcbc15972adbf557939bf3e2852af276422631b"
|
||||
source = "git+https://github.com/logos-blockchain/logos-execution-zone.git?tag=v0.2.0-rc1#35d8df0d031315219f94d1546ceb862b0e5b208f"
|
||||
dependencies = [
|
||||
"base58",
|
||||
"borsh",
|
||||
@ -2863,8 +2863,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "spel-framework"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/logos-co/spel.git?rev=57201f64b4542bb3f592bc9a0aa654c47aa908a6#57201f64b4542bb3f592bc9a0aa654c47aa908a6"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/logos-co/spel.git?tag=v0.2.0-rc.2#9005e9fbbd78b0530412f9987273f753ed32eb2d"
|
||||
dependencies = [
|
||||
"borsh",
|
||||
"nssa_core",
|
||||
@ -2874,8 +2874,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "spel-framework-core"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/logos-co/spel.git?rev=57201f64b4542bb3f592bc9a0aa654c47aa908a6#57201f64b4542bb3f592bc9a0aa654c47aa908a6"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/logos-co/spel.git?tag=v0.2.0-rc.2#9005e9fbbd78b0530412f9987273f753ed32eb2d"
|
||||
dependencies = [
|
||||
"borsh",
|
||||
"nssa_core",
|
||||
@ -2887,8 +2887,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "spel-framework-macros"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/logos-co/spel.git?rev=57201f64b4542bb3f592bc9a0aa654c47aa908a6#57201f64b4542bb3f592bc9a0aa654c47aa908a6"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/logos-co/spel.git?tag=v0.2.0-rc.2#9005e9fbbd78b0530412f9987273f753ed32eb2d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
||||
@ -10,8 +10,8 @@ name = "token"
|
||||
path = "src/bin/token.rs"
|
||||
|
||||
[dependencies]
|
||||
spel-framework = { git = "https://github.com/logos-co/spel.git", rev = "57201f64b4542bb3f592bc9a0aa654c47aa908a6", package = "spel-framework" }
|
||||
nssa_core = { git = "https://github.com/logos-blockchain/logos-execution-zone.git", rev = "ffcbc15972adbf557939bf3e2852af276422631b" }
|
||||
spel-framework = { git = "https://github.com/logos-co/spel.git", tag = "v0.2.0-rc.2", package = "spel-framework" }
|
||||
nssa_core = { git = "https://github.com/logos-blockchain/logos-execution-zone.git", tag = "v0.2.0-rc1" }
|
||||
risc0-zkvm = { version = "=3.0.5", default-features = false }
|
||||
token_core = { path = "../../core" }
|
||||
token_program = { path = "../..", package = "token_program" }
|
||||
|
||||
@ -11,6 +11,7 @@ mod token {
|
||||
use super::*;
|
||||
|
||||
/// Transfer tokens from sender to recipient.
|
||||
/// Fresh public recipients must be explicitly authorized in the same transaction.
|
||||
#[instruction]
|
||||
pub fn transfer(
|
||||
sender: AccountWithMetadata,
|
||||
@ -25,6 +26,7 @@ mod token {
|
||||
}
|
||||
|
||||
/// Create a new fungible token definition without metadata.
|
||||
/// Definition and holding targets must be uninitialized and authorized.
|
||||
#[instruction]
|
||||
pub fn new_fungible_definition(
|
||||
definition_target_account: AccountWithMetadata,
|
||||
@ -43,6 +45,7 @@ mod token {
|
||||
}
|
||||
|
||||
/// Create a new fungible or non-fungible token definition with metadata.
|
||||
/// Definition, holding, and metadata targets must be uninitialized and authorized.
|
||||
#[instruction]
|
||||
pub fn new_definition_with_metadata(
|
||||
definition_target_account: AccountWithMetadata,
|
||||
@ -63,6 +66,7 @@ mod token {
|
||||
}
|
||||
|
||||
/// Initialize a token holding account for a given token definition.
|
||||
/// The holding target must be uninitialized and authorized.
|
||||
#[instruction]
|
||||
pub fn initialize_account(
|
||||
definition_account: AccountWithMetadata,
|
||||
@ -91,6 +95,7 @@ mod token {
|
||||
}
|
||||
|
||||
/// Mint new tokens to the holder's account.
|
||||
/// Fresh public holders must be explicitly authorized in the same transaction.
|
||||
#[instruction]
|
||||
pub fn mint(
|
||||
definition_account: AccountWithMetadata,
|
||||
@ -105,6 +110,7 @@ mod token {
|
||||
}
|
||||
|
||||
/// Print a new NFT from the master copy.
|
||||
/// The printed copy target must be uninitialized and authorized.
|
||||
#[instruction]
|
||||
pub fn print_nft(
|
||||
master_account: AccountWithMetadata,
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
use nssa_core::{
|
||||
account::{Account, AccountWithMetadata, Data},
|
||||
program::AccountPostState,
|
||||
program::{AccountPostState, Claim},
|
||||
};
|
||||
use token_core::{TokenDefinition, TokenHolding};
|
||||
|
||||
@ -13,6 +13,10 @@ pub fn initialize_account(
|
||||
Account::default(),
|
||||
"Only Uninitialized accounts can be initialized"
|
||||
);
|
||||
assert!(
|
||||
account_to_initialize.is_authorized,
|
||||
"Account to initialize must be authorized"
|
||||
);
|
||||
|
||||
// TODO: #212 We should check that this is an account owned by the token program.
|
||||
// This check can't be done here since the ID of the program is known only after compiling it
|
||||
@ -29,6 +33,6 @@ pub fn initialize_account(
|
||||
|
||||
vec![
|
||||
AccountPostState::new(definition_post),
|
||||
AccountPostState::new_claimed(account_to_initialize),
|
||||
AccountPostState::new_claimed(account_to_initialize, Claim::Authorized),
|
||||
]
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
use nssa_core::{
|
||||
account::{Account, AccountWithMetadata, Data},
|
||||
program::AccountPostState,
|
||||
program::{AccountPostState, Claim},
|
||||
};
|
||||
use token_core::{TokenDefinition, TokenHolding};
|
||||
|
||||
@ -66,6 +66,6 @@ pub fn mint(
|
||||
|
||||
vec![
|
||||
AccountPostState::new(definition_post),
|
||||
AccountPostState::new_claimed_if_default(holding_post),
|
||||
AccountPostState::new_claimed_if_default(holding_post, Claim::Authorized),
|
||||
]
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
use nssa_core::{
|
||||
account::{Account, AccountWithMetadata, Data},
|
||||
program::AccountPostState,
|
||||
program::{AccountPostState, Claim},
|
||||
};
|
||||
use token_core::{
|
||||
NewTokenDefinition, NewTokenMetadata, TokenDefinition, TokenHolding, TokenMetadata,
|
||||
@ -23,6 +23,14 @@ pub fn new_fungible_definition(
|
||||
Account::default(),
|
||||
"Holding target account must have default values"
|
||||
);
|
||||
assert!(
|
||||
definition_target_account.is_authorized,
|
||||
"Definition target account must be authorized"
|
||||
);
|
||||
assert!(
|
||||
holding_target_account.is_authorized,
|
||||
"Holding target account must be authorized"
|
||||
);
|
||||
|
||||
let token_definition = TokenDefinition::Fungible {
|
||||
name,
|
||||
@ -41,8 +49,8 @@ pub fn new_fungible_definition(
|
||||
holding_target_account_post.data = Data::from(&token_holding);
|
||||
|
||||
vec![
|
||||
AccountPostState::new_claimed(definition_target_account_post),
|
||||
AccountPostState::new_claimed(holding_target_account_post),
|
||||
AccountPostState::new_claimed(definition_target_account_post, Claim::Authorized),
|
||||
AccountPostState::new_claimed(holding_target_account_post, Claim::Authorized),
|
||||
]
|
||||
}
|
||||
|
||||
@ -70,6 +78,18 @@ pub fn new_definition_with_metadata(
|
||||
Account::default(),
|
||||
"Metadata target account must have default values"
|
||||
);
|
||||
assert!(
|
||||
definition_target_account.is_authorized,
|
||||
"Definition target account must be authorized"
|
||||
);
|
||||
assert!(
|
||||
holding_target_account.is_authorized,
|
||||
"Holding target account must be authorized"
|
||||
);
|
||||
assert!(
|
||||
metadata_target_account.is_authorized,
|
||||
"Metadata target account must be authorized"
|
||||
);
|
||||
|
||||
let (token_definition, token_holding) = match new_definition {
|
||||
NewTokenDefinition::Fungible { name, total_supply } => (
|
||||
@ -117,8 +137,8 @@ pub fn new_definition_with_metadata(
|
||||
metadata_target_account_post.data = Data::from(&token_metadata);
|
||||
|
||||
vec![
|
||||
AccountPostState::new_claimed(definition_target_account_post),
|
||||
AccountPostState::new_claimed(holding_target_account_post),
|
||||
AccountPostState::new_claimed(metadata_target_account_post),
|
||||
AccountPostState::new_claimed(definition_target_account_post, Claim::Authorized),
|
||||
AccountPostState::new_claimed(holding_target_account_post, Claim::Authorized),
|
||||
AccountPostState::new_claimed(metadata_target_account_post, Claim::Authorized),
|
||||
]
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
use nssa_core::{
|
||||
account::{Account, AccountWithMetadata, Data},
|
||||
program::AccountPostState,
|
||||
program::{AccountPostState, Claim},
|
||||
};
|
||||
use token_core::TokenHolding;
|
||||
|
||||
@ -18,6 +18,10 @@ pub fn print_nft(
|
||||
Account::default(),
|
||||
"Printed Account must be uninitialized"
|
||||
);
|
||||
assert!(
|
||||
printed_account.is_authorized,
|
||||
"Printed Account must be authorized"
|
||||
);
|
||||
|
||||
let mut master_account_data =
|
||||
TokenHolding::try_from(&master_account.account.data).expect("Invalid Token Holding data");
|
||||
@ -49,6 +53,6 @@ pub fn print_nft(
|
||||
|
||||
vec![
|
||||
AccountPostState::new(master_account_post),
|
||||
AccountPostState::new_claimed(printed_account_post),
|
||||
AccountPostState::new_claimed(printed_account_post, Claim::Authorized),
|
||||
]
|
||||
}
|
||||
|
||||
@ -1,12 +1,16 @@
|
||||
#![cfg(test)]
|
||||
|
||||
use nssa_core::account::{Account, AccountId, AccountWithMetadata, Data, Nonce};
|
||||
use nssa_core::{
|
||||
account::{Account, AccountId, AccountWithMetadata, Data, Nonce},
|
||||
program::Claim,
|
||||
};
|
||||
use token_core::{
|
||||
MetadataStandard, NewTokenDefinition, NewTokenMetadata, TokenDefinition, TokenHolding,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
burn::burn,
|
||||
initialize::initialize_account,
|
||||
mint::mint,
|
||||
new_definition::{new_definition_with_metadata, new_fungible_definition},
|
||||
print_nft::print_nft,
|
||||
@ -161,6 +165,14 @@ impl AccountForTests {
|
||||
}
|
||||
}
|
||||
|
||||
fn holding_account_uninit_auth() -> AccountWithMetadata {
|
||||
AccountWithMetadata {
|
||||
account: Account::default(),
|
||||
is_authorized: true,
|
||||
account_id: IdForTests::holding_id_2(),
|
||||
}
|
||||
}
|
||||
|
||||
fn init_mint() -> AccountWithMetadata {
|
||||
AccountWithMetadata {
|
||||
account: Account {
|
||||
@ -251,6 +263,22 @@ impl AccountForTests {
|
||||
}
|
||||
}
|
||||
|
||||
fn definition_account_uninit_auth() -> AccountWithMetadata {
|
||||
AccountWithMetadata {
|
||||
account: Account::default(),
|
||||
is_authorized: true,
|
||||
account_id: IdForTests::pool_definition_id(),
|
||||
}
|
||||
}
|
||||
|
||||
fn metadata_account_uninit_auth() -> AccountWithMetadata {
|
||||
AccountWithMetadata {
|
||||
account: Account::default(),
|
||||
is_authorized: true,
|
||||
account_id: AccountId::new([19; 32]),
|
||||
}
|
||||
}
|
||||
|
||||
fn holding_account_init() -> AccountWithMetadata {
|
||||
AccountWithMetadata {
|
||||
account: Account {
|
||||
@ -569,10 +597,36 @@ fn test_new_definition_non_default_second_account_should_fail() {
|
||||
);
|
||||
}
|
||||
|
||||
#[should_panic(expected = "Definition target account must be authorized")]
|
||||
#[test]
|
||||
fn test_new_definition_requires_authorized_definition_target() {
|
||||
let definition_account = AccountForTests::definition_account_uninit();
|
||||
let holding_account = AccountForTests::holding_account_uninit_auth();
|
||||
let _post_states = new_fungible_definition(
|
||||
definition_account,
|
||||
holding_account,
|
||||
String::from("test"),
|
||||
10,
|
||||
);
|
||||
}
|
||||
|
||||
#[should_panic(expected = "Holding target account must be authorized")]
|
||||
#[test]
|
||||
fn test_new_definition_requires_authorized_holding_target() {
|
||||
let definition_account = AccountForTests::definition_account_uninit_auth();
|
||||
let holding_account = AccountForTests::holding_account_uninit();
|
||||
let _post_states = new_fungible_definition(
|
||||
definition_account,
|
||||
holding_account,
|
||||
String::from("test"),
|
||||
10,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_new_definition_with_valid_inputs_succeeds() {
|
||||
let definition_account = AccountForTests::definition_account_uninit();
|
||||
let holding_account = AccountForTests::holding_account_uninit();
|
||||
let definition_account = AccountForTests::definition_account_uninit_auth();
|
||||
let holding_account = AccountForTests::holding_account_uninit_auth();
|
||||
|
||||
let post_states = new_fungible_definition(
|
||||
definition_account,
|
||||
@ -586,11 +640,13 @@ fn test_new_definition_with_valid_inputs_succeeds() {
|
||||
*definition_account.account(),
|
||||
AccountForTests::definition_account_unclaimed().account
|
||||
);
|
||||
assert_eq!(definition_account.required_claim(), Some(Claim::Authorized));
|
||||
|
||||
assert_eq!(
|
||||
*holding_account.account(),
|
||||
AccountForTests::holding_account_unclaimed().account
|
||||
);
|
||||
assert_eq!(holding_account.required_claim(), Some(Claim::Authorized));
|
||||
}
|
||||
|
||||
#[should_panic(expected = "Sender and recipient definition id mismatch")]
|
||||
@ -633,6 +689,8 @@ fn test_transfer_with_valid_inputs_succeeds() {
|
||||
*recipient_post.account(),
|
||||
AccountForTests::holding_account2_init_post_transfer().account
|
||||
);
|
||||
assert_eq!(sender_post.required_claim(), None);
|
||||
assert_eq!(recipient_post.required_claim(), None);
|
||||
}
|
||||
|
||||
#[should_panic(expected = "Invalid balance for NFT Master transfer")]
|
||||
@ -669,9 +727,9 @@ fn test_transfer_with_master_nft_success() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_token_initialize_account_succeeds() {
|
||||
fn test_transfer_with_default_recipient_claims_recipient() {
|
||||
let sender = AccountForTests::holding_account_init();
|
||||
let recipient = AccountForTests::holding_account2_init();
|
||||
let recipient = AccountForTests::holding_account_uninit();
|
||||
let post_states = transfer(sender, recipient, BalanceForTests::transfer_amount());
|
||||
let [sender_post, recipient_post] = post_states.try_into().unwrap();
|
||||
|
||||
@ -681,8 +739,53 @@ fn test_token_initialize_account_succeeds() {
|
||||
);
|
||||
assert_eq!(
|
||||
*recipient_post.account(),
|
||||
AccountForTests::holding_account2_init_post_transfer().account
|
||||
Account {
|
||||
program_owner: [0u32; 8],
|
||||
balance: 0u128,
|
||||
data: Data::from(&TokenHolding::Fungible {
|
||||
definition_id: IdForTests::pool_definition_id(),
|
||||
balance: BalanceForTests::transfer_amount(),
|
||||
}),
|
||||
nonce: Nonce(0),
|
||||
}
|
||||
);
|
||||
assert_eq!(sender_post.required_claim(), None);
|
||||
assert_eq!(recipient_post.required_claim(), Some(Claim::Authorized));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_token_initialize_account_succeeds() {
|
||||
let definition_account = AccountForTests::definition_account_auth();
|
||||
let holding_account = AccountForTests::holding_account_uninit_auth();
|
||||
let post_states = initialize_account(definition_account, holding_account);
|
||||
let [definition_post, holding_post] = post_states.try_into().unwrap();
|
||||
|
||||
assert_eq!(
|
||||
*definition_post.account(),
|
||||
AccountForTests::definition_account_auth().account
|
||||
);
|
||||
assert_eq!(
|
||||
*holding_post.account(),
|
||||
Account {
|
||||
program_owner: [0u32; 8],
|
||||
balance: 0u128,
|
||||
data: Data::from(&TokenHolding::Fungible {
|
||||
definition_id: IdForTests::pool_definition_id(),
|
||||
balance: 0,
|
||||
}),
|
||||
nonce: Nonce(0),
|
||||
}
|
||||
);
|
||||
assert_eq!(definition_post.required_claim(), None);
|
||||
assert_eq!(holding_post.required_claim(), Some(Claim::Authorized));
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "Account to initialize must be authorized")]
|
||||
fn test_token_initialize_account_requires_authorization() {
|
||||
let definition_account = AccountForTests::definition_account_auth();
|
||||
let holding_account = AccountForTests::holding_account_uninit();
|
||||
let _post_states = initialize_account(definition_account, holding_account);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -824,6 +927,8 @@ fn test_mint_success() {
|
||||
*holding_post.account(),
|
||||
AccountForTests::holding_account_same_definition_mint().account
|
||||
);
|
||||
assert_eq!(def_post.required_claim(), None);
|
||||
assert_eq!(holding_post.required_claim(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -846,7 +951,8 @@ fn test_mint_uninit_holding_success() {
|
||||
*holding_post.account(),
|
||||
AccountForTests::init_mint().account
|
||||
);
|
||||
assert!(holding_post.requires_claim());
|
||||
assert_eq!(def_post.required_claim(), None);
|
||||
assert_eq!(holding_post.required_claim(), Some(Claim::Authorized));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -885,6 +991,111 @@ fn test_mint_cannot_mint_unmintable_tokens() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_new_definition_with_metadata_success() {
|
||||
let definition_account = AccountForTests::definition_account_uninit_auth();
|
||||
let holding_account = AccountForTests::holding_account_uninit_auth();
|
||||
let metadata_account = AccountForTests::metadata_account_uninit_auth();
|
||||
let new_definition = NewTokenDefinition::Fungible {
|
||||
name: String::from("test"),
|
||||
total_supply: 15u128,
|
||||
};
|
||||
let metadata = NewTokenMetadata {
|
||||
standard: MetadataStandard::Simple,
|
||||
uri: "test_uri".to_string(),
|
||||
creators: "test_creators".to_string(),
|
||||
};
|
||||
|
||||
let post_states = new_definition_with_metadata(
|
||||
definition_account,
|
||||
holding_account,
|
||||
metadata_account,
|
||||
new_definition,
|
||||
metadata,
|
||||
);
|
||||
let [definition_post, holding_post, metadata_post] = post_states.try_into().unwrap();
|
||||
|
||||
assert_eq!(definition_post.required_claim(), Some(Claim::Authorized));
|
||||
assert_eq!(holding_post.required_claim(), Some(Claim::Authorized));
|
||||
assert_eq!(metadata_post.required_claim(), Some(Claim::Authorized));
|
||||
}
|
||||
|
||||
#[should_panic(expected = "Definition target account must be authorized")]
|
||||
#[test]
|
||||
fn test_call_new_definition_metadata_requires_authorized_definition() {
|
||||
let definition_account = AccountForTests::definition_account_uninit();
|
||||
let holding_account = AccountForTests::holding_account_uninit_auth();
|
||||
let metadata_account = AccountForTests::metadata_account_uninit_auth();
|
||||
let new_definition = NewTokenDefinition::Fungible {
|
||||
name: String::from("test"),
|
||||
total_supply: 15u128,
|
||||
};
|
||||
let metadata = NewTokenMetadata {
|
||||
standard: MetadataStandard::Simple,
|
||||
uri: "test_uri".to_string(),
|
||||
creators: "test_creators".to_string(),
|
||||
};
|
||||
let _post_states = new_definition_with_metadata(
|
||||
definition_account,
|
||||
holding_account,
|
||||
metadata_account,
|
||||
new_definition,
|
||||
metadata,
|
||||
);
|
||||
}
|
||||
|
||||
#[should_panic(expected = "Holding target account must be authorized")]
|
||||
#[test]
|
||||
fn test_call_new_definition_metadata_requires_authorized_holding() {
|
||||
let definition_account = AccountForTests::definition_account_uninit_auth();
|
||||
let holding_account = AccountForTests::holding_account_uninit();
|
||||
let metadata_account = AccountForTests::metadata_account_uninit_auth();
|
||||
let new_definition = NewTokenDefinition::Fungible {
|
||||
name: String::from("test"),
|
||||
total_supply: 15u128,
|
||||
};
|
||||
let metadata = NewTokenMetadata {
|
||||
standard: MetadataStandard::Simple,
|
||||
uri: "test_uri".to_string(),
|
||||
creators: "test_creators".to_string(),
|
||||
};
|
||||
let _post_states = new_definition_with_metadata(
|
||||
definition_account,
|
||||
holding_account,
|
||||
metadata_account,
|
||||
new_definition,
|
||||
metadata,
|
||||
);
|
||||
}
|
||||
|
||||
#[should_panic(expected = "Metadata target account must be authorized")]
|
||||
#[test]
|
||||
fn test_call_new_definition_metadata_requires_authorized_metadata() {
|
||||
let definition_account = AccountForTests::definition_account_uninit_auth();
|
||||
let holding_account = AccountForTests::holding_account_uninit_auth();
|
||||
let metadata_account = AccountWithMetadata {
|
||||
account: Account::default(),
|
||||
is_authorized: false,
|
||||
account_id: AccountId::new([20; 32]),
|
||||
};
|
||||
let new_definition = NewTokenDefinition::Fungible {
|
||||
name: String::from("test"),
|
||||
total_supply: 15u128,
|
||||
};
|
||||
let metadata = NewTokenMetadata {
|
||||
standard: MetadataStandard::Simple,
|
||||
uri: "test_uri".to_string(),
|
||||
creators: "test_creators".to_string(),
|
||||
};
|
||||
let _post_states = new_definition_with_metadata(
|
||||
definition_account,
|
||||
holding_account,
|
||||
metadata_account,
|
||||
new_definition,
|
||||
metadata,
|
||||
);
|
||||
}
|
||||
|
||||
#[should_panic(expected = "Definition target account must have default values")]
|
||||
#[test]
|
||||
fn test_call_new_definition_metadata_with_init_definition() {
|
||||
@ -997,11 +1208,19 @@ fn test_print_nft_print_account_initialized() {
|
||||
let _post_states = print_nft(master_account, printed_account);
|
||||
}
|
||||
|
||||
#[should_panic(expected = "Printed Account must be authorized")]
|
||||
#[test]
|
||||
fn test_print_nft_print_account_must_be_authorized() {
|
||||
let master_account = AccountForTests::holding_account_master_nft();
|
||||
let printed_account = AccountForTests::holding_account_uninit();
|
||||
let _post_states = print_nft(master_account, printed_account);
|
||||
}
|
||||
|
||||
#[should_panic(expected = "Invalid Token Holding data")]
|
||||
#[test]
|
||||
fn test_print_nft_master_nft_invalid_token_holding() {
|
||||
let master_account = AccountForTests::definition_account_auth();
|
||||
let printed_account = AccountForTests::holding_account_uninit();
|
||||
let printed_account = AccountForTests::holding_account_uninit_auth();
|
||||
let _post_states = print_nft(master_account, printed_account);
|
||||
}
|
||||
|
||||
@ -1009,7 +1228,7 @@ fn test_print_nft_master_nft_invalid_token_holding() {
|
||||
#[test]
|
||||
fn test_print_nft_master_nft_not_nft_master_account() {
|
||||
let master_account = AccountForTests::holding_account_init();
|
||||
let printed_account = AccountForTests::holding_account_uninit();
|
||||
let printed_account = AccountForTests::holding_account_uninit_auth();
|
||||
let _post_states = print_nft(master_account, printed_account);
|
||||
}
|
||||
|
||||
@ -1017,14 +1236,14 @@ fn test_print_nft_master_nft_not_nft_master_account() {
|
||||
#[test]
|
||||
fn test_print_nft_master_nft_insufficient_balance() {
|
||||
let master_account = AccountForTests::holding_account_master_nft_insufficient_balance();
|
||||
let printed_account = AccountForTests::holding_account_uninit();
|
||||
let printed_account = AccountForTests::holding_account_uninit_auth();
|
||||
let _post_states = print_nft(master_account, printed_account);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_print_nft_success() {
|
||||
let master_account = AccountForTests::holding_account_master_nft();
|
||||
let printed_account = AccountForTests::holding_account_uninit();
|
||||
let printed_account = AccountForTests::holding_account_uninit_auth();
|
||||
let post_states = print_nft(master_account, printed_account);
|
||||
|
||||
let [post_master_nft, post_printed] = post_states.try_into().unwrap();
|
||||
@ -1037,4 +1256,6 @@ fn test_print_nft_success() {
|
||||
*post_printed.account(),
|
||||
AccountForTests::holding_account_printed_nft().account
|
||||
);
|
||||
assert_eq!(post_master_nft.required_claim(), None);
|
||||
assert_eq!(post_printed.required_claim(), Some(Claim::Authorized));
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
use nssa_core::{
|
||||
account::{Account, AccountWithMetadata, Data},
|
||||
program::AccountPostState,
|
||||
program::{AccountPostState, Claim},
|
||||
};
|
||||
use token_core::TokenHolding;
|
||||
|
||||
@ -105,6 +105,6 @@ pub fn transfer(
|
||||
|
||||
vec![
|
||||
AccountPostState::new(sender_post),
|
||||
AccountPostState::new_claimed_if_default(recipient_post),
|
||||
AccountPostState::new_claimed_if_default(recipient_post, Claim::Authorized),
|
||||
]
|
||||
}
|
||||
|
||||
@ -8,7 +8,7 @@ name = "idl-gen"
|
||||
path = "src/main.rs"
|
||||
|
||||
[dependencies]
|
||||
spel-framework-core = { git = "https://github.com/logos-co/spel.git", rev = "57201f64b4542bb3f592bc9a0aa654c47aa908a6", features = [
|
||||
spel-framework-core = { git = "https://github.com/logos-co/spel.git", tag = "v0.2.0-rc.2", features = [
|
||||
"idl-gen",
|
||||
] }
|
||||
serde_json = "1.0"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user