mirror of
https://github.com/logos-blockchain/lez-programs.git
synced 2026-05-19 15:39:28 +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
9f34384dd7
18
Cargo.lock
generated
18
Cargo.lock
generated
@ -598,6 +598,15 @@ dependencies = [
|
|||||||
"inout",
|
"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]]
|
[[package]]
|
||||||
name = "cobs"
|
name = "cobs"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
@ -1821,10 +1830,11 @@ checksum = "a5b0c77c1b780822bc749a33e39aeb2c07584ab93332303babeabb645298a76e"
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "nssa"
|
name = "nssa"
|
||||||
version = "0.1.0"
|
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 = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"borsh",
|
"borsh",
|
||||||
|
"clock_core",
|
||||||
"hex",
|
"hex",
|
||||||
"k256",
|
"k256",
|
||||||
"log",
|
"log",
|
||||||
@ -1842,7 +1852,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "nssa_core"
|
name = "nssa_core"
|
||||||
version = "0.1.0"
|
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 = [
|
dependencies = [
|
||||||
"base58",
|
"base58",
|
||||||
"borsh",
|
"borsh",
|
||||||
@ -2962,8 +2972,8 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "spel-framework-core"
|
name = "spel-framework-core"
|
||||||
version = "0.1.0"
|
version = "0.2.0"
|
||||||
source = "git+https://github.com/logos-co/spel.git?rev=57201f64b4542bb3f592bc9a0aa654c47aa908a6#57201f64b4542bb3f592bc9a0aa654c47aa908a6"
|
source = "git+https://github.com/logos-co/spel.git?tag=v0.2.0-rc.2#9005e9fbbd78b0530412f9987273f753ed32eb2d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"borsh",
|
"borsh",
|
||||||
"nssa_core",
|
"nssa_core",
|
||||||
|
|||||||
@ -20,8 +20,8 @@ exclude = [
|
|||||||
resolver = "2"
|
resolver = "2"
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.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"] }
|
||||||
nssa = { git = "https://github.com/logos-blockchain/logos-execution-zone.git", rev = "ffcbc15972adbf557939bf3e2852af276422631b", features = ["test-utils"] }
|
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_core = { path = "token/core" }
|
||||||
token_program = { path = "token" }
|
token_program = { path = "token" }
|
||||||
amm_core = { path = "amm/core" }
|
amm_core = { path = "amm/core" }
|
||||||
@ -33,4 +33,3 @@ borsh = { version = "1.0", features = ["derive"] }
|
|||||||
risc0-zkvm = { version = "=3.0.5" }
|
risc0-zkvm = { version = "=3.0.5" }
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
tokio = { version = "1.28.2", features = ["net", "rt-multi-thread", "sync", "macros"] }
|
tokio = { version = "1.28.2", features = ["net", "rt-multi-thread", "sync", "macros"] }
|
||||||
|
|
||||||
|
|||||||
@ -4,6 +4,6 @@ version = "0.1.0"
|
|||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[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" }
|
amm_core = { path = "core" }
|
||||||
token_core = { path = "../token/core" }
|
token_core = { path = "../token/core" }
|
||||||
|
|||||||
@ -4,7 +4,7 @@ version = "0.1.0"
|
|||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[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" }
|
token_core = { path = "../../token/core" }
|
||||||
borsh = { version = "1.5", features = ["derive"] }
|
borsh = { version = "1.5", features = ["derive"] }
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
|||||||
@ -29,7 +29,7 @@ pub enum Instruction {
|
|||||||
/// pool.account_id)`
|
/// pool.account_id)`
|
||||||
/// - User Holding Account for Token A (authorized)
|
/// - User Holding Account for Token A (authorized)
|
||||||
/// - User Holding Account for Token B (authorized)
|
/// - User Holding Account for Token B (authorized)
|
||||||
/// - User Holding Account for Pool Liquidity
|
/// - User Holding Account for Pool Liquidity (authorized when uninitialized)
|
||||||
NewDefinition {
|
NewDefinition {
|
||||||
token_a_amount: u128,
|
token_a_amount: u128,
|
||||||
token_b_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]]
|
[[package]]
|
||||||
name = "nssa_core"
|
name = "nssa_core"
|
||||||
version = "0.1.0"
|
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 = [
|
dependencies = [
|
||||||
"base58",
|
"base58",
|
||||||
"borsh",
|
"borsh",
|
||||||
@ -2897,8 +2897,8 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "spel-framework"
|
name = "spel-framework"
|
||||||
version = "0.1.0"
|
version = "0.2.0"
|
||||||
source = "git+https://github.com/logos-co/spel.git?rev=57201f64b4542bb3f592bc9a0aa654c47aa908a6#57201f64b4542bb3f592bc9a0aa654c47aa908a6"
|
source = "git+https://github.com/logos-co/spel.git?tag=v0.2.0-rc.2#9005e9fbbd78b0530412f9987273f753ed32eb2d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"borsh",
|
"borsh",
|
||||||
"nssa_core",
|
"nssa_core",
|
||||||
@ -2908,8 +2908,8 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "spel-framework-core"
|
name = "spel-framework-core"
|
||||||
version = "0.1.0"
|
version = "0.2.0"
|
||||||
source = "git+https://github.com/logos-co/spel.git?rev=57201f64b4542bb3f592bc9a0aa654c47aa908a6#57201f64b4542bb3f592bc9a0aa654c47aa908a6"
|
source = "git+https://github.com/logos-co/spel.git?tag=v0.2.0-rc.2#9005e9fbbd78b0530412f9987273f753ed32eb2d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"borsh",
|
"borsh",
|
||||||
"nssa_core",
|
"nssa_core",
|
||||||
@ -2921,8 +2921,8 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "spel-framework-macros"
|
name = "spel-framework-macros"
|
||||||
version = "0.1.0"
|
version = "0.2.0"
|
||||||
source = "git+https://github.com/logos-co/spel.git?rev=57201f64b4542bb3f592bc9a0aa654c47aa908a6#57201f64b4542bb3f592bc9a0aa654c47aa908a6"
|
source = "git+https://github.com/logos-co/spel.git?tag=v0.2.0-rc.2#9005e9fbbd78b0530412f9987273f753ed32eb2d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
|||||||
@ -10,8 +10,8 @@ name = "amm"
|
|||||||
path = "src/bin/amm.rs"
|
path = "src/bin/amm.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
spel-framework = { git = "https://github.com/logos-co/spel.git", rev = "57201f64b4542bb3f592bc9a0aa654c47aa908a6", package = "spel-framework" }
|
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", rev = "ffcbc15972adbf557939bf3e2852af276422631b" }
|
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 }
|
risc0-zkvm = { version = "=3.0.5", default-features = false }
|
||||||
amm_core = { path = "../../core" }
|
amm_core = { path = "../../core" }
|
||||||
amm_program = { path = "../..", package = "amm_program" }
|
amm_program = { path = "../..", package = "amm_program" }
|
||||||
|
|||||||
@ -16,6 +16,7 @@ mod amm {
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
/// Initializes a new Pool (or re-initializes an existing zero-supply Pool).
|
/// 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]
|
#[instruction]
|
||||||
pub fn new_definition(
|
pub fn new_definition(
|
||||||
pool: AccountWithMetadata,
|
pool: AccountWithMetadata,
|
||||||
|
|||||||
@ -2,12 +2,13 @@ use std::num::NonZeroU128;
|
|||||||
|
|
||||||
use amm_core::{
|
use amm_core::{
|
||||||
assert_supported_fee_tier, compute_liquidity_token_pda, compute_liquidity_token_pda_seed,
|
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,
|
MINIMUM_LIQUIDITY,
|
||||||
};
|
};
|
||||||
use nssa_core::{
|
use nssa_core::{
|
||||||
account::{Account, AccountWithMetadata, Data},
|
account::{Account, AccountWithMetadata, Data},
|
||||||
program::{AccountPostState, ChainedCall, ProgramId},
|
program::{AccountPostState, ChainedCall, Claim, ProgramId},
|
||||||
};
|
};
|
||||||
use token_core::TokenDefinition;
|
use token_core::TokenDefinition;
|
||||||
|
|
||||||
@ -78,6 +79,10 @@ pub fn new_definition(
|
|||||||
Account::default(),
|
Account::default(),
|
||||||
"Pool account must be uninitialized"
|
"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
|
// LP Token minting calculation
|
||||||
let initial_lp = token_a_amount
|
let initial_lp = token_a_amount
|
||||||
@ -106,40 +111,63 @@ pub fn new_definition(
|
|||||||
};
|
};
|
||||||
|
|
||||||
pool_post.data = Data::from(&pool_post_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;
|
let token_program_id = user_holding_a.account.program_owner;
|
||||||
|
|
||||||
// Chain call for Token A (user_holding_a -> Vault_A)
|
// 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(
|
let call_token_a = ChainedCall::new(
|
||||||
token_program_id,
|
token_program_id,
|
||||||
vec![user_holding_a.clone(), vault_a.clone()],
|
vec![user_holding_a.clone(), vault_a_authorized],
|
||||||
&token_core::Instruction::Transfer {
|
&token_core::Instruction::Transfer {
|
||||||
amount_to_transfer: token_a_amount.into(),
|
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)
|
// 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(
|
let call_token_b = ChainedCall::new(
|
||||||
token_program_id,
|
token_program_id,
|
||||||
vec![user_holding_b.clone(), vault_b.clone()],
|
vec![user_holding_b.clone(), vault_b_authorized],
|
||||||
&token_core::Instruction::Transfer {
|
&token_core::Instruction::Transfer {
|
||||||
amount_to_transfer: token_b_amount.into(),
|
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
|
// Chain call for liquidity token lock holding
|
||||||
let mut pool_lp_auth = pool_definition_lp.clone();
|
let mut pool_lp_auth = pool_definition_lp.clone();
|
||||||
pool_lp_auth.is_authorized = true;
|
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(
|
let call_token_lp_lock = ChainedCall::new(
|
||||||
token_program_id,
|
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 {
|
&token_core::Instruction::NewFungibleDefinition {
|
||||||
name: String::from("LP Token"),
|
name: String::from("LP Token"),
|
||||||
total_supply: MINIMUM_LIQUIDITY,
|
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();
|
let mut pool_lp_after_lock = pool_lp_auth.clone();
|
||||||
pool_lp_after_lock.account.program_owner = token_program_id;
|
pool_lp_after_lock.account.program_owner = token_program_id;
|
||||||
|
|||||||
@ -4,13 +4,13 @@ use std::num::NonZero;
|
|||||||
|
|
||||||
use amm_core::{
|
use amm_core::{
|
||||||
compute_liquidity_token_pda, compute_liquidity_token_pda_seed, compute_lp_lock_holding_pda,
|
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,
|
compute_lp_lock_holding_pda_seed, compute_pool_pda, compute_pool_pda_seed, compute_vault_pda,
|
||||||
FEE_BPS_DENOMINATOR, FEE_TIER_BPS_1, FEE_TIER_BPS_100, FEE_TIER_BPS_30, FEE_TIER_BPS_5,
|
compute_vault_pda_seed, PoolDefinition, FEE_BPS_DENOMINATOR, FEE_TIER_BPS_1, FEE_TIER_BPS_100,
|
||||||
MINIMUM_LIQUIDITY,
|
FEE_TIER_BPS_30, FEE_TIER_BPS_5, MINIMUM_LIQUIDITY,
|
||||||
};
|
};
|
||||||
use nssa_core::{
|
use nssa_core::{
|
||||||
account::{Account, AccountId, AccountWithMetadata, Data, Nonce},
|
account::{Account, AccountId, AccountWithMetadata, Data, Nonce},
|
||||||
program::{ChainedCall, ProgramId},
|
program::{ChainedCall, Claim, ProgramId},
|
||||||
};
|
};
|
||||||
use token_core::{TokenDefinition, TokenHolding};
|
use token_core::{TokenDefinition, TokenHolding};
|
||||||
|
|
||||||
@ -489,46 +489,57 @@ impl ChainedCallForTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn cc_new_definition_token_a() -> ChainedCall {
|
fn cc_new_definition_token_a() -> ChainedCall {
|
||||||
|
let mut vault_a_auth = AccountWithMetadataForTests::vault_a_init();
|
||||||
|
vault_a_auth.is_authorized = true;
|
||||||
|
|
||||||
ChainedCall::new(
|
ChainedCall::new(
|
||||||
TOKEN_PROGRAM_ID,
|
TOKEN_PROGRAM_ID,
|
||||||
vec![
|
vec![AccountWithMetadataForTests::user_holding_a(), vault_a_auth],
|
||||||
AccountWithMetadataForTests::user_holding_a(),
|
|
||||||
AccountWithMetadataForTests::vault_a_init(),
|
|
||||||
],
|
|
||||||
&token_core::Instruction::Transfer {
|
&token_core::Instruction::Transfer {
|
||||||
amount_to_transfer: BalanceForTests::vault_a_reserve_init(),
|
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 {
|
fn cc_new_definition_token_b() -> ChainedCall {
|
||||||
|
let mut vault_b_auth = AccountWithMetadataForTests::vault_b_init();
|
||||||
|
vault_b_auth.is_authorized = true;
|
||||||
|
|
||||||
ChainedCall::new(
|
ChainedCall::new(
|
||||||
TOKEN_PROGRAM_ID,
|
TOKEN_PROGRAM_ID,
|
||||||
vec![
|
vec![AccountWithMetadataForTests::user_holding_b(), vault_b_auth],
|
||||||
AccountWithMetadataForTests::user_holding_b(),
|
|
||||||
AccountWithMetadataForTests::vault_b_init(),
|
|
||||||
],
|
|
||||||
&token_core::Instruction::Transfer {
|
&token_core::Instruction::Transfer {
|
||||||
amount_to_transfer: BalanceForTests::vault_b_reserve_init(),
|
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 {
|
fn cc_new_definition_token_lp_lock() -> ChainedCall {
|
||||||
let mut pool_lp_auth = AccountForTests::pool_lp_uninit();
|
let mut pool_lp_auth = AccountForTests::pool_lp_uninit();
|
||||||
pool_lp_auth.is_authorized = true;
|
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(
|
ChainedCall::new(
|
||||||
TOKEN_PROGRAM_ID,
|
TOKEN_PROGRAM_ID,
|
||||||
vec![pool_lp_auth, AccountForTests::lp_lock_holding_uninit()],
|
vec![pool_lp_auth, lp_lock_holding_auth],
|
||||||
&token_core::Instruction::NewFungibleDefinition {
|
&token_core::Instruction::NewFungibleDefinition {
|
||||||
name: String::from("LP Token"),
|
name: String::from("LP Token"),
|
||||||
total_supply: MINIMUM_LIQUIDITY,
|
total_supply: MINIMUM_LIQUIDITY,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.with_pda_seeds(vec![compute_liquidity_token_pda_seed(
|
.with_pda_seeds(vec![
|
||||||
IdForTests::pool_definition_id(),
|
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 {
|
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();
|
let pool_post = post_states[0].clone();
|
||||||
|
|
||||||
assert!(AccountWithMetadataForTests::pool_definition_init().account == *pool_post.account());
|
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_lock = chained_calls[0].clone();
|
||||||
let chained_call_lp_user = chained_calls[1].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();
|
let mut pool_lp_auth = AccountForTests::pool_lp_uninit();
|
||||||
pool_lp_auth.is_authorized = true;
|
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(
|
let expected_lp_lock_call = ChainedCall::new(
|
||||||
TOKEN_PROGRAM_ID,
|
TOKEN_PROGRAM_ID,
|
||||||
vec![
|
vec![pool_lp_auth.clone(), lp_lock_holding_auth],
|
||||||
pool_lp_auth.clone(),
|
|
||||||
AccountForTests::lp_lock_holding_uninit(),
|
|
||||||
],
|
|
||||||
&token_core::Instruction::NewFungibleDefinition {
|
&token_core::Instruction::NewFungibleDefinition {
|
||||||
name: String::from("LP Token"),
|
name: String::from("LP Token"),
|
||||||
total_supply: MINIMUM_LIQUIDITY,
|
total_supply: MINIMUM_LIQUIDITY,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.with_pda_seeds(vec![compute_liquidity_token_pda_seed(
|
.with_pda_seeds(vec![
|
||||||
IdForTests::pool_definition_id(),
|
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(
|
let expected_lp_user_call = ChainedCall::new(
|
||||||
TOKEN_PROGRAM_ID,
|
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();
|
let mut pool_lp_auth = AccountForTests::pool_lp_uninit();
|
||||||
pool_lp_auth.is_authorized = true;
|
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(
|
let expected_lock_call = ChainedCall::new(
|
||||||
TOKEN_PROGRAM_ID,
|
TOKEN_PROGRAM_ID,
|
||||||
vec![
|
vec![pool_lp_auth.clone(), lp_lock_holding_auth],
|
||||||
pool_lp_auth.clone(),
|
|
||||||
AccountForTests::lp_lock_holding_uninit(),
|
|
||||||
],
|
|
||||||
&token_core::Instruction::NewFungibleDefinition {
|
&token_core::Instruction::NewFungibleDefinition {
|
||||||
name: String::from("LP Token"),
|
name: String::from("LP Token"),
|
||||||
total_supply: MINIMUM_LIQUIDITY,
|
total_supply: MINIMUM_LIQUIDITY,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.with_pda_seeds(vec![compute_liquidity_token_pda_seed(
|
.with_pda_seeds(vec![
|
||||||
IdForTests::pool_definition_id(),
|
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(
|
let expected_user_call = ChainedCall::new(
|
||||||
TOKEN_PROGRAM_ID,
|
TOKEN_PROGRAM_ID,
|
||||||
vec![
|
vec![
|
||||||
|
|||||||
@ -4,6 +4,6 @@ version = "0.1.0"
|
|||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[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" }
|
ata_core = { path = "core" }
|
||||||
token_core = { path = "../token/core" }
|
token_core = { path = "../token/core" }
|
||||||
|
|||||||
@ -4,7 +4,7 @@ version = "0.1.0"
|
|||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[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"] }
|
borsh = { version = "1.5", features = ["derive"] }
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
risc0-zkvm = { version = "=3.0.5", default-features = false }
|
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`.
|
/// `token_program_id` is derived from `token_definition.account.program_owner`.
|
||||||
Create { ata_program_id: ProgramId },
|
Create { ata_program_id: ProgramId },
|
||||||
|
|
||||||
/// Transfer tokens FROM owner's ATA to a recipient holding account.
|
/// Transfer tokens FROM owner's ATA to a recipient token holding account.
|
||||||
/// Uses PDA seeds to authorize the ATA in the chained Token::Transfer call.
|
/// Uses ATA PDA seeds to authorize the chained Token::Transfer call.
|
||||||
///
|
///
|
||||||
/// Required accounts (3):
|
/// Required accounts (3):
|
||||||
/// - Owner account (authorized)
|
/// - Owner account (authorized)
|
||||||
/// - Sender ATA (owner's token holding)
|
/// - 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`.
|
/// `token_program_id` is derived from `sender_ata.account.program_owner`.
|
||||||
Transfer {
|
Transfer {
|
||||||
|
|||||||
14
ata/methods/guest/Cargo.lock
generated
14
ata/methods/guest/Cargo.lock
generated
@ -1777,7 +1777,7 @@ checksum = "a5b0c77c1b780822bc749a33e39aeb2c07584ab93332303babeabb645298a76e"
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "nssa_core"
|
name = "nssa_core"
|
||||||
version = "0.1.0"
|
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 = [
|
dependencies = [
|
||||||
"base58",
|
"base58",
|
||||||
"borsh",
|
"borsh",
|
||||||
@ -2896,8 +2896,8 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "spel-framework"
|
name = "spel-framework"
|
||||||
version = "0.1.0"
|
version = "0.2.0"
|
||||||
source = "git+https://github.com/logos-co/spel.git?rev=57201f64b4542bb3f592bc9a0aa654c47aa908a6#57201f64b4542bb3f592bc9a0aa654c47aa908a6"
|
source = "git+https://github.com/logos-co/spel.git?tag=v0.2.0-rc.2#9005e9fbbd78b0530412f9987273f753ed32eb2d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"borsh",
|
"borsh",
|
||||||
"nssa_core",
|
"nssa_core",
|
||||||
@ -2907,8 +2907,8 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "spel-framework-core"
|
name = "spel-framework-core"
|
||||||
version = "0.1.0"
|
version = "0.2.0"
|
||||||
source = "git+https://github.com/logos-co/spel.git?rev=57201f64b4542bb3f592bc9a0aa654c47aa908a6#57201f64b4542bb3f592bc9a0aa654c47aa908a6"
|
source = "git+https://github.com/logos-co/spel.git?tag=v0.2.0-rc.2#9005e9fbbd78b0530412f9987273f753ed32eb2d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"borsh",
|
"borsh",
|
||||||
"nssa_core",
|
"nssa_core",
|
||||||
@ -2920,8 +2920,8 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "spel-framework-macros"
|
name = "spel-framework-macros"
|
||||||
version = "0.1.0"
|
version = "0.2.0"
|
||||||
source = "git+https://github.com/logos-co/spel.git?rev=57201f64b4542bb3f592bc9a0aa654c47aa908a6#57201f64b4542bb3f592bc9a0aa654c47aa908a6"
|
source = "git+https://github.com/logos-co/spel.git?tag=v0.2.0-rc.2#9005e9fbbd78b0530412f9987273f753ed32eb2d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
|||||||
@ -10,8 +10,8 @@ name = "ata"
|
|||||||
path = "src/bin/ata.rs"
|
path = "src/bin/ata.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
spel-framework = { git = "https://github.com/logos-co/spel.git", rev = "57201f64b4542bb3f592bc9a0aa654c47aa908a6", package = "spel-framework" }
|
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", rev = "ffcbc15972adbf557939bf3e2852af276422631b" }
|
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 }
|
risc0-zkvm = { version = "=3.0.5", default-features = false }
|
||||||
ata_core = { path = "../../core" }
|
ata_core = { path = "../../core" }
|
||||||
ata_program = { path = "../..", package = "ata_program" }
|
ata_program = { path = "../..", package = "ata_program" }
|
||||||
|
|||||||
@ -28,7 +28,8 @@ mod ata {
|
|||||||
Ok(SpelOutput::with_chained_calls(post_states, chained_calls))
|
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]
|
#[instruction]
|
||||||
pub fn transfer(
|
pub fn transfer(
|
||||||
owner: AccountWithMetadata,
|
owner: AccountWithMetadata,
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
use nssa_core::{
|
use nssa_core::{
|
||||||
account::{Account, AccountWithMetadata},
|
account::{Account, AccountWithMetadata},
|
||||||
program::{AccountPostState, ChainedCall, ProgramId},
|
program::{AccountPostState, ChainedCall, Claim, ProgramId},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn create_associated_token_account(
|
pub fn create_associated_token_account(
|
||||||
@ -9,9 +9,12 @@ pub fn create_associated_token_account(
|
|||||||
ata_account: AccountWithMetadata,
|
ata_account: AccountWithMetadata,
|
||||||
ata_program_id: ProgramId,
|
ata_program_id: ProgramId,
|
||||||
) -> (Vec<AccountPostState>, Vec<ChainedCall>) {
|
) -> (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;
|
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,
|
&ata_account,
|
||||||
&owner,
|
&owner,
|
||||||
token_definition.account_id,
|
token_definition.account_id,
|
||||||
@ -22,7 +25,7 @@ pub fn create_associated_token_account(
|
|||||||
if ata_account.account != Account::default() {
|
if ata_account.account != Account::default() {
|
||||||
return (
|
return (
|
||||||
vec![
|
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(token_definition.account.clone()),
|
||||||
AccountPostState::new(ata_account.account.clone()),
|
AccountPostState::new(ata_account.account.clone()),
|
||||||
],
|
],
|
||||||
@ -31,14 +34,17 @@ pub fn create_associated_token_account(
|
|||||||
}
|
}
|
||||||
|
|
||||||
let post_states = vec![
|
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(token_definition.account.clone()),
|
||||||
AccountPostState::new(ata_account.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(
|
let chained_call = ChainedCall::new(
|
||||||
token_program_id,
|
token_program_id,
|
||||||
vec![token_definition.clone(), ata_account.clone()],
|
vec![token_definition.clone(), ata_account_auth],
|
||||||
&token_core::Instruction::InitializeAccount,
|
&token_core::Instruction::InitializeAccount,
|
||||||
);
|
)
|
||||||
|
.with_pda_seeds(vec![seed]);
|
||||||
(post_states, vec![chained_call])
|
(post_states, vec![chained_call])
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,8 @@
|
|||||||
use ata_core::{compute_ata_seed, get_associated_token_account_id};
|
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};
|
use token_core::{TokenDefinition, TokenHolding};
|
||||||
|
|
||||||
const ATA_PROGRAM_ID: nssa_core::program::ProgramId = [1u32; 8];
|
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!(post_states.len(), 3);
|
||||||
assert_eq!(chained_calls.len(), 1);
|
assert_eq!(post_states[0].required_claim(), Some(Claim::Authorized));
|
||||||
assert_eq!(chained_calls[0].program_id, TOKEN_PROGRAM_ID);
|
|
||||||
|
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]
|
#[test]
|
||||||
|
|||||||
@ -16,7 +16,7 @@ pub fn transfer_from_associated_token_account(
|
|||||||
let definition_id = TokenHolding::try_from(&sender_ata.account.data)
|
let definition_id = TokenHolding::try_from(&sender_ata.account.data)
|
||||||
.expect("Sender ATA must hold a valid token")
|
.expect("Sender ATA must hold a valid token")
|
||||||
.definition_id();
|
.definition_id();
|
||||||
let seed =
|
let sender_seed =
|
||||||
ata_core::verify_ata_and_get_seed(&sender_ata, &owner, definition_id, ata_program_id);
|
ata_core::verify_ata_and_get_seed(&sender_ata, &owner, definition_id, ata_program_id);
|
||||||
|
|
||||||
let post_states = vec![
|
let post_states = vec![
|
||||||
@ -29,11 +29,11 @@ pub fn transfer_from_associated_token_account(
|
|||||||
|
|
||||||
let chained_call = ChainedCall::new(
|
let chained_call = ChainedCall::new(
|
||||||
token_program_id,
|
token_program_id,
|
||||||
vec![sender_ata_auth, recipient.clone()],
|
vec![sender_ata_auth, recipient],
|
||||||
&token_core::Instruction::Transfer {
|
&token_core::Instruction::Transfer {
|
||||||
amount_to_transfer: amount,
|
amount_to_transfer: amount,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.with_pda_seeds(vec![seed]);
|
.with_pda_seeds(vec![sender_seed]);
|
||||||
(post_states, vec![chained_call])
|
(post_states, vec![chained_call])
|
||||||
}
|
}
|
||||||
|
|||||||
@ -809,6 +809,18 @@ impl Accounts {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn user_lp_holding_new_init() -> Account {
|
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 {
|
Account {
|
||||||
program_owner: Ids::token_program(),
|
program_owner: Ids::token_program(),
|
||||||
balance: 0_u128,
|
balance: 0_u128,
|
||||||
@ -895,7 +907,7 @@ fn deploy_programs(state: &mut V03State) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn state_for_amm_tests() -> 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);
|
deploy_programs(&mut state);
|
||||||
state.force_insert_account(Ids::pool_definition(), Accounts::pool_definition_init());
|
state.force_insert_account(Ids::pool_definition(), Accounts::pool_definition_init());
|
||||||
state.force_insert_account(
|
state.force_insert_account(
|
||||||
@ -919,7 +931,7 @@ fn state_for_amm_tests() -> V03State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn state_for_amm_tests_with_new_def() -> 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);
|
deploy_programs(&mut state);
|
||||||
state.force_insert_account(
|
state.force_insert_account(
|
||||||
Ids::token_a_definition(),
|
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
|
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 {
|
let instruction = amm_core::Instruction::NewDefinition {
|
||||||
token_a_amount: Balances::vault_a_init(),
|
token_a_amount: Balances::vault_a_init(),
|
||||||
token_b_amount: Balances::vault_b_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_b(),
|
||||||
Ids::user_lp(),
|
Ids::user_lp(),
|
||||||
],
|
],
|
||||||
vec![
|
if authorize_user_lp {
|
||||||
current_nonce(state, Ids::user_a()),
|
vec![
|
||||||
current_nonce(state, Ids::user_b()),
|
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,
|
instruction,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let witness_set =
|
let witness_set = if authorize_user_lp {
|
||||||
public_transaction::WitnessSet::for_message(&message, &[&Keys::user_a(), &Keys::user_b()]);
|
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);
|
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) {
|
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) {
|
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 witness_set = public_transaction::WitnessSet::for_message(&message, &[&Keys::user_a()]);
|
||||||
|
|
||||||
let tx = PublicTransaction::new(message, witness_set);
|
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) {
|
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 witness_set = public_transaction::WitnessSet::for_message(&message, &[&Keys::user_b()]);
|
||||||
|
|
||||||
let tx = PublicTransaction::new(message, witness_set);
|
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(
|
fn execute_add_liquidity(
|
||||||
@ -1066,7 +1102,7 @@ fn execute_add_liquidity(
|
|||||||
public_transaction::WitnessSet::for_message(&message, &[&Keys::user_a(), &Keys::user_b()]);
|
public_transaction::WitnessSet::for_message(&message, &[&Keys::user_a(), &Keys::user_b()]);
|
||||||
|
|
||||||
let tx = PublicTransaction::new(message, witness_set);
|
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(
|
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 witness_set = public_transaction::WitnessSet::for_message(&message, &[&Keys::user_lp()]);
|
||||||
|
|
||||||
let tx = PublicTransaction::new(message, witness_set);
|
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 {
|
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 witness_set = public_transaction::WitnessSet::for_message(&message, &[&Keys::user_lp()]);
|
||||||
|
|
||||||
let tx = PublicTransaction::new(message, witness_set);
|
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!(
|
assert_eq!(
|
||||||
state.get_account_by_id(Ids::pool_definition()),
|
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 witness_set = public_transaction::WitnessSet::for_message(&message, &[&Keys::user_lp()]);
|
||||||
|
|
||||||
let tx = PublicTransaction::new(message, witness_set);
|
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]
|
#[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]
|
#[test]
|
||||||
fn amm_new_definition_supports_all_fee_tiers() {
|
fn amm_new_definition_supports_all_fee_tiers() {
|
||||||
for fees in [
|
for fees in [
|
||||||
@ -1293,7 +1411,7 @@ fn amm_new_definition_supports_all_fee_tiers() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn amm_new_definition_rejects_unsupported_fee_tier_transaction() {
|
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_a(), Accounts::vault_a_reinitializable());
|
||||||
state.force_insert_account(Ids::vault_b(), Accounts::vault_b_reinitializable());
|
state.force_insert_account(Ids::vault_b(), Accounts::vault_b_reinitializable());
|
||||||
state.force_insert_account(
|
state.force_insert_account(
|
||||||
@ -1304,9 +1422,8 @@ fn amm_new_definition_rejects_unsupported_fee_tier_transaction() {
|
|||||||
Ids::token_lp_definition(),
|
Ids::token_lp_definition(),
|
||||||
Accounts::token_lp_definition_reinitializable(),
|
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!(matches!(result, Err(NssaError::ProgramExecutionFailed(_))));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -1369,7 +1486,7 @@ fn amm_add_liquidity() {
|
|||||||
public_transaction::WitnessSet::for_message(&message, &[&Keys::user_a(), &Keys::user_b()]);
|
public_transaction::WitnessSet::for_message(&message, &[&Keys::user_a(), &Keys::user_b()]);
|
||||||
|
|
||||||
let tx = PublicTransaction::new(message, witness_set);
|
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!(
|
assert_eq!(
|
||||||
state.get_account_by_id(Ids::pool_definition()),
|
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 witness_set = public_transaction::WitnessSet::for_message(&message, &[&Keys::user_b()]);
|
||||||
|
|
||||||
let tx = PublicTransaction::new(message, witness_set);
|
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!(
|
assert_eq!(
|
||||||
state.get_account_by_id(Ids::pool_definition()),
|
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 witness_set = public_transaction::WitnessSet::for_message(&message, &[&Keys::user_a()]);
|
||||||
|
|
||||||
let tx = PublicTransaction::new(message, witness_set);
|
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!(
|
assert_eq!(
|
||||||
state.get_account_by_id(Ids::pool_definition()),
|
state.get_account_by_id(Ids::pool_definition()),
|
||||||
|
|||||||
@ -93,6 +93,18 @@ impl Accounts {
|
|||||||
nonce: Nonce(0),
|
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) {
|
fn deploy_programs(state: &mut V03State) {
|
||||||
@ -113,16 +125,22 @@ fn deploy_programs(state: &mut V03State) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn state_for_ata_tests() -> 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);
|
deploy_programs(&mut state);
|
||||||
state.force_insert_account(Ids::token_definition(), Accounts::token_definition_init());
|
state.force_insert_account(Ids::token_definition(), Accounts::token_definition_init());
|
||||||
state.force_insert_account(Ids::owner_ata(), Accounts::owner_ata_init());
|
state.force_insert_account(Ids::owner_ata(), Accounts::owner_ata_init());
|
||||||
state
|
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]
|
#[test]
|
||||||
fn ata_create() {
|
fn ata_create() {
|
||||||
let mut state = V03State::new_with_genesis_accounts(&[], &[]);
|
let mut state = V03State::new_with_genesis_accounts(&[], &[], 0);
|
||||||
deploy_programs(&mut state);
|
deploy_programs(&mut state);
|
||||||
state.force_insert_account(Ids::token_definition(), Accounts::token_definition_init());
|
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 witness_set = public_transaction::WitnessSet::for_message(&message, &[&Keys::owner_key()]);
|
||||||
|
|
||||||
let tx = PublicTransaction::new(message, witness_set);
|
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!(
|
assert_eq!(
|
||||||
state.get_account_by_id(Ids::owner_ata()),
|
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 witness_set = public_transaction::WitnessSet::for_message(&message, &[&Keys::owner_key()]);
|
||||||
|
|
||||||
let tx = PublicTransaction::new(message, witness_set);
|
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
|
// Already initialized — should remain unchanged
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -195,7 +213,7 @@ fn ata_create_is_idempotent() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn ata_transfer() {
|
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 {
|
let instruction = ata_core::Instruction::Transfer {
|
||||||
ata_program_id: Ids::ata_program(),
|
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 witness_set = public_transaction::WitnessSet::for_message(&message, &[&Keys::owner_key()]);
|
||||||
|
|
||||||
let tx = PublicTransaction::new(message, witness_set);
|
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!(
|
assert_eq!(
|
||||||
state.get_account_by_id(Ids::owner_ata()),
|
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 witness_set = public_transaction::WitnessSet::for_message(&message, &[&Keys::owner_key()]);
|
||||||
|
|
||||||
let tx = PublicTransaction::new(message, witness_set);
|
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!(
|
assert_eq!(
|
||||||
state.get_account_by_id(Ids::owner_ata()),
|
state.get_account_by_id(Ids::owner_ata()),
|
||||||
@ -294,7 +312,7 @@ fn ata_burn() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn ata_create_from_private_owner() {
|
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);
|
deploy_programs(&mut state);
|
||||||
state.force_insert_account(Ids::token_definition(), Accounts::token_definition_init());
|
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 witness_set = WitnessSet::for_message(&message, proof, &[]);
|
||||||
let tx = PrivacyPreservingTransaction::new(message, witness_set);
|
let tx = PrivacyPreservingTransaction::new(message, witness_set);
|
||||||
state
|
state
|
||||||
.transition_from_privacy_preserving_transaction(&tx, 0)
|
.transition_from_privacy_preserving_transaction(&tx, 0, 0)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|||||||
@ -74,6 +74,18 @@ impl Accounts {
|
|||||||
nonce: Nonce(0),
|
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) {
|
fn deploy_token(state: &mut V03State) {
|
||||||
@ -85,7 +97,16 @@ fn deploy_token(state: &mut V03State) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn state_for_token_tests() -> 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);
|
deploy_token(&mut state);
|
||||||
state.force_insert_account(Ids::token_definition(), Accounts::token_definition_init());
|
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::holder(), Accounts::holder_init());
|
||||||
@ -94,7 +115,7 @@ fn state_for_token_tests() -> V03State {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn token_new_fungible_definition() {
|
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);
|
deploy_token(&mut state);
|
||||||
|
|
||||||
let instruction = token_core::Instruction::NewFungibleDefinition {
|
let instruction = token_core::Instruction::NewFungibleDefinition {
|
||||||
@ -116,7 +137,7 @@ fn token_new_fungible_definition() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let tx = PublicTransaction::new(message, witness_set);
|
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!(
|
assert_eq!(
|
||||||
state.get_account_by_id(Ids::token_definition()),
|
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 witness_set = public_transaction::WitnessSet::for_message(&message, &[&Keys::holder_key()]);
|
||||||
|
|
||||||
let tx = PublicTransaction::new(message, witness_set);
|
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!(
|
assert_eq!(
|
||||||
state.get_account_by_id(Ids::holder()),
|
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]
|
#[test]
|
||||||
fn token_burn() {
|
fn token_burn() {
|
||||||
let mut state = state_for_token_tests();
|
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 witness_set = public_transaction::WitnessSet::for_message(&message, &[&Keys::holder_key()]);
|
||||||
|
|
||||||
let tx = PublicTransaction::new(message, witness_set);
|
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!(
|
assert_eq!(
|
||||||
state.get_account_by_id(Ids::token_definition()),
|
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 witness_set = public_transaction::WitnessSet::for_message(&message, &[&Keys::def_key()]);
|
||||||
|
|
||||||
let tx = PublicTransaction::new(message, witness_set);
|
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!(
|
assert_eq!(
|
||||||
state.get_account_by_id(Ids::token_definition()),
|
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;
|
struct PrivateKeys;
|
||||||
|
|
||||||
impl 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 witness_set = WitnessSet::for_message(&message, proof, &[&Keys::holder_key()]);
|
||||||
let tx = PrivacyPreservingTransaction::new(message, witness_set);
|
let tx = PrivacyPreservingTransaction::new(message, witness_set);
|
||||||
state
|
state
|
||||||
.transition_from_privacy_preserving_transaction(&tx, 0)
|
.transition_from_privacy_preserving_transaction(&tx, 0, 0)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
Account {
|
Account {
|
||||||
@ -476,7 +662,7 @@ fn token_private_transfer() {
|
|||||||
let witness_set = WitnessSet::for_message(&message, proof, &[]);
|
let witness_set = WitnessSet::for_message(&message, proof, &[]);
|
||||||
let tx = PrivacyPreservingTransaction::new(message, witness_set);
|
let tx = PrivacyPreservingTransaction::new(message, witness_set);
|
||||||
state
|
state
|
||||||
.transition_from_privacy_preserving_transaction(&tx, 0)
|
.transition_from_privacy_preserving_transaction(&tx, 0, 0)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let sender_nonce_after =
|
let sender_nonce_after =
|
||||||
@ -559,7 +745,7 @@ fn token_deshielded_transfer() {
|
|||||||
let witness_set = WitnessSet::for_message(&message, proof, &[]);
|
let witness_set = WitnessSet::for_message(&message, proof, &[]);
|
||||||
let tx = PrivacyPreservingTransaction::new(message, witness_set);
|
let tx = PrivacyPreservingTransaction::new(message, witness_set);
|
||||||
state
|
state
|
||||||
.transition_from_privacy_preserving_transaction(&tx, 0)
|
.transition_from_privacy_preserving_transaction(&tx, 0, 0)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|||||||
@ -4,5 +4,5 @@ version = "0.1.0"
|
|||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[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" }
|
token_core = { path = "core" }
|
||||||
|
|||||||
@ -4,6 +4,6 @@ version = "0.1.0"
|
|||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[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"] }
|
borsh = { version = "1.5", features = ["derive"] }
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
|||||||
@ -10,23 +10,24 @@ pub enum Instruction {
|
|||||||
/// Transfer tokens from sender to recipient.
|
/// Transfer tokens from sender to recipient.
|
||||||
///
|
///
|
||||||
/// Required accounts:
|
/// Required accounts:
|
||||||
/// - Sender's Token Holding account (authorized),
|
/// - Sender's Token Holding account (initialized, authorized),
|
||||||
/// - Recipient's Token Holding account.
|
/// - Recipient's Token Holding account (initialized, or uninitialized with recipient
|
||||||
|
/// authorization in the same transaction).
|
||||||
Transfer { amount_to_transfer: u128 },
|
Transfer { amount_to_transfer: u128 },
|
||||||
|
|
||||||
/// Create a new fungible token definition without metadata.
|
/// Create a new fungible token definition without metadata.
|
||||||
///
|
///
|
||||||
/// Required accounts:
|
/// Required accounts:
|
||||||
/// - Token Definition account (uninitialized),
|
/// - Token Definition account (uninitialized, authorized),
|
||||||
/// - Token Holding account (uninitialized).
|
/// - Token Holding account (uninitialized, authorized).
|
||||||
NewFungibleDefinition { name: String, total_supply: u128 },
|
NewFungibleDefinition { name: String, total_supply: u128 },
|
||||||
|
|
||||||
/// Create a new fungible or non-fungible token definition with metadata.
|
/// Create a new fungible or non-fungible token definition with metadata.
|
||||||
///
|
///
|
||||||
/// Required accounts:
|
/// Required accounts:
|
||||||
/// - Token Definition account (uninitialized),
|
/// - Token Definition account (uninitialized, authorized),
|
||||||
/// - Token Holding account (uninitialized),
|
/// - Token Holding account (uninitialized, authorized),
|
||||||
/// - Token Metadata account (uninitialized).
|
/// - Token Metadata account (uninitialized, authorized).
|
||||||
NewDefinitionWithMetadata {
|
NewDefinitionWithMetadata {
|
||||||
new_definition: NewTokenDefinition,
|
new_definition: NewTokenDefinition,
|
||||||
/// Boxed to avoid large enum variant size
|
/// Boxed to avoid large enum variant size
|
||||||
@ -37,7 +38,7 @@ pub enum Instruction {
|
|||||||
///
|
///
|
||||||
/// Required accounts:
|
/// Required accounts:
|
||||||
/// - Token Definition account (initialized),
|
/// - Token Definition account (initialized),
|
||||||
/// - Token Holding account (uninitialized),
|
/// - Token Holding account (uninitialized, authorized),
|
||||||
InitializeAccount,
|
InitializeAccount,
|
||||||
|
|
||||||
/// Burn tokens from the holder's account.
|
/// Burn tokens from the holder's account.
|
||||||
@ -50,15 +51,16 @@ pub enum Instruction {
|
|||||||
/// Mint new tokens to the holder's account.
|
/// Mint new tokens to the holder's account.
|
||||||
///
|
///
|
||||||
/// Required accounts:
|
/// Required accounts:
|
||||||
/// - Token Definition account (authorized),
|
/// - Token Definition account (initialized, authorized),
|
||||||
/// - Token Holding account (uninitialized or initialized).
|
/// - Token Holding account (initialized, or uninitialized with holder authorization in the
|
||||||
|
/// same transaction).
|
||||||
Mint { amount_to_mint: u128 },
|
Mint { amount_to_mint: u128 },
|
||||||
|
|
||||||
/// Print a new NFT from the master copy.
|
/// Print a new NFT from the master copy.
|
||||||
///
|
///
|
||||||
/// Required accounts:
|
/// Required accounts:
|
||||||
/// - NFT Master Token Holding account (authorized),
|
/// - NFT Master Token Holding account (authorized),
|
||||||
/// - NFT Printed Copy Token Holding account (uninitialized).
|
/// - NFT Printed Copy Token Holding account (uninitialized, authorized).
|
||||||
PrintNft,
|
PrintNft,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
14
token/methods/guest/Cargo.lock
generated
14
token/methods/guest/Cargo.lock
generated
@ -1744,7 +1744,7 @@ checksum = "a5b0c77c1b780822bc749a33e39aeb2c07584ab93332303babeabb645298a76e"
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "nssa_core"
|
name = "nssa_core"
|
||||||
version = "0.1.0"
|
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 = [
|
dependencies = [
|
||||||
"base58",
|
"base58",
|
||||||
"borsh",
|
"borsh",
|
||||||
@ -2863,8 +2863,8 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "spel-framework"
|
name = "spel-framework"
|
||||||
version = "0.1.0"
|
version = "0.2.0"
|
||||||
source = "git+https://github.com/logos-co/spel.git?rev=57201f64b4542bb3f592bc9a0aa654c47aa908a6#57201f64b4542bb3f592bc9a0aa654c47aa908a6"
|
source = "git+https://github.com/logos-co/spel.git?tag=v0.2.0-rc.2#9005e9fbbd78b0530412f9987273f753ed32eb2d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"borsh",
|
"borsh",
|
||||||
"nssa_core",
|
"nssa_core",
|
||||||
@ -2874,8 +2874,8 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "spel-framework-core"
|
name = "spel-framework-core"
|
||||||
version = "0.1.0"
|
version = "0.2.0"
|
||||||
source = "git+https://github.com/logos-co/spel.git?rev=57201f64b4542bb3f592bc9a0aa654c47aa908a6#57201f64b4542bb3f592bc9a0aa654c47aa908a6"
|
source = "git+https://github.com/logos-co/spel.git?tag=v0.2.0-rc.2#9005e9fbbd78b0530412f9987273f753ed32eb2d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"borsh",
|
"borsh",
|
||||||
"nssa_core",
|
"nssa_core",
|
||||||
@ -2887,8 +2887,8 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "spel-framework-macros"
|
name = "spel-framework-macros"
|
||||||
version = "0.1.0"
|
version = "0.2.0"
|
||||||
source = "git+https://github.com/logos-co/spel.git?rev=57201f64b4542bb3f592bc9a0aa654c47aa908a6#57201f64b4542bb3f592bc9a0aa654c47aa908a6"
|
source = "git+https://github.com/logos-co/spel.git?tag=v0.2.0-rc.2#9005e9fbbd78b0530412f9987273f753ed32eb2d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
|||||||
@ -10,8 +10,8 @@ name = "token"
|
|||||||
path = "src/bin/token.rs"
|
path = "src/bin/token.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
spel-framework = { git = "https://github.com/logos-co/spel.git", rev = "57201f64b4542bb3f592bc9a0aa654c47aa908a6", package = "spel-framework" }
|
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", rev = "ffcbc15972adbf557939bf3e2852af276422631b" }
|
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 }
|
risc0-zkvm = { version = "=3.0.5", default-features = false }
|
||||||
token_core = { path = "../../core" }
|
token_core = { path = "../../core" }
|
||||||
token_program = { path = "../..", package = "token_program" }
|
token_program = { path = "../..", package = "token_program" }
|
||||||
|
|||||||
@ -11,6 +11,7 @@ mod token {
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
/// Transfer tokens from sender to recipient.
|
/// Transfer tokens from sender to recipient.
|
||||||
|
/// Fresh public recipients must be explicitly authorized in the same transaction.
|
||||||
#[instruction]
|
#[instruction]
|
||||||
pub fn transfer(
|
pub fn transfer(
|
||||||
sender: AccountWithMetadata,
|
sender: AccountWithMetadata,
|
||||||
@ -25,6 +26,7 @@ mod token {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new fungible token definition without metadata.
|
/// Create a new fungible token definition without metadata.
|
||||||
|
/// Definition and holding targets must be uninitialized and authorized.
|
||||||
#[instruction]
|
#[instruction]
|
||||||
pub fn new_fungible_definition(
|
pub fn new_fungible_definition(
|
||||||
definition_target_account: AccountWithMetadata,
|
definition_target_account: AccountWithMetadata,
|
||||||
@ -43,6 +45,7 @@ mod token {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new fungible or non-fungible token definition with metadata.
|
/// Create a new fungible or non-fungible token definition with metadata.
|
||||||
|
/// Definition, holding, and metadata targets must be uninitialized and authorized.
|
||||||
#[instruction]
|
#[instruction]
|
||||||
pub fn new_definition_with_metadata(
|
pub fn new_definition_with_metadata(
|
||||||
definition_target_account: AccountWithMetadata,
|
definition_target_account: AccountWithMetadata,
|
||||||
@ -63,6 +66,7 @@ mod token {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Initialize a token holding account for a given token definition.
|
/// Initialize a token holding account for a given token definition.
|
||||||
|
/// The holding target must be uninitialized and authorized.
|
||||||
#[instruction]
|
#[instruction]
|
||||||
pub fn initialize_account(
|
pub fn initialize_account(
|
||||||
definition_account: AccountWithMetadata,
|
definition_account: AccountWithMetadata,
|
||||||
@ -91,6 +95,7 @@ mod token {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Mint new tokens to the holder's account.
|
/// Mint new tokens to the holder's account.
|
||||||
|
/// Fresh public holders must be explicitly authorized in the same transaction.
|
||||||
#[instruction]
|
#[instruction]
|
||||||
pub fn mint(
|
pub fn mint(
|
||||||
definition_account: AccountWithMetadata,
|
definition_account: AccountWithMetadata,
|
||||||
@ -105,6 +110,7 @@ mod token {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Print a new NFT from the master copy.
|
/// Print a new NFT from the master copy.
|
||||||
|
/// The printed copy target must be uninitialized and authorized.
|
||||||
#[instruction]
|
#[instruction]
|
||||||
pub fn print_nft(
|
pub fn print_nft(
|
||||||
master_account: AccountWithMetadata,
|
master_account: AccountWithMetadata,
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
use nssa_core::{
|
use nssa_core::{
|
||||||
account::{Account, AccountWithMetadata, Data},
|
account::{Account, AccountWithMetadata, Data},
|
||||||
program::AccountPostState,
|
program::{AccountPostState, Claim},
|
||||||
};
|
};
|
||||||
use token_core::{TokenDefinition, TokenHolding};
|
use token_core::{TokenDefinition, TokenHolding};
|
||||||
|
|
||||||
@ -13,6 +13,10 @@ pub fn initialize_account(
|
|||||||
Account::default(),
|
Account::default(),
|
||||||
"Only Uninitialized accounts can be initialized"
|
"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.
|
// 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
|
// 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![
|
vec![
|
||||||
AccountPostState::new(definition_post),
|
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::{
|
use nssa_core::{
|
||||||
account::{Account, AccountWithMetadata, Data},
|
account::{Account, AccountWithMetadata, Data},
|
||||||
program::AccountPostState,
|
program::{AccountPostState, Claim},
|
||||||
};
|
};
|
||||||
use token_core::{TokenDefinition, TokenHolding};
|
use token_core::{TokenDefinition, TokenHolding};
|
||||||
|
|
||||||
@ -66,6 +66,6 @@ pub fn mint(
|
|||||||
|
|
||||||
vec![
|
vec![
|
||||||
AccountPostState::new(definition_post),
|
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::{
|
use nssa_core::{
|
||||||
account::{Account, AccountWithMetadata, Data},
|
account::{Account, AccountWithMetadata, Data},
|
||||||
program::AccountPostState,
|
program::{AccountPostState, Claim},
|
||||||
};
|
};
|
||||||
use token_core::{
|
use token_core::{
|
||||||
NewTokenDefinition, NewTokenMetadata, TokenDefinition, TokenHolding, TokenMetadata,
|
NewTokenDefinition, NewTokenMetadata, TokenDefinition, TokenHolding, TokenMetadata,
|
||||||
@ -23,6 +23,14 @@ pub fn new_fungible_definition(
|
|||||||
Account::default(),
|
Account::default(),
|
||||||
"Holding target account must have default values"
|
"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 {
|
let token_definition = TokenDefinition::Fungible {
|
||||||
name,
|
name,
|
||||||
@ -41,8 +49,8 @@ pub fn new_fungible_definition(
|
|||||||
holding_target_account_post.data = Data::from(&token_holding);
|
holding_target_account_post.data = Data::from(&token_holding);
|
||||||
|
|
||||||
vec![
|
vec![
|
||||||
AccountPostState::new_claimed(definition_target_account_post),
|
AccountPostState::new_claimed(definition_target_account_post, Claim::Authorized),
|
||||||
AccountPostState::new_claimed(holding_target_account_post),
|
AccountPostState::new_claimed(holding_target_account_post, Claim::Authorized),
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,6 +78,18 @@ pub fn new_definition_with_metadata(
|
|||||||
Account::default(),
|
Account::default(),
|
||||||
"Metadata target account must have default values"
|
"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 {
|
let (token_definition, token_holding) = match new_definition {
|
||||||
NewTokenDefinition::Fungible { name, total_supply } => (
|
NewTokenDefinition::Fungible { name, total_supply } => (
|
||||||
@ -117,8 +137,8 @@ pub fn new_definition_with_metadata(
|
|||||||
metadata_target_account_post.data = Data::from(&token_metadata);
|
metadata_target_account_post.data = Data::from(&token_metadata);
|
||||||
|
|
||||||
vec![
|
vec![
|
||||||
AccountPostState::new_claimed(definition_target_account_post),
|
AccountPostState::new_claimed(definition_target_account_post, Claim::Authorized),
|
||||||
AccountPostState::new_claimed(holding_target_account_post),
|
AccountPostState::new_claimed(holding_target_account_post, Claim::Authorized),
|
||||||
AccountPostState::new_claimed(metadata_target_account_post),
|
AccountPostState::new_claimed(metadata_target_account_post, Claim::Authorized),
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
use nssa_core::{
|
use nssa_core::{
|
||||||
account::{Account, AccountWithMetadata, Data},
|
account::{Account, AccountWithMetadata, Data},
|
||||||
program::AccountPostState,
|
program::{AccountPostState, Claim},
|
||||||
};
|
};
|
||||||
use token_core::TokenHolding;
|
use token_core::TokenHolding;
|
||||||
|
|
||||||
@ -18,6 +18,10 @@ pub fn print_nft(
|
|||||||
Account::default(),
|
Account::default(),
|
||||||
"Printed Account must be uninitialized"
|
"Printed Account must be uninitialized"
|
||||||
);
|
);
|
||||||
|
assert!(
|
||||||
|
printed_account.is_authorized,
|
||||||
|
"Printed Account must be authorized"
|
||||||
|
);
|
||||||
|
|
||||||
let mut master_account_data =
|
let mut master_account_data =
|
||||||
TokenHolding::try_from(&master_account.account.data).expect("Invalid Token Holding data");
|
TokenHolding::try_from(&master_account.account.data).expect("Invalid Token Holding data");
|
||||||
@ -49,6 +53,6 @@ pub fn print_nft(
|
|||||||
|
|
||||||
vec![
|
vec![
|
||||||
AccountPostState::new(master_account_post),
|
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)]
|
#![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::{
|
use token_core::{
|
||||||
MetadataStandard, NewTokenDefinition, NewTokenMetadata, TokenDefinition, TokenHolding,
|
MetadataStandard, NewTokenDefinition, NewTokenMetadata, TokenDefinition, TokenHolding,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
burn::burn,
|
burn::burn,
|
||||||
|
initialize::initialize_account,
|
||||||
mint::mint,
|
mint::mint,
|
||||||
new_definition::{new_definition_with_metadata, new_fungible_definition},
|
new_definition::{new_definition_with_metadata, new_fungible_definition},
|
||||||
print_nft::print_nft,
|
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 {
|
fn init_mint() -> AccountWithMetadata {
|
||||||
AccountWithMetadata {
|
AccountWithMetadata {
|
||||||
account: Account {
|
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 {
|
fn holding_account_init() -> AccountWithMetadata {
|
||||||
AccountWithMetadata {
|
AccountWithMetadata {
|
||||||
account: Account {
|
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]
|
#[test]
|
||||||
fn test_new_definition_with_valid_inputs_succeeds() {
|
fn test_new_definition_with_valid_inputs_succeeds() {
|
||||||
let definition_account = AccountForTests::definition_account_uninit();
|
let definition_account = AccountForTests::definition_account_uninit_auth();
|
||||||
let holding_account = AccountForTests::holding_account_uninit();
|
let holding_account = AccountForTests::holding_account_uninit_auth();
|
||||||
|
|
||||||
let post_states = new_fungible_definition(
|
let post_states = new_fungible_definition(
|
||||||
definition_account,
|
definition_account,
|
||||||
@ -586,11 +640,13 @@ fn test_new_definition_with_valid_inputs_succeeds() {
|
|||||||
*definition_account.account(),
|
*definition_account.account(),
|
||||||
AccountForTests::definition_account_unclaimed().account
|
AccountForTests::definition_account_unclaimed().account
|
||||||
);
|
);
|
||||||
|
assert_eq!(definition_account.required_claim(), Some(Claim::Authorized));
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
*holding_account.account(),
|
*holding_account.account(),
|
||||||
AccountForTests::holding_account_unclaimed().account
|
AccountForTests::holding_account_unclaimed().account
|
||||||
);
|
);
|
||||||
|
assert_eq!(holding_account.required_claim(), Some(Claim::Authorized));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[should_panic(expected = "Sender and recipient definition id mismatch")]
|
#[should_panic(expected = "Sender and recipient definition id mismatch")]
|
||||||
@ -633,6 +689,8 @@ fn test_transfer_with_valid_inputs_succeeds() {
|
|||||||
*recipient_post.account(),
|
*recipient_post.account(),
|
||||||
AccountForTests::holding_account2_init_post_transfer().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")]
|
#[should_panic(expected = "Invalid balance for NFT Master transfer")]
|
||||||
@ -669,9 +727,9 @@ fn test_transfer_with_master_nft_success() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_token_initialize_account_succeeds() {
|
fn test_transfer_with_default_recipient_claims_recipient() {
|
||||||
let sender = AccountForTests::holding_account_init();
|
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 post_states = transfer(sender, recipient, BalanceForTests::transfer_amount());
|
||||||
let [sender_post, recipient_post] = post_states.try_into().unwrap();
|
let [sender_post, recipient_post] = post_states.try_into().unwrap();
|
||||||
|
|
||||||
@ -681,8 +739,53 @@ fn test_token_initialize_account_succeeds() {
|
|||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
*recipient_post.account(),
|
*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]
|
#[test]
|
||||||
@ -824,6 +927,8 @@ fn test_mint_success() {
|
|||||||
*holding_post.account(),
|
*holding_post.account(),
|
||||||
AccountForTests::holding_account_same_definition_mint().account
|
AccountForTests::holding_account_same_definition_mint().account
|
||||||
);
|
);
|
||||||
|
assert_eq!(def_post.required_claim(), None);
|
||||||
|
assert_eq!(holding_post.required_claim(), None);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -846,7 +951,8 @@ fn test_mint_uninit_holding_success() {
|
|||||||
*holding_post.account(),
|
*holding_post.account(),
|
||||||
AccountForTests::init_mint().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]
|
#[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")]
|
#[should_panic(expected = "Definition target account must have default values")]
|
||||||
#[test]
|
#[test]
|
||||||
fn test_call_new_definition_metadata_with_init_definition() {
|
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);
|
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")]
|
#[should_panic(expected = "Invalid Token Holding data")]
|
||||||
#[test]
|
#[test]
|
||||||
fn test_print_nft_master_nft_invalid_token_holding() {
|
fn test_print_nft_master_nft_invalid_token_holding() {
|
||||||
let master_account = AccountForTests::definition_account_auth();
|
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);
|
let _post_states = print_nft(master_account, printed_account);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1009,7 +1228,7 @@ fn test_print_nft_master_nft_invalid_token_holding() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_print_nft_master_nft_not_nft_master_account() {
|
fn test_print_nft_master_nft_not_nft_master_account() {
|
||||||
let master_account = AccountForTests::holding_account_init();
|
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);
|
let _post_states = print_nft(master_account, printed_account);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1017,14 +1236,14 @@ fn test_print_nft_master_nft_not_nft_master_account() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_print_nft_master_nft_insufficient_balance() {
|
fn test_print_nft_master_nft_insufficient_balance() {
|
||||||
let master_account = AccountForTests::holding_account_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);
|
let _post_states = print_nft(master_account, printed_account);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_print_nft_success() {
|
fn test_print_nft_success() {
|
||||||
let master_account = AccountForTests::holding_account_master_nft();
|
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_states = print_nft(master_account, printed_account);
|
||||||
|
|
||||||
let [post_master_nft, post_printed] = post_states.try_into().unwrap();
|
let [post_master_nft, post_printed] = post_states.try_into().unwrap();
|
||||||
@ -1037,4 +1256,6 @@ fn test_print_nft_success() {
|
|||||||
*post_printed.account(),
|
*post_printed.account(),
|
||||||
AccountForTests::holding_account_printed_nft().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::{
|
use nssa_core::{
|
||||||
account::{Account, AccountWithMetadata, Data},
|
account::{Account, AccountWithMetadata, Data},
|
||||||
program::AccountPostState,
|
program::{AccountPostState, Claim},
|
||||||
};
|
};
|
||||||
use token_core::TokenHolding;
|
use token_core::TokenHolding;
|
||||||
|
|
||||||
@ -105,6 +105,6 @@ pub fn transfer(
|
|||||||
|
|
||||||
vec![
|
vec![
|
||||||
AccountPostState::new(sender_post),
|
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"
|
path = "src/main.rs"
|
||||||
|
|
||||||
[dependencies]
|
[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",
|
"idl-gen",
|
||||||
] }
|
] }
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user