diff --git a/Cargo.lock b/Cargo.lock index 3c8bc58..8b8b327 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2970,7 +2970,7 @@ dependencies = [ [[package]] name = "spel-framework-core" version = "0.2.0" -source = "git+https://github.com/logos-co/spel.git?rev=ba6e87d086ed85c5ac095325d8a28f02e3d33ca2#ba6e87d086ed85c5ac095325d8a28f02e3d33ca2" +source = "git+https://github.com/logos-co/spel.git?rev=6473ab4c400bc59bac8db83a286faaeafa7d1999#6473ab4c400bc59bac8db83a286faaeafa7d1999" dependencies = [ "borsh", "nssa_core", @@ -2985,7 +2985,7 @@ dependencies = [ [[package]] name = "spel-framework-macros" version = "0.2.0" -source = "git+https://github.com/logos-co/spel.git?rev=ba6e87d086ed85c5ac095325d8a28f02e3d33ca2#ba6e87d086ed85c5ac095325d8a28f02e3d33ca2" +source = "git+https://github.com/logos-co/spel.git?rev=6473ab4c400bc59bac8db83a286faaeafa7d1999#6473ab4c400bc59bac8db83a286faaeafa7d1999" dependencies = [ "proc-macro2", "quote", diff --git a/amm/core/Cargo.toml b/amm/core/Cargo.toml index 1d095a7..7fe2729 100644 --- a/amm/core/Cargo.toml +++ b/amm/core/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" [dependencies] nssa_core = { git = "https://github.com/logos-blockchain/logos-execution-zone.git", tag = "v0.2.0-rc3", features = ["host"] } -spel-framework-macros = { git = "https://github.com/logos-co/spel.git", rev = "ba6e87d086ed85c5ac095325d8a28f02e3d33ca2", package = "spel-framework-macros" } +spel-framework-macros = { git = "https://github.com/logos-co/spel.git", rev = "6473ab4c400bc59bac8db83a286faaeafa7d1999", package = "spel-framework-macros" } token_core = { path = "../../token/core" } borsh = { version = "1.5", features = ["derive"] } serde = { version = "1.0", features = ["derive"] } diff --git a/amm/core/src/lib.rs b/amm/core/src/lib.rs index 9c74337..60366df 100644 --- a/amm/core/src/lib.rs +++ b/amm/core/src/lib.rs @@ -26,7 +26,7 @@ pub enum Instruction { /// - Vault Holding Account for Token A /// - Vault Holding Account for Token B /// - Pool Liquidity Token Definition - /// - LP Lock Holding Account, derived as `compute_lp_lock_holding_pda(amm_program_id, + /// - LP Lock Holding Account, derived as `compute_lp_lock_holding_pda(self_program_id, /// pool.account_id)` /// - User Holding Account for Token A (authorized) /// - User Holding Account for Token B (authorized) @@ -35,7 +35,6 @@ pub enum Instruction { token_a_amount: u128, token_b_amount: u128, fees: u128, - amm_program_id: ProgramId, /// Unix timestamp (milliseconds) after which this transaction is invalid. deadline: u64, }, diff --git a/amm/methods/guest/Cargo.lock b/amm/methods/guest/Cargo.lock index ab6b1b1..b1c7136 100644 --- a/amm/methods/guest/Cargo.lock +++ b/amm/methods/guest/Cargo.lock @@ -2892,7 +2892,7 @@ dependencies = [ [[package]] name = "spel-framework" version = "0.2.0" -source = "git+https://github.com/logos-co/spel.git?rev=ba6e87d086ed85c5ac095325d8a28f02e3d33ca2#ba6e87d086ed85c5ac095325d8a28f02e3d33ca2" +source = "git+https://github.com/logos-co/spel.git?rev=6473ab4c400bc59bac8db83a286faaeafa7d1999#6473ab4c400bc59bac8db83a286faaeafa7d1999" dependencies = [ "borsh", "nssa_core", @@ -2904,7 +2904,7 @@ dependencies = [ [[package]] name = "spel-framework-core" version = "0.2.0" -source = "git+https://github.com/logos-co/spel.git?rev=ba6e87d086ed85c5ac095325d8a28f02e3d33ca2#ba6e87d086ed85c5ac095325d8a28f02e3d33ca2" +source = "git+https://github.com/logos-co/spel.git?rev=6473ab4c400bc59bac8db83a286faaeafa7d1999#6473ab4c400bc59bac8db83a286faaeafa7d1999" dependencies = [ "borsh", "nssa_core", @@ -2919,7 +2919,7 @@ dependencies = [ [[package]] name = "spel-framework-macros" version = "0.2.0" -source = "git+https://github.com/logos-co/spel.git?rev=ba6e87d086ed85c5ac095325d8a28f02e3d33ca2#ba6e87d086ed85c5ac095325d8a28f02e3d33ca2" +source = "git+https://github.com/logos-co/spel.git?rev=6473ab4c400bc59bac8db83a286faaeafa7d1999#6473ab4c400bc59bac8db83a286faaeafa7d1999" dependencies = [ "proc-macro2", "quote", diff --git a/amm/methods/guest/Cargo.toml b/amm/methods/guest/Cargo.toml index 29d14d4..c878494 100644 --- a/amm/methods/guest/Cargo.toml +++ b/amm/methods/guest/Cargo.toml @@ -10,7 +10,7 @@ name = "amm" path = "src/bin/amm.rs" [dependencies] -spel-framework = { git = "https://github.com/logos-co/spel.git", rev = "ba6e87d086ed85c5ac095325d8a28f02e3d33ca2", package = "spel-framework" } +spel-framework = { git = "https://github.com/logos-co/spel.git", rev = "6473ab4c400bc59bac8db83a286faaeafa7d1999", package = "spel-framework" } nssa_core = { git = "https://github.com/logos-blockchain/logos-execution-zone.git", tag = "v0.2.0-rc3" } risc0-zkvm = { version = "=3.0.5", default-features = false } amm_core = { path = "../../core" } diff --git a/amm/methods/guest/src/bin/amm.rs b/amm/methods/guest/src/bin/amm.rs index 6fa3aef..99356f1 100644 --- a/amm/methods/guest/src/bin/amm.rs +++ b/amm/methods/guest/src/bin/amm.rs @@ -3,9 +3,9 @@ use std::num::NonZeroU128; use spel_framework::prelude::*; +use spel_framework::context::ProgramContext; use nssa_core::{ account::{AccountId, AccountWithMetadata}, - program::ProgramId, }; risc0_zkvm::guest::entry!(main); @@ -19,6 +19,7 @@ mod amm { /// A fresh user LP holding must be explicitly authorized by the caller. #[instruction] pub fn new_definition( + ctx: ProgramContext, pool: AccountWithMetadata, vault_a: AccountWithMetadata, vault_b: AccountWithMetadata, @@ -30,7 +31,6 @@ mod amm { token_a_amount: u128, token_b_amount: u128, fees: u128, - amm_program_id: ProgramId, deadline: u64, ) -> SpelResult { let (post_states, chained_calls) = amm_program::new_definition::new_definition( @@ -45,7 +45,7 @@ mod amm { NonZeroU128::new(token_a_amount).expect("token_a_amount must be nonzero"), NonZeroU128::new(token_b_amount).expect("token_b_amount must be nonzero"), fees, - amm_program_id, + ctx.self_program_id, ); Ok(spel_framework::SpelOutput::execute(post_states, chained_calls) .with_timestamp_validity_window(..deadline)) diff --git a/artifacts/amm-idl.json b/artifacts/amm-idl.json index 123f2fc..b89de30 100644 --- a/artifacts/amm-idl.json +++ b/artifacts/amm-idl.json @@ -67,10 +67,6 @@ "name": "fees", "type": "u128" }, - { - "name": "amm_program_id", - "type": "program_id" - }, { "name": "deadline", "type": "u64" diff --git a/artifacts/ata-idl.json b/artifacts/ata-idl.json index 2d49320..53818d0 100644 --- a/artifacts/ata-idl.json +++ b/artifacts/ata-idl.json @@ -24,12 +24,7 @@ "init": false } ], - "args": [ - { - "name": "ata_program_id", - "type": "program_id" - } - ] + "args": [] }, { "name": "transfer", @@ -54,10 +49,6 @@ } ], "args": [ - { - "name": "ata_program_id", - "type": "program_id" - }, { "name": "amount", "type": "u128" @@ -87,10 +78,6 @@ } ], "args": [ - { - "name": "ata_program_id", - "type": "program_id" - }, { "name": "amount", "type": "u128" diff --git a/ata/core/src/lib.rs b/ata/core/src/lib.rs index fb75ae2..b6862d0 100644 --- a/ata/core/src/lib.rs +++ b/ata/core/src/lib.rs @@ -16,7 +16,7 @@ pub enum Instruction { /// - Associated token account (default/uninitialized, or already initialized) /// /// `token_program_id` is derived from `token_definition.account.program_owner`. - Create { ata_program_id: ProgramId }, + Create, /// Transfer tokens FROM owner's ATA to a recipient token holding account. /// Uses ATA PDA seeds to authorize the chained Token::Transfer call. @@ -27,10 +27,7 @@ pub enum Instruction { /// - Recipient token holding (must be initialized) /// /// `token_program_id` is derived from `sender_ata.account.program_owner`. - Transfer { - ata_program_id: ProgramId, - amount: u128, - }, + Transfer { amount: u128 }, /// Burn tokens FROM owner's ATA. /// Uses PDA seeds to authorize the ATA in the chained Token::Burn call. @@ -41,10 +38,7 @@ pub enum Instruction { /// - Token definition account /// /// `token_program_id` is derived from `holder_ata.account.program_owner`. - Burn { - ata_program_id: ProgramId, - amount: u128, - }, + Burn { amount: u128 }, } pub fn compute_ata_seed(owner_id: AccountId, definition_id: AccountId) -> PdaSeed { diff --git a/ata/methods/guest/Cargo.lock b/ata/methods/guest/Cargo.lock index 8b0be85..fe7116a 100644 --- a/ata/methods/guest/Cargo.lock +++ b/ata/methods/guest/Cargo.lock @@ -2890,7 +2890,7 @@ dependencies = [ [[package]] name = "spel-framework" version = "0.2.0" -source = "git+https://github.com/logos-co/spel.git?rev=ba6e87d086ed85c5ac095325d8a28f02e3d33ca2#ba6e87d086ed85c5ac095325d8a28f02e3d33ca2" +source = "git+https://github.com/logos-co/spel.git?rev=6473ab4c400bc59bac8db83a286faaeafa7d1999#6473ab4c400bc59bac8db83a286faaeafa7d1999" dependencies = [ "borsh", "nssa_core", @@ -2902,7 +2902,7 @@ dependencies = [ [[package]] name = "spel-framework-core" version = "0.2.0" -source = "git+https://github.com/logos-co/spel.git?rev=ba6e87d086ed85c5ac095325d8a28f02e3d33ca2#ba6e87d086ed85c5ac095325d8a28f02e3d33ca2" +source = "git+https://github.com/logos-co/spel.git?rev=6473ab4c400bc59bac8db83a286faaeafa7d1999#6473ab4c400bc59bac8db83a286faaeafa7d1999" dependencies = [ "borsh", "nssa_core", @@ -2917,7 +2917,7 @@ dependencies = [ [[package]] name = "spel-framework-macros" version = "0.2.0" -source = "git+https://github.com/logos-co/spel.git?rev=ba6e87d086ed85c5ac095325d8a28f02e3d33ca2#ba6e87d086ed85c5ac095325d8a28f02e3d33ca2" +source = "git+https://github.com/logos-co/spel.git?rev=6473ab4c400bc59bac8db83a286faaeafa7d1999#6473ab4c400bc59bac8db83a286faaeafa7d1999" dependencies = [ "proc-macro2", "quote", diff --git a/ata/methods/guest/Cargo.toml b/ata/methods/guest/Cargo.toml index c676c44..db4b128 100644 --- a/ata/methods/guest/Cargo.toml +++ b/ata/methods/guest/Cargo.toml @@ -10,7 +10,7 @@ name = "ata" path = "src/bin/ata.rs" [dependencies] -spel-framework = { git = "https://github.com/logos-co/spel.git", rev = "ba6e87d086ed85c5ac095325d8a28f02e3d33ca2", package = "spel-framework" } +spel-framework = { git = "https://github.com/logos-co/spel.git", rev = "6473ab4c400bc59bac8db83a286faaeafa7d1999", package = "spel-framework" } nssa_core = { git = "https://github.com/logos-blockchain/logos-execution-zone.git", tag = "v0.2.0-rc3" } risc0-zkvm = { version = "=3.0.5", default-features = false } ata_core = { path = "../../core" } diff --git a/ata/methods/guest/src/bin/ata.rs b/ata/methods/guest/src/bin/ata.rs index b3020a0..fb8e1c1 100644 --- a/ata/methods/guest/src/bin/ata.rs +++ b/ata/methods/guest/src/bin/ata.rs @@ -1,7 +1,8 @@ #![no_main] use spel_framework::prelude::*; -use nssa_core::{account::AccountWithMetadata, program::ProgramId}; +use spel_framework::context::ProgramContext; +use nssa_core::account::AccountWithMetadata; risc0_zkvm::guest::entry!(main); @@ -14,16 +15,16 @@ mod ata { /// Idempotent: no-op if the account already exists. #[instruction] pub fn create( + ctx: ProgramContext, owner: AccountWithMetadata, token_definition: AccountWithMetadata, ata_account: AccountWithMetadata, - ata_program_id: ProgramId, ) -> SpelResult { let (post_states, chained_calls) = ata_program::create::create_associated_token_account( owner, token_definition, ata_account, - ata_program_id, + ctx.self_program_id, ); Ok(spel_framework::SpelOutput::execute(post_states, chained_calls)) } @@ -32,10 +33,10 @@ mod ata { /// The recipient holding account must already be initialized. #[instruction] pub fn transfer( + ctx: ProgramContext, owner: AccountWithMetadata, sender_ata: AccountWithMetadata, recipient: AccountWithMetadata, - ata_program_id: ProgramId, amount: u128, ) -> SpelResult { let (post_states, chained_calls) = @@ -43,7 +44,7 @@ mod ata { owner, sender_ata, recipient, - ata_program_id, + ctx.self_program_id, amount, ); Ok(spel_framework::SpelOutput::execute(post_states, chained_calls)) @@ -52,10 +53,10 @@ mod ata { /// Burn tokens FROM owner's ATA. #[instruction] pub fn burn( + ctx: ProgramContext, owner: AccountWithMetadata, holder_ata: AccountWithMetadata, token_definition: AccountWithMetadata, - ata_program_id: ProgramId, amount: u128, ) -> SpelResult { let (post_states, chained_calls) = @@ -63,7 +64,7 @@ mod ata { owner, holder_ata, token_definition, - ata_program_id, + ctx.self_program_id, amount, ); Ok(spel_framework::SpelOutput::execute(post_states, chained_calls)) diff --git a/integration_tests/tests/amm.rs b/integration_tests/tests/amm.rs index 7073fe8..ada0f46 100644 --- a/integration_tests/tests/amm.rs +++ b/integration_tests/tests/amm.rs @@ -965,7 +965,6 @@ fn try_execute_new_definition( token_a_amount: Balances::vault_a_init(), token_b_amount: Balances::vault_b_init(), fees, - amm_program_id: Ids::amm_program(), deadline: u64::MAX, }; @@ -1844,7 +1843,6 @@ fn amm_new_definition_rejects_expired_deadline() { token_a_amount: Balances::vault_a_init(), token_b_amount: Balances::vault_b_init(), fees: amm_core::FEE_TIER_BPS_30, - amm_program_id: Ids::amm_program(), deadline: deadline_ms, }; diff --git a/integration_tests/tests/ata.rs b/integration_tests/tests/ata.rs index 41d36a1..9a5da73 100644 --- a/integration_tests/tests/ata.rs +++ b/integration_tests/tests/ata.rs @@ -144,9 +144,7 @@ fn ata_create() { deploy_programs(&mut state); state.force_insert_account(Ids::token_definition(), Accounts::token_definition_init()); - let instruction = ata_core::Instruction::Create { - ata_program_id: Ids::ata_program(), - }; + let instruction = ata_core::Instruction::Create; let message = public_transaction::Message::try_new( Ids::ata_program(), @@ -179,9 +177,7 @@ fn ata_create() { fn ata_create_is_idempotent() { let mut state = state_for_ata_tests(); - let instruction = ata_core::Instruction::Create { - ata_program_id: Ids::ata_program(), - }; + let instruction = ata_core::Instruction::Create; let message = public_transaction::Message::try_new( Ids::ata_program(), @@ -216,7 +212,6 @@ fn ata_transfer() { let mut state = state_for_ata_tests_with_precreated_recipient_ata(); let instruction = ata_core::Instruction::Transfer { - ata_program_id: Ids::ata_program(), amount: 400_000_u128, }; @@ -265,7 +260,6 @@ fn ata_burn() { let mut state = state_for_ata_tests(); let instruction = ata_core::Instruction::Burn { - ata_program_id: Ids::ata_program(), amount: 300_000_u128, }; @@ -337,9 +331,7 @@ fn ata_create_from_private_owner() { ); let ata_pre = AccountWithMetadata::new(Account::default(), false, owner_ata_id); - let instruction = ata_core::Instruction::Create { - ata_program_id: Ids::ata_program(), - }; + let instruction = ata_core::Instruction::Create; let instruction_data = Program::serialize_instruction(instruction).unwrap(); // Ephemeral key for encrypting the private owner's post-state diff --git a/integration_tests/tests/token.rs b/integration_tests/tests/token.rs index 01772d0..e0b552b 100644 --- a/integration_tests/tests/token.rs +++ b/integration_tests/tests/token.rs @@ -36,6 +36,10 @@ impl Ids { token_methods::TOKEN_ID } + fn foreign_token_program() -> nssa_core::program::ProgramId { + [0xfeed_u32; 8] + } + fn token_definition() -> AccountId { AccountId::from(&PublicKey::new_from_private_key(&Keys::def_key())) } @@ -63,6 +67,19 @@ impl Accounts { } } + fn token_definition_foreign_owner() -> Account { + Account { + program_owner: Ids::foreign_token_program(), + balance: 0_u128, + data: Data::from(&TokenDefinition::Fungible { + name: String::from("Gold"), + total_supply: 1_000_000_u128, + metadata_id: None, + }), + nonce: Nonce(0), + } + } + fn holder_init() -> Account { Account { program_owner: Ids::token_program(), @@ -167,6 +184,78 @@ fn token_new_fungible_definition() { ); } +#[test] +fn token_initialize_account_succeeds_for_canonical_definition() { + let mut state = state_for_token_tests_without_recipient(); + + let instruction = token_core::Instruction::InitializeAccount; + + 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::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()), + Accounts::token_definition_init() + ); + 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: 0_u128, + }), + nonce: Nonce(1), + } + ); +} + +#[test] +fn token_initialize_account_rejects_foreign_owned_definition() { + let mut state = state_for_token_tests_without_recipient(); + state.force_insert_account( + Ids::token_definition(), + Accounts::token_definition_foreign_owner(), + ); + + let instruction = token_core::Instruction::InitializeAccount; + + 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::recipient_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_foreign_owner() + ); + assert_eq!( + state.get_account_by_id(Ids::recipient()), + Account::default() + ); +} + #[test] fn token_transfer() { let mut state = state_for_token_tests(); @@ -395,6 +484,44 @@ fn token_mint() { ); } +#[test] +fn token_mint_rejects_foreign_owned_definition() { + let mut state = state_for_token_tests_without_recipient(); + state.force_insert_account( + Ids::token_definition(), + Accounts::token_definition_foreign_owner(), + ); + + 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); + assert!(state.transition_from_public_transaction(&tx, 0, 0).is_err()); + + assert_eq!( + state.get_account_by_id(Ids::token_definition()), + Accounts::token_definition_foreign_owner() + ); + assert_eq!( + state.get_account_by_id(Ids::recipient()), + Account::default() + ); +} + #[test] fn token_mint_fresh_public_recipient_requires_authorization() { let mut state = state_for_token_tests_without_recipient(); diff --git a/stablecoin/methods/guest/Cargo.lock b/stablecoin/methods/guest/Cargo.lock index 7697add..b8d5a21 100644 --- a/stablecoin/methods/guest/Cargo.lock +++ b/stablecoin/methods/guest/Cargo.lock @@ -2857,7 +2857,7 @@ dependencies = [ [[package]] name = "spel-framework" version = "0.2.0" -source = "git+https://github.com/logos-co/spel.git?rev=ba6e87d086ed85c5ac095325d8a28f02e3d33ca2#ba6e87d086ed85c5ac095325d8a28f02e3d33ca2" +source = "git+https://github.com/logos-co/spel.git?rev=6473ab4c400bc59bac8db83a286faaeafa7d1999#6473ab4c400bc59bac8db83a286faaeafa7d1999" dependencies = [ "borsh", "nssa_core", @@ -2869,7 +2869,7 @@ dependencies = [ [[package]] name = "spel-framework-core" version = "0.2.0" -source = "git+https://github.com/logos-co/spel.git?rev=ba6e87d086ed85c5ac095325d8a28f02e3d33ca2#ba6e87d086ed85c5ac095325d8a28f02e3d33ca2" +source = "git+https://github.com/logos-co/spel.git?rev=6473ab4c400bc59bac8db83a286faaeafa7d1999#6473ab4c400bc59bac8db83a286faaeafa7d1999" dependencies = [ "borsh", "nssa_core", @@ -2884,7 +2884,7 @@ dependencies = [ [[package]] name = "spel-framework-macros" version = "0.2.0" -source = "git+https://github.com/logos-co/spel.git?rev=ba6e87d086ed85c5ac095325d8a28f02e3d33ca2#ba6e87d086ed85c5ac095325d8a28f02e3d33ca2" +source = "git+https://github.com/logos-co/spel.git?rev=6473ab4c400bc59bac8db83a286faaeafa7d1999#6473ab4c400bc59bac8db83a286faaeafa7d1999" dependencies = [ "proc-macro2", "quote", diff --git a/stablecoin/methods/guest/Cargo.toml b/stablecoin/methods/guest/Cargo.toml index 2b7fee3..826343e 100644 --- a/stablecoin/methods/guest/Cargo.toml +++ b/stablecoin/methods/guest/Cargo.toml @@ -10,7 +10,7 @@ name = "stablecoin" path = "src/bin/stablecoin.rs" [dependencies] -spel-framework = { git = "https://github.com/logos-co/spel.git", rev = "ba6e87d086ed85c5ac095325d8a28f02e3d33ca2", package = "spel-framework" } +spel-framework = { git = "https://github.com/logos-co/spel.git", rev = "6473ab4c400bc59bac8db83a286faaeafa7d1999", package = "spel-framework" } nssa_core = { git = "https://github.com/logos-blockchain/logos-execution-zone.git", tag = "v0.2.0-rc3" } risc0-zkvm = { version = "=3.0.5", default-features = false } stablecoin_core = { path = "../../core" } diff --git a/token/core/Cargo.toml b/token/core/Cargo.toml index 6cebf20..afdbc31 100644 --- a/token/core/Cargo.toml +++ b/token/core/Cargo.toml @@ -5,6 +5,6 @@ edition = "2021" [dependencies] nssa_core = { git = "https://github.com/logos-blockchain/logos-execution-zone.git", tag = "v0.2.0-rc3", features = ["host"] } -spel-framework-macros = { git = "https://github.com/logos-co/spel.git", rev = "ba6e87d086ed85c5ac095325d8a28f02e3d33ca2", package = "spel-framework-macros" } +spel-framework-macros = { git = "https://github.com/logos-co/spel.git", rev = "6473ab4c400bc59bac8db83a286faaeafa7d1999", package = "spel-framework-macros" } borsh = { version = "1.5", features = ["derive"] } serde = { version = "1.0", features = ["derive"] } diff --git a/token/methods/guest/Cargo.lock b/token/methods/guest/Cargo.lock index de7d2ad..6083228 100644 --- a/token/methods/guest/Cargo.lock +++ b/token/methods/guest/Cargo.lock @@ -2857,7 +2857,7 @@ dependencies = [ [[package]] name = "spel-framework" version = "0.2.0" -source = "git+https://github.com/logos-co/spel.git?rev=ba6e87d086ed85c5ac095325d8a28f02e3d33ca2#ba6e87d086ed85c5ac095325d8a28f02e3d33ca2" +source = "git+https://github.com/logos-co/spel.git?rev=6473ab4c400bc59bac8db83a286faaeafa7d1999#6473ab4c400bc59bac8db83a286faaeafa7d1999" dependencies = [ "borsh", "nssa_core", @@ -2869,7 +2869,7 @@ dependencies = [ [[package]] name = "spel-framework-core" version = "0.2.0" -source = "git+https://github.com/logos-co/spel.git?rev=ba6e87d086ed85c5ac095325d8a28f02e3d33ca2#ba6e87d086ed85c5ac095325d8a28f02e3d33ca2" +source = "git+https://github.com/logos-co/spel.git?rev=6473ab4c400bc59bac8db83a286faaeafa7d1999#6473ab4c400bc59bac8db83a286faaeafa7d1999" dependencies = [ "borsh", "nssa_core", @@ -2884,7 +2884,7 @@ dependencies = [ [[package]] name = "spel-framework-macros" version = "0.2.0" -source = "git+https://github.com/logos-co/spel.git?rev=ba6e87d086ed85c5ac095325d8a28f02e3d33ca2#ba6e87d086ed85c5ac095325d8a28f02e3d33ca2" +source = "git+https://github.com/logos-co/spel.git?rev=6473ab4c400bc59bac8db83a286faaeafa7d1999#6473ab4c400bc59bac8db83a286faaeafa7d1999" dependencies = [ "proc-macro2", "quote", diff --git a/token/methods/guest/Cargo.toml b/token/methods/guest/Cargo.toml index 702af5d..4a57ba4 100644 --- a/token/methods/guest/Cargo.toml +++ b/token/methods/guest/Cargo.toml @@ -10,7 +10,7 @@ name = "token" path = "src/bin/token.rs" [dependencies] -spel-framework = { git = "https://github.com/logos-co/spel.git", rev = "ba6e87d086ed85c5ac095325d8a28f02e3d33ca2", package = "spel-framework" } +spel-framework = { git = "https://github.com/logos-co/spel.git", rev = "6473ab4c400bc59bac8db83a286faaeafa7d1999", package = "spel-framework" } nssa_core = { git = "https://github.com/logos-blockchain/logos-execution-zone.git", tag = "v0.2.0-rc3" } risc0-zkvm = { version = "=3.0.5", default-features = false } token_core = { path = "../../core" } diff --git a/token/methods/guest/src/bin/token.rs b/token/methods/guest/src/bin/token.rs index e2b7749..924b1b7 100644 --- a/token/methods/guest/src/bin/token.rs +++ b/token/methods/guest/src/bin/token.rs @@ -1,6 +1,7 @@ #![no_main] use spel_framework::prelude::*; +use spel_framework::context::ProgramContext; use nssa_core::account::AccountWithMetadata; risc0_zkvm::guest::entry!(main); @@ -71,6 +72,7 @@ mod token { /// The holding target must be uninitialized and authorized. #[instruction] pub fn initialize_account( + ctx: ProgramContext, definition_account: AccountWithMetadata, account_to_initialize: AccountWithMetadata, ) -> SpelResult { @@ -78,6 +80,7 @@ mod token { token_program::initialize::initialize_account( definition_account, account_to_initialize, + ctx.self_program_id, ), vec![], )) @@ -101,6 +104,7 @@ mod token { /// Fresh public holders must be explicitly authorized in the same transaction. #[instruction] pub fn mint( + ctx: ProgramContext, definition_account: AccountWithMetadata, user_holding_account: AccountWithMetadata, amount_to_mint: u128, @@ -109,6 +113,7 @@ mod token { definition_account, user_holding_account, amount_to_mint, + ctx.self_program_id, ), vec![])) } diff --git a/token/src/initialize.rs b/token/src/initialize.rs index d8350d4..7f57e38 100644 --- a/token/src/initialize.rs +++ b/token/src/initialize.rs @@ -1,12 +1,13 @@ use nssa_core::{ account::{Account, AccountWithMetadata, Data}, - program::{AccountPostState, Claim}, + program::{AccountPostState, Claim, ProgramId}, }; use token_core::{TokenDefinition, TokenHolding}; pub fn initialize_account( definition_account: AccountWithMetadata, account_to_initialize: AccountWithMetadata, + token_program_id: ProgramId, ) -> Vec { assert_eq!( account_to_initialize.account, @@ -17,11 +18,11 @@ pub fn initialize_account( account_to_initialize.is_authorized, "Account to initialize must be authorized" ); + assert_eq!( + definition_account.account.program_owner, token_program_id, + "Token definition must be owned by 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 - // - // Check definition account is valid let definition = TokenDefinition::try_from(&definition_account.account.data) .expect("Definition account must be valid"); let holding = diff --git a/token/src/mint.rs b/token/src/mint.rs index ff744d6..0c638d1 100644 --- a/token/src/mint.rs +++ b/token/src/mint.rs @@ -1,6 +1,6 @@ use nssa_core::{ account::{Account, AccountWithMetadata, Data}, - program::{AccountPostState, Claim}, + program::{AccountPostState, Claim, ProgramId}, }; use token_core::{TokenDefinition, TokenHolding}; @@ -8,11 +8,16 @@ pub fn mint( definition_account: AccountWithMetadata, user_holding_account: AccountWithMetadata, amount_to_mint: u128, + token_program_id: ProgramId, ) -> Vec { assert!( definition_account.is_authorized, "Definition authorization is missing" ); + assert_eq!( + definition_account.account.program_owner, token_program_id, + "Token definition must be owned by token program" + ); let mut definition = TokenDefinition::try_from(&definition_account.account.data) .expect("Token Definition account must be valid"); diff --git a/token/src/tests.rs b/token/src/tests.rs index 532787e..3c5494c 100644 --- a/token/src/tests.rs +++ b/token/src/tests.rs @@ -2,7 +2,7 @@ use nssa_core::{ account::{Account, AccountId, AccountWithMetadata, Data, Nonce}, - program::Claim, + program::{Claim, ProgramId}, }; use token_core::{ MetadataStandard, NewTokenDefinition, NewTokenMetadata, TokenDefinition, TokenHolding, @@ -25,11 +25,31 @@ struct IdForTests; struct AccountForTests; +const TOKEN_PROGRAM_ID: ProgramId = [5u32; 8]; +const FOREIGN_TOKEN_PROGRAM_ID: ProgramId = [6u32; 8]; + impl AccountForTests { fn definition_account_auth() -> AccountWithMetadata { AccountWithMetadata { account: Account { - program_owner: [5u32; 8], + program_owner: TOKEN_PROGRAM_ID, + balance: 0u128, + data: Data::from(&TokenDefinition::Fungible { + name: String::from("test"), + total_supply: BalanceForTests::init_supply(), + metadata_id: None, + }), + nonce: Nonce(0), + }, + is_authorized: true, + account_id: IdForTests::pool_definition_id(), + } + } + + fn definition_account_foreign_owner() -> AccountWithMetadata { + AccountWithMetadata { + account: Account { + program_owner: FOREIGN_TOKEN_PROGRAM_ID, balance: 0u128, data: Data::from(&TokenDefinition::Fungible { name: String::from("test"), @@ -46,7 +66,7 @@ impl AccountForTests { fn definition_account_without_auth() -> AccountWithMetadata { AccountWithMetadata { account: Account { - program_owner: [5u32; 8], + program_owner: TOKEN_PROGRAM_ID, balance: 0u128, data: Data::from(&TokenDefinition::Fungible { name: String::from("test"), @@ -757,7 +777,7 @@ fn test_transfer_with_default_recipient_claims_recipient() { 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 post_states = initialize_account(definition_account, holding_account, TOKEN_PROGRAM_ID); let [definition_post, holding_post] = post_states.try_into().unwrap(); assert_eq!( @@ -785,7 +805,15 @@ fn test_token_initialize_account_succeeds() { 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); + let _post_states = initialize_account(definition_account, holding_account, TOKEN_PROGRAM_ID); +} + +#[test] +#[should_panic(expected = "Token definition must be owned by token program")] +fn test_token_initialize_account_rejects_foreign_owned_definition() { + let definition_account = AccountForTests::definition_account_foreign_owner(); + let holding_account = AccountForTests::holding_account_uninit_auth(); + let _post_states = initialize_account(definition_account, holding_account, TOKEN_PROGRAM_ID); } #[test] @@ -868,6 +896,7 @@ fn test_mint_not_valid_holding_account() { definition_account, holding_account, BalanceForTests::mint_success(), + TOKEN_PROGRAM_ID, ); } @@ -880,6 +909,7 @@ fn test_mint_not_valid_definition_account() { definition_account, holding_account, BalanceForTests::mint_success(), + TOKEN_PROGRAM_ID, ); } @@ -892,6 +922,20 @@ fn test_mint_missing_authorization() { definition_account, holding_account, BalanceForTests::mint_success(), + TOKEN_PROGRAM_ID, + ); +} + +#[test] +#[should_panic(expected = "Token definition must be owned by token program")] +fn test_mint_rejects_foreign_owned_definition() { + let definition_account = AccountForTests::definition_account_foreign_owner(); + let holding_account = AccountForTests::holding_account_uninit(); + let _post_states = mint( + definition_account, + holding_account, + BalanceForTests::mint_success(), + TOKEN_PROGRAM_ID, ); } @@ -904,6 +948,7 @@ fn test_mint_mismatched_token_definition() { definition_account, holding_account, BalanceForTests::mint_success(), + TOKEN_PROGRAM_ID, ); } @@ -915,6 +960,7 @@ fn test_mint_success() { definition_account, holding_account, BalanceForTests::mint_success(), + TOKEN_PROGRAM_ID, ); let [def_post, holding_post] = post_states.try_into().unwrap(); @@ -939,6 +985,7 @@ fn test_mint_uninit_holding_success() { definition_account, holding_account, BalanceForTests::mint_success(), + TOKEN_PROGRAM_ID, ); let [def_post, holding_post] = post_states.try_into().unwrap(); @@ -964,6 +1011,7 @@ fn test_mint_total_supply_overflow() { definition_account, holding_account, BalanceForTests::mint_overflow(), + TOKEN_PROGRAM_ID, ); } @@ -976,6 +1024,7 @@ fn test_mint_holding_account_overflow() { definition_account, holding_account, BalanceForTests::mint_overflow(), + TOKEN_PROGRAM_ID, ); } @@ -988,6 +1037,7 @@ fn test_mint_cannot_mint_unmintable_tokens() { definition_account, holding_account, BalanceForTests::mint_success(), + TOKEN_PROGRAM_ID, ); } diff --git a/tools/idl-gen/Cargo.toml b/tools/idl-gen/Cargo.toml index 67996c6..7817871 100644 --- a/tools/idl-gen/Cargo.toml +++ b/tools/idl-gen/Cargo.toml @@ -8,7 +8,7 @@ name = "idl-gen" path = "src/main.rs" [dependencies] -spel-framework-core = { git = "https://github.com/logos-co/spel.git", rev = "ba6e87d086ed85c5ac095325d8a28f02e3d33ca2", features = [ +spel-framework-core = { git = "https://github.com/logos-co/spel.git", rev = "6473ab4c400bc59bac8db83a286faaeafa7d1999", features = [ "idl-gen", ] } serde_json = "1.0"