Skip to content

Commit

Permalink
Merge pull request #14 from zeta-chain/pause-deposit
Browse files Browse the repository at this point in the history
program: add pause deposit state and guard in deposit & deposit_spl_token
  • Loading branch information
brewmaster012 authored Aug 15, 2024
2 parents eb03529 + 52a13a4 commit 18ed2fb
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 0 deletions.
27 changes: 27 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,3 +125,30 @@ Ethereum style). `authority` is the one who can update
the TSS address stored in PDA account.

The `initialize` instruction sets nonce to 0.

# Troubleshooting

## MacOS error when running `anchor test` or `solana-test-validator`

If you see errors like
```
Unable to get latest blockhash. Test validator does not look started. Check ".anchor/test-ledger/test-ledger-log.txt" for errors. Consider increasing [test.startup_wait] in Anchor.toml.
```

or
```bash
% solana-test-validator --reset
Ledger location: test-ledger
Log: test-ledger/validator.log
Error: failed to start validator: Failed to create ledger at test-ledger: io error: Error checking to unpack genesis archive: Archive error: extra entry found: "._genesis.bin" Regular
```

This is because the BSD tar program is not compatible with the GNU tar program.
To fix it:

```bash
brew install gnu-tar
# Put this in ~/.zshrc
export PATH="/opt/homebrew/opt/gnu-tar/libexec/gnubin:$PATH"
```
see https://solana.stackexchange.com/questions/4499/blockstore-error-when-starting-solana-test-validator-on-macos-13-0-1
51 changes: 51 additions & 0 deletions programs/protocol-contracts-solana/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ pub enum Errors {
MemoLengthExceeded,
#[msg("MemoLengthTooShort")]
MemoLengthTooShort,
#[msg("DepositPaused")]
DepositPaused,
}

declare_id!("94U5AHQMKkV5txNJ17QPXWoh474PheGou6cNP2FEuL1d");
Expand All @@ -42,10 +44,22 @@ pub mod gateway {
initialized_pda.tss_address = tss_address;
initialized_pda.authority = ctx.accounts.signer.key();
initialized_pda.chain_id = chain_id;
initialized_pda.deposit_paused = false;

Ok(())
}

pub fn set_deposit_paused(ctx: Context<UpdatePaused>, deposit_paused: bool) -> Result<()> {
let pda = &mut ctx.accounts.pda;
require!(
ctx.accounts.signer.key() == pda.authority,
Errors::SignerIsNotAuthority
);
pda.deposit_paused = deposit_paused;
msg!("set_deposit_paused: {:?}", deposit_paused);
Ok(())
}

pub fn update_tss(ctx: Context<UpdateTss>, tss_address: [u8; 20]) -> Result<()> {
let pda = &mut ctx.accounts.pda;
require!(
Expand All @@ -56,9 +70,26 @@ pub mod gateway {
Ok(())
}

pub fn update_authority(
ctx: Context<UpdateAuthority>,
new_authority_address: Pubkey,
) -> Result<()> {
let pda = &mut ctx.accounts.pda;
require!(
ctx.accounts.signer.key() == pda.authority,
Errors::SignerIsNotAuthority
);
pda.authority = new_authority_address;
Ok(())
}

pub fn deposit(ctx: Context<Deposit>, amount: u64, memo: Vec<u8>) -> Result<()> {
require!(memo.len() >= 20, Errors::MemoLengthTooShort);
require!(memo.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 {
Expand Down Expand Up @@ -86,6 +117,9 @@ pub mod gateway {
let token = &ctx.accounts.token_program;
let from = &ctx.accounts.from;

let pda = &mut ctx.accounts.pda;
require!(!pda.deposit_paused, Errors::DepositPaused);

let pda_ata = spl_associated_token_account::get_associated_token_address(
&ctx.accounts.pda.key(),
&from.mint,
Expand Down Expand Up @@ -293,12 +327,29 @@ pub struct UpdateTss<'info> {
pub signer: Signer<'info>,
}

#[derive(Accounts)]
pub struct UpdateAuthority<'info> {
#[account(mut)]
pub pda: Account<'info, Pda>,
#[account(mut)]
pub signer: Signer<'info>,
}

#[derive(Accounts)]
pub struct UpdatePaused<'info> {
#[account(mut)]
pub pda: Account<'info, Pda>,
#[account(mut)]
pub signer: Signer<'info>,
}

#[account]
pub struct Pda {
nonce: u64, // ensure that each signature can only be used once
tss_address: [u8; 20], // 20 bytes address format of ethereum
authority: Pubkey,
chain_id: u64,
deposit_paused: bool,
}

#[cfg(test)]
Expand Down
39 changes: 39 additions & 0 deletions tests/protocol-contracts-solana.ts
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,45 @@ describe("some tests", () => {
}
});

it("pause deposit and deposit should fail", async () => {
const newTss = new Uint8Array(20);
randomFillSync(newTss);
// console.log("generated new TSS address", newTss);
await gatewayProgram.methods.setDepositPaused(true).accounts({
pda: pdaAccount,
}).rpc();

// now try deposit, should fail
try {
await gatewayProgram.methods.deposit(new anchor.BN(1_000_000), address).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 () => {
const newAuthority = anchor.web3.Keypair.generate();
await gatewayProgram.methods.updateAuthority(newAuthority.publicKey).accounts({
pda: pdaAccount,
}).rpc();
// const pdaAccountData = await gatewayProgram.account.pda.fetch(pdaAccount);
// expect(pdaAccountData.authority).to.be.eq(newAuthority.publicKey);

// now the old authority cannot update TSS address and will fail
try {
await gatewayProgram.methods.updateTss(Array.from(new Uint8Array(20))).accounts({
pda: pdaAccount,
}).rpc();
} catch (err) {
console.log("Error message: ", err.message);
expect(err).to.be.instanceof(anchor.AnchorError);
expect(err.message).to.include("SignerIsNotAuthority");
}
});


});

Expand Down

0 comments on commit 18ed2fb

Please sign in to comment.