Skip to content

Commit

Permalink
refactor deposit_and_call and deposit_spl_token_and_call (#35)
Browse files Browse the repository at this point in the history
* remove memo from deposit_spl_token

so that it matches deposit instruction.

* refactor deposit*_and_call instructions to reuse deposit*

* format

* update comment in code that is inaccurate

* address some CI complaints

* add some light comments to instructions

* silence intentional unused variable warnings

* add some test
  • Loading branch information
brewmaster012 authored Oct 3, 2024
1 parent c70d803 commit 98bd5c3
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 49 deletions.
68 changes: 42 additions & 26 deletions programs/protocol-contracts-solana/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ pub mod gateway {
Ok(())
}

// admin function to pause or unpause deposit
pub fn set_deposit_paused(ctx: Context<UpdatePaused>, deposit_paused: bool) -> Result<()> {
let pda = &mut ctx.accounts.pda;
require!(
Expand Down Expand Up @@ -84,7 +85,15 @@ pub mod gateway {
Ok(())
}

pub fn deposit(ctx: Context<Deposit>, amount: u64, receiver: [u8; 20]) -> Result<()> {
// 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<Deposit>,
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);

Expand All @@ -106,43 +115,31 @@ 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<Deposit>,
amount: u64,
receiver: [u8; 20],
message: Vec<u8>,
) -> 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,
);

deposit(ctx, amount, receiver)?;
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
#[allow(unused)]
pub fn deposit_spl_token(
ctx: Context<DepositSplToken>,
amount: u64,
memo: Vec<u8>,
receiver: [u8; 20], // unused in this program; for directing zetachain protocol only
) -> Result<()> {
require!(memo.len() >= 20, Errors::MemoLengthTooShort);
require!(memo.len() <= 512, Errors::MemoLengthExceeded);
let token = &ctx.accounts.token_program;
let from = &ctx.accounts.from;

Expand Down Expand Up @@ -174,7 +171,25 @@ pub mod gateway {
Ok(())
}

// only tss address stored in PDA can call this instruction
// 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`.
#[allow(unused)]
pub fn deposit_spl_token_and_call(
ctx: Context<DepositSplToken>,
amount: u64,
receiver: [u8; 20],
message: Vec<u8>,
) -> Result<()> {
require!(message.len() <= 512, Errors::MemoLengthExceeded);
deposit_spl_token(ctx, amount, receiver)?;
Ok(())
}

// require tss address signature on the internal message defined in the following
// concatenated_buffer vec.
pub fn withdraw(
ctx: Context<Withdraw>,
amount: u64,
Expand Down Expand Up @@ -216,7 +231,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<WithdrawSPLToken>,
amount: u64,
Expand Down
62 changes: 39 additions & 23 deletions tests/protocol-contracts-solana.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,25 +139,20 @@ 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), 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 {
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,
Expand All @@ -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);
Expand Down Expand Up @@ -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 {
Expand All @@ -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);
}

});
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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 () => {
Expand Down

0 comments on commit 98bd5c3

Please sign in to comment.