From 5abfbaf249120c4c8bac0a35713d68ecf22d7f80 Mon Sep 17 00:00:00 2001 From: brewmaster012 <88689859+brewmaster012@users.noreply.github.com> Date: Wed, 2 Oct 2024 10:33:27 -0500 Subject: [PATCH 1/8] remove memo from deposit_spl_token so that it matches deposit instruction. --- programs/protocol-contracts-solana/src/lib.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/programs/protocol-contracts-solana/src/lib.rs b/programs/protocol-contracts-solana/src/lib.rs index f857bc6..0407497 100644 --- a/programs/protocol-contracts-solana/src/lib.rs +++ b/programs/protocol-contracts-solana/src/lib.rs @@ -139,10 +139,9 @@ pub mod gateway { pub fn deposit_spl_token( ctx: Context, amount: u64, - memo: Vec, + receiver: [u8; 20], ) -> Result<()> { - require!(memo.len() >= 20, Errors::MemoLengthTooShort); - require!(memo.len() <= 512, Errors::MemoLengthExceeded); + let token = &ctx.accounts.token_program; let from = &ctx.accounts.from; From 6f4eccd91eff59bcd88d7ec452536e68b8b2e032 Mon Sep 17 00:00:00 2001 From: brewmaster012 <88689859+brewmaster012@users.noreply.github.com> Date: Wed, 2 Oct 2024 10:42:15 -0500 Subject: [PATCH 2/8] refactor deposit*_and_call instructions to reuse deposit* --- programs/protocol-contracts-solana/src/lib.rs | 35 ++++++++----------- tests/protocol-contracts-solana.ts | 4 +-- 2 files changed, 16 insertions(+), 23 deletions(-) diff --git a/programs/protocol-contracts-solana/src/lib.rs b/programs/protocol-contracts-solana/src/lib.rs index 0407497..38fbee5 100644 --- a/programs/protocol-contracts-solana/src/lib.rs +++ b/programs/protocol-contracts-solana/src/lib.rs @@ -113,27 +113,8 @@ pub mod gateway { message: Vec, ) -> Result<()> { require!(message.len() <= 512, Errors::MemoLengthExceeded); - - let pda = &mut ctx.accounts.pda; - require!(!pda.deposit_paused, Errors::DepositPaused); - - let cpi_context = CpiContext::new( - ctx.accounts.system_program.to_account_info(), - system_program::Transfer { - from: ctx.accounts.signer.to_account_info().clone(), - to: ctx.accounts.pda.to_account_info().clone(), - }, - ); - system_program::transfer(cpi_context, amount)?; - msg!( - "{:?} deposits {:?} lamports to PDA and call contract {:?} with message {:?}", - ctx.accounts.signer.key(), - amount, - receiver, - message, - ); - - Ok(()) + deposit(ctx, amount, receiver)?; + return Ok(()); } pub fn deposit_spl_token( @@ -173,6 +154,18 @@ pub mod gateway { Ok(()) } + + pub fn deposit_spl_token_and_call( + ctx: Context, + amount: u64, + receiver: [u8; 20], + message: Vec, + ) -> Result<()> { + require!(message.len() <= 512, Errors::MemoLengthExceeded); + deposit_spl_token(ctx, amount, receiver)?; + return Ok(()); + } + // only tss address stored in PDA can call this instruction pub fn withdraw( ctx: Context, diff --git a/tests/protocol-contracts-solana.ts b/tests/protocol-contracts-solana.ts index 8fa8cd4..734fcf0 100644 --- a/tests/protocol-contracts-solana.ts +++ b/tests/protocol-contracts-solana.ts @@ -146,7 +146,7 @@ describe("some tests", () => { ); tx.add(memoInst); const depositInst = await gatewayProgram.methods.depositSplToken( - new anchor.BN(1_000_000), address).accounts( + new anchor.BN(1_000_000), Array.from(address)).accounts( { from: tokenAccount.address, to: pda_ata.address, @@ -157,7 +157,7 @@ describe("some tests", () => { try { - await gatewayProgram.methods.depositSplToken(new anchor.BN(1_000_000), address).accounts( + await gatewayProgram.methods.depositSplToken(new anchor.BN(1_000_000), Array.from(address)).accounts( { from: tokenAccount.address, to: wallet_ata, From acbd25cebc68a809f03023d939d86b53544a545e Mon Sep 17 00:00:00 2001 From: brewmaster012 <88689859+brewmaster012@users.noreply.github.com> Date: Wed, 2 Oct 2024 10:54:29 -0500 Subject: [PATCH 3/8] format --- programs/protocol-contracts-solana/src/lib.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/programs/protocol-contracts-solana/src/lib.rs b/programs/protocol-contracts-solana/src/lib.rs index 38fbee5..14b6cc8 100644 --- a/programs/protocol-contracts-solana/src/lib.rs +++ b/programs/protocol-contracts-solana/src/lib.rs @@ -122,7 +122,6 @@ pub mod gateway { amount: u64, receiver: [u8; 20], ) -> Result<()> { - let token = &ctx.accounts.token_program; let from = &ctx.accounts.from; @@ -154,7 +153,6 @@ pub mod gateway { Ok(()) } - pub fn deposit_spl_token_and_call( ctx: Context, amount: u64, From b0318bbe5e6f333564e644d39b616b0a5a0f4ebe Mon Sep 17 00:00:00 2001 From: brewmaster012 <88689859+brewmaster012@users.noreply.github.com> Date: Wed, 2 Oct 2024 10:59:36 -0500 Subject: [PATCH 4/8] update comment in code that is inaccurate --- programs/protocol-contracts-solana/src/lib.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/programs/protocol-contracts-solana/src/lib.rs b/programs/protocol-contracts-solana/src/lib.rs index 14b6cc8..ede9234 100644 --- a/programs/protocol-contracts-solana/src/lib.rs +++ b/programs/protocol-contracts-solana/src/lib.rs @@ -164,7 +164,8 @@ pub mod gateway { return Ok(()); } - // only tss address stored in PDA can call this instruction + // require tss address signature on the internal message defined in the following + // concatenated_buffer vec. pub fn withdraw( ctx: Context, amount: u64, @@ -206,7 +207,8 @@ pub mod gateway { Ok(()) } - // only tss address stored in PDA can call this instruction + // require tss address signature on the internal message defined in the following + // concatenated_buffer vec. pub fn withdraw_spl_token( ctx: Context, amount: u64, From 0e18af415267fbe87cd912ac24d0a882d8f824cf Mon Sep 17 00:00:00 2001 From: brewmaster012 <88689859+brewmaster012@users.noreply.github.com> Date: Wed, 2 Oct 2024 14:16:34 -0500 Subject: [PATCH 5/8] address some CI complaints --- programs/protocol-contracts-solana/src/lib.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/programs/protocol-contracts-solana/src/lib.rs b/programs/protocol-contracts-solana/src/lib.rs index ede9234..2b386e2 100644 --- a/programs/protocol-contracts-solana/src/lib.rs +++ b/programs/protocol-contracts-solana/src/lib.rs @@ -84,7 +84,11 @@ pub mod gateway { Ok(()) } - pub fn deposit(ctx: Context, amount: u64, receiver: [u8; 20]) -> Result<()> { + pub fn deposit( + ctx: Context, + amount: u64, + receiver: [u8; 20], // not used in this program; for directing zetachain protocol only + ) -> Result<()> { let pda = &mut ctx.accounts.pda; require!(!pda.deposit_paused, Errors::DepositPaused); @@ -114,13 +118,13 @@ pub mod gateway { ) -> Result<()> { require!(message.len() <= 512, Errors::MemoLengthExceeded); deposit(ctx, amount, receiver)?; - return Ok(()); + Ok(()) } pub fn deposit_spl_token( ctx: Context, amount: u64, - receiver: [u8; 20], + receiver: [u8; 20], // unused in this program; for directing zetachain protocol only ) -> Result<()> { let token = &ctx.accounts.token_program; let from = &ctx.accounts.from; @@ -161,7 +165,7 @@ pub mod gateway { ) -> Result<()> { require!(message.len() <= 512, Errors::MemoLengthExceeded); deposit_spl_token(ctx, amount, receiver)?; - return Ok(()); + Ok(()) } // require tss address signature on the internal message defined in the following From f352dc37c5334abdaea130867ca02eb46ce8bbe4 Mon Sep 17 00:00:00 2001 From: brewmaster012 <88689859+brewmaster012@users.noreply.github.com> Date: Wed, 2 Oct 2024 14:39:16 -0500 Subject: [PATCH 6/8] add some light comments to instructions --- programs/protocol-contracts-solana/src/lib.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/programs/protocol-contracts-solana/src/lib.rs b/programs/protocol-contracts-solana/src/lib.rs index 2b386e2..a49a051 100644 --- a/programs/protocol-contracts-solana/src/lib.rs +++ b/programs/protocol-contracts-solana/src/lib.rs @@ -48,6 +48,7 @@ pub mod gateway { Ok(()) } + // admin function to pause or unpause deposit pub fn set_deposit_paused(ctx: Context, deposit_paused: bool) -> Result<()> { let pda = &mut ctx.accounts.pda; require!( @@ -84,6 +85,10 @@ pub mod gateway { Ok(()) } + // deposit SOL into this program and the `receiver` on ZetaChain zEVM + // will get corresponding ZRC20 credit. + // amount: amount of lamports (10^-9 SOL) to deposit + // receiver: ethereum address (20Bytes) of the receiver on ZetaChain zEVM pub fn deposit( ctx: Context, amount: u64, @@ -110,6 +115,10 @@ pub mod gateway { Ok(()) } + // deposit SOL into this program and the `receiver` on ZetaChain zEVM + // will get corresponding ZRC20 credit. The `receiver` should be a contract + // on zEVM and the `message` will be used as input data for the contract call. + // The `receiver` contract on zEVM will get the SOL ZRC20 credit and receive the `message`. pub fn deposit_and_call( ctx: Context, amount: u64, @@ -121,6 +130,10 @@ pub mod gateway { Ok(()) } + // deposit SPL token into this program and the `receiver` on ZetaChain zEVM + // will get corresponding ZRC20 credit. + // amount: amount of SPL token to deposit + // receiver: ethereum address (20Bytes) of the receiver on ZetaChain zEVM pub fn deposit_spl_token( ctx: Context, amount: u64, @@ -157,6 +170,11 @@ pub mod gateway { Ok(()) } + // like `deposit_spl_token` instruction, + // deposit SPL token into this program and the `receiver` on ZetaChain zEVM + // will get corresponding ZRC20 credit. The `receiver` should be a contract + // on zEVM and the `message` will be used as input data for the contract call. + // The `receiver` contract on zEVM will get the SPL token ZRC20 credit and receive the `message`. pub fn deposit_spl_token_and_call( ctx: Context, amount: u64, From f9151ac3cac9e37852f5d2285531c28de0c2fd96 Mon Sep 17 00:00:00 2001 From: brewmaster012 <88689859+brewmaster012@users.noreply.github.com> Date: Wed, 2 Oct 2024 14:45:59 -0500 Subject: [PATCH 7/8] silence intentional unused variable warnings --- programs/protocol-contracts-solana/src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/programs/protocol-contracts-solana/src/lib.rs b/programs/protocol-contracts-solana/src/lib.rs index a49a051..d49454e 100644 --- a/programs/protocol-contracts-solana/src/lib.rs +++ b/programs/protocol-contracts-solana/src/lib.rs @@ -134,6 +134,7 @@ pub mod gateway { // will get corresponding ZRC20 credit. // amount: amount of SPL token to deposit // receiver: ethereum address (20Bytes) of the receiver on ZetaChain zEVM + #[allow(unused)] pub fn deposit_spl_token( ctx: Context, amount: u64, @@ -175,6 +176,7 @@ pub mod gateway { // will get corresponding ZRC20 credit. The `receiver` should be a contract // on zEVM and the `message` will be used as input data for the contract call. // The `receiver` contract on zEVM will get the SPL token ZRC20 credit and receive the `message`. + #[allow(unused)] pub fn deposit_spl_token_and_call( ctx: Context, amount: u64, From 0d81e93453569b8ba3e20a7ee255262c4d26ccf8 Mon Sep 17 00:00:00 2001 From: brewmaster012 <88689859+brewmaster012@users.noreply.github.com> Date: Thu, 3 Oct 2024 11:56:29 -0500 Subject: [PATCH 8/8] add some test --- tests/protocol-contracts-solana.ts | 60 +++++++++++++++++++----------- 1 file changed, 38 insertions(+), 22 deletions(-) diff --git a/tests/protocol-contracts-solana.ts b/tests/protocol-contracts-solana.ts index 734fcf0..33c209b 100644 --- a/tests/protocol-contracts-solana.ts +++ b/tests/protocol-contracts-solana.ts @@ -139,21 +139,16 @@ describe("some tests", () => { true ); console.log("pda_ata address", pda_ata.address.toString()); - const tx = new web3.Transaction(); - const memoInst = memo.createMemoInstruction( - "this is a memo", - [wallet.publicKey], - ); - tx.add(memoInst); - const depositInst = await gatewayProgram.methods.depositSplToken( - new anchor.BN(1_000_000), Array.from(address)).accounts( - { - from: tokenAccount.address, - to: pda_ata.address, - } - ).instruction(); - tx.add(depositInst); - const txsig = await anchor.web3.sendAndConfirmTransaction(conn, tx, [wallet]); + + let acct = await spl.getAccount(conn, pda_ata.address); + let bal0 = acct.amount; + await gatewayProgram.methods.depositSplToken(new anchor.BN(1_000_000), Array.from(address)).accounts({ + from: tokenAccount.address, + to: pda_ata.address, + }).rpc({commitment: 'confirmed'}); + acct = await spl.getAccount(conn, pda_ata.address); + let bal1 = acct.amount; + expect(bal1-bal0).to.be.eq(1_000_000n); try { @@ -169,12 +164,31 @@ describe("some tests", () => { expect(err.message).to.include("DepositToAddressMismatch"); // console.log("Error message: ", err.message); } + + // test depositSplTokenAndCall + acct = await spl.getAccount(conn, pda_ata.address); + bal0 = acct.amount; + await gatewayProgram.methods.depositSplTokenAndCall(new anchor.BN(2_000_000), Array.from(address), Buffer.from('hi', 'utf-8')).accounts({ + from: tokenAccount.address, + to: pda_ata.address, + }).rpc({commitment: 'confirmed'}); + acct = await spl.getAccount(conn, pda_ata.address); + bal1 = acct.amount; + expect(bal1-bal0).to.be.eq(2_000_000n); + + // try { + // await gatewayProgram.methods.depositSplTokenAndCall(new anchor.BN(1_000_000), Array.from(address), Buffer.from("hello", "utf-8")).accounts({ + // from: tokenAccount.address, + // to: pda_ata.address, + // }).rpc(); + // + // } }); it("Withdraw 500_000 USDC from Gateway with ECDSA signature", async () => { const account2 = await spl.getAccount(conn, pda_ata.address); - expect(account2.amount).to.be.eq(1_000_000n); - // console.log("B4 withdraw: Account balance:", account2.amount.toString()); + // expect(account2.amount).to.be.eq(1_000_000n); + console.log("B4 withdraw: Account balance:", account2.amount.toString()); const pdaAccountData = await gatewayProgram.account.pda.fetch(pdaAccount); @@ -212,7 +226,7 @@ describe("some tests", () => { }).rpc(); const account3 = await spl.getAccount(conn, pda_ata.address); - expect(account3.amount).to.be.eq(500_000n); + expect(account3.amount-account2.amount).to.be.eq(-500_000n); try { @@ -227,7 +241,7 @@ describe("some tests", () => { expect(err.message).to.include("NonceMismatch"); const account4 = await spl.getAccount(conn, pda_ata.address); console.log("After 2nd withdraw: Account balance:", account4.amount.toString()); - expect(account4.amount).to.be.eq(500_000n); + expect(account4.amount).to.be.eq(2_500_000n); } }); @@ -288,11 +302,14 @@ describe("some tests", () => { it("deposit and call", async () => { let bal1 = await conn.getBalance(pdaAccount); - await gatewayProgram.methods.depositAndCall(new anchor.BN(1_000_000_000), Array.from(address), Buffer.from("hello", "utf-8")).accounts({pda: pdaAccount}).rpc(); + const txsig = await gatewayProgram.methods.depositAndCall(new anchor.BN(1_000_000_000), Array.from(address), Buffer.from("hello", "utf-8")).accounts({pda: pdaAccount}).rpc({commitment: 'confirmed'}); + const tx = await conn.getParsedTransaction(txsig, 'confirmed'); + console.log("deposit and call parsed tx", tx); let bal2 = await conn.getBalance(pdaAccount); expect(bal2-bal1).to.be.gte(1_000_000_000); }) + it("update TSS address", async () => { const newTss = new Uint8Array(20); randomFillSync(newTss); @@ -326,13 +343,12 @@ describe("some tests", () => { // now try deposit, should fail try { - await gatewayProgram.methods.deposit(new anchor.BN(1_000_000), Array.from(address)).accounts({pda: pdaAccount}).rpc(); + await gatewayProgram.methods.depositAndCall(new anchor.BN(1_000_000), Array.from(address), Buffer.from('hi', 'utf-8')).accounts({pda: pdaAccount}).rpc(); } catch (err) { console.log("Error message: ", err.message); expect(err).to.be.instanceof(anchor.AnchorError); expect(err.message).to.include("DepositPaused"); } - }); it("update authority", async () => {