From 79728bca9e3697256899b3fb6e3054a40d9ef01f Mon Sep 17 00:00:00 2001 From: Promethea Raschke Date: Wed, 2 Aug 2023 17:31:43 +0100 Subject: [PATCH] Add test for depositing wrapped tokens --- cross-chain/solana/tests/01__tbtc.ts | 72 +++--------------- .../solana/tests/02__wormholeGateway.ts | 76 +++++++++++++++++-- .../solana/tests/helpers/tbtcHelpers.ts | 53 ++++++++++++- 3 files changed, 131 insertions(+), 70 deletions(-) diff --git a/cross-chain/solana/tests/01__tbtc.ts b/cross-chain/solana/tests/01__tbtc.ts index 28b13556e..b71473f87 100644 --- a/cross-chain/solana/tests/01__tbtc.ts +++ b/cross-chain/solana/tests/01__tbtc.ts @@ -6,14 +6,7 @@ import { Tbtc } from "../target/types/tbtc"; import { expect } from 'chai'; import { ASSOCIATED_PROGRAM_ID } from "@coral-xyz/anchor/dist/cjs/utils/token"; import { transferLamports } from "./helpers/utils"; -import { getConfigPDA, getTokenPDA, getMinterPDA, getGuardianPDA } from "./helpers/tbtcHelpers"; - -function maybeAuthorityAnd( - signer, - signers -) { - return signers.concat(signer instanceof (anchor.Wallet as any) ? [] : [signer]); -} +import { maybeAuthorityAnd, getConfigPDA, getTokenPDA, getMinterPDA, getGuardianPDA, checkState, addMinter } from "./helpers/tbtcHelpers"; async function setup( program: Program, @@ -32,26 +25,6 @@ async function setup( .rpc(); } -async function checkState( - program: Program, - expectedAuthority, - expectedMinters, - expectedGuardians, - expectedTokensSupply -) { - const [config,] = getConfigPDA(program); - let configState = await program.account.config.fetch(config); - - expect(configState.authority).to.eql(expectedAuthority.publicKey); - expect(configState.numMinters).to.equal(expectedMinters); - expect(configState.numGuardians).to.equal(expectedGuardians); - - let tbtcMint = configState.mint; - - let mintState = await spl.getMint(program.provider.connection, tbtcMint); - - expect(mintState.supply).to.equal(BigInt(expectedTokensSupply)); -} async function changeAuthority( program: Program, @@ -127,34 +100,11 @@ async function checkPaused( } - - -async function addMinter( - program: Program, - authority, - minter, - payer -): Promise { - const [config,] = getConfigPDA(program); - const [minterInfoPDA, _] = getMinterPDA(program, minter); - await program.methods - .addMinter() - .accounts({ - config, - authority: authority.publicKey, - minter: minter.publicKey, - minterInfo: minterInfoPDA, - }) - .signers(maybeAuthorityAnd(authority, [])) - .rpc(); - return minterInfoPDA; -} - async function checkMinter( program: Program, minter ) { - const [minterInfoPDA, bump] = getMinterPDA(program, minter); + const [minterInfoPDA, bump] = getMinterPDA(program, minter.publicKey); let minterInfo = await program.account.minterInfo.fetch(minterInfoPDA); expect(minterInfo.minter).to.eql(minter.publicKey); @@ -397,7 +347,7 @@ describe("tbtc", () => { it('add minter', async () => { await checkState(program, authority, 0, 0, 0); - await addMinter(program, authority, minterKeys, authority); + await addMinter(program, authority, minterKeys.publicKey); await checkMinter(program, minterKeys); await checkState(program, authority, 1, 0, 0); @@ -416,7 +366,7 @@ describe("tbtc", () => { // ); try { - await addMinter(program, impostorKeys, minter2Keys, authority); + await addMinter(program, impostorKeys, minter2Keys.publicKey); chai.assert(false, "should've failed but didn't"); } catch (_err) { expect(_err).to.be.instanceOf(AnchorError); @@ -428,7 +378,7 @@ describe("tbtc", () => { it('mint', async () => { await checkState(program, authority, 1, 0, 0); - const [minterInfoPDA, _] = getMinterPDA(program, minterKeys); + const [minterInfoPDA, _] = getMinterPDA(program, minterKeys.publicKey); await checkMinter(program, minterKeys); // await setupMint(program, authority, recipientKeys); @@ -449,7 +399,7 @@ describe("tbtc", () => { it('won\'t mint', async () => { await checkState(program, authority, 1, 0, 1000); - const [minterInfoPDA, _] = getMinterPDA(program, minterKeys); + const [minterInfoPDA, _] = getMinterPDA(program, minterKeys.publicKey); await checkMinter(program, minterKeys); // await setupMint(program, authority, recipientKeys); @@ -467,9 +417,9 @@ describe("tbtc", () => { it('use two minters', async () => { await checkState(program, authority, 1, 0, 1000); - const [minterInfoPDA, _] = getMinterPDA(program, minterKeys); + const [minterInfoPDA, _] = getMinterPDA(program, minterKeys.publicKey); await checkMinter(program, minterKeys); - const minter2InfoPDA = await addMinter(program, authority, minter2Keys, authority); + const minter2InfoPDA = await addMinter(program, authority, minter2Keys.publicKey); await checkMinter(program, minter2Keys); await checkState(program, authority, 2, 0, 1000); // await setupMint(program, authority, recipientKeys); @@ -502,7 +452,7 @@ describe("tbtc", () => { it('remove minter', async () => { await checkState(program, authority, 2, 0, 1500); - const [minter2InfoPDA, _] = getMinterPDA(program, minter2Keys); + const [minter2InfoPDA, _] = getMinterPDA(program, minter2Keys.publicKey); await checkMinter(program, minter2Keys); await removeMinter(program, authority, minter2Keys, minter2InfoPDA); await checkState(program, authority, 1, 0, 1500); @@ -510,7 +460,7 @@ describe("tbtc", () => { it('won\'t remove minter', async () => { await checkState(program, authority, 1, 0, 1500); - const [minterInfoPDA, _] = getMinterPDA(program, minterKeys); + const [minterInfoPDA, _] = getMinterPDA(program, minterKeys.publicKey); await checkMinter(program, minterKeys); try { @@ -611,7 +561,7 @@ describe("tbtc", () => { it('won\'t mint when paused', async () => { await checkState(program, authority, 0, 1, 1500); - const minterInfoPDA = await addMinter(program, authority, minterKeys, authority); + const minterInfoPDA = await addMinter(program, authority, minterKeys.publicKey); await pause(program, guardianKeys); // await setupMint(program, authority, recipientKeys); diff --git a/cross-chain/solana/tests/02__wormholeGateway.ts b/cross-chain/solana/tests/02__wormholeGateway.ts index 47390f8ae..cf07e7c8e 100644 --- a/cross-chain/solana/tests/02__wormholeGateway.ts +++ b/cross-chain/solana/tests/02__wormholeGateway.ts @@ -10,7 +10,7 @@ import { expect } from 'chai'; import { WormholeGateway } from "../target/types/wormhole_gateway"; import { generatePayer, getOrCreateTokenAccount } from "./helpers/utils"; import { getCustodianPDA, getTokenBridgeRedeemerPDA, getTokenBridgeSenderPDA, getWrappedTbtcTokenPDA } from "./helpers/wormholeGatewayHelpers"; -import { getConfigPDA, getTokenPDA, getMinterPDA, getGuardianPDA } from "./helpers/tbtcHelpers"; +import * as tbtc from "./helpers/tbtcHelpers"; import { web3 } from "@coral-xyz/anchor"; import { Tbtc } from "../target/types/tbtc"; @@ -24,18 +24,16 @@ const GUARDIAN_SET_INDEX = 3; async function setup( program: Program, - tbtc: Program, + tbtcProgram: Program, authority, mintingLimit: number ) { const [custodian,] = getCustodianPDA(program); - const [tbtcMint,] = getTokenPDA(tbtc); + const [tbtcMint,] = tbtc.getTokenPDA(tbtcProgram); const [gatewayWrappedTbtcToken,] = getWrappedTbtcTokenPDA(program); const [tokenBridgeSender,] = getTokenBridgeSenderPDA(program); const [tokenBridgeRedeemer,] = getTokenBridgeRedeemerPDA(program); - const connection = program.provider.connection; - const wrappedTbtcMint = tokenBridge.deriveWrappedMintKey(SOLANA_TOKEN_BRIDGE_ADDRESS, 2, ETHEREUM_TBTC_ADDRESS); await program.methods @@ -74,6 +72,13 @@ describe("wormhole-gateway", () => { const tbtcProgram = anchor.workspace.Tbtc as Program; + const [custodian,] = getCustodianPDA(program); + const [tbtcMint,] = tbtc.getTokenPDA(tbtcProgram); + const [tbtcConfig,] = tbtc.getConfigPDA(tbtcProgram); + const [gatewayWrappedTbtcToken,] = getWrappedTbtcTokenPDA(program); + const [tokenBridgeSender,] = getTokenBridgeSenderPDA(program); + const [tokenBridgeRedeemer,] = getTokenBridgeRedeemerPDA(program); + const authority = (program.provider as anchor.AnchorProvider).wallet as anchor.Wallet; const newAuthority = anchor.web3.Keypair.generate(); const minterKeys = anchor.web3.Keypair.generate(); @@ -127,9 +132,66 @@ describe("wormhole-gateway", () => { }); it('setup', async () => { - await setup(program, tbtcProgram, authority, 1000); - await checkState(program, authority, 1000); + await setup(program, tbtcProgram, authority, 10000); + await checkState(program, authority, 10000); + await tbtc.checkState(tbtcProgram, authority, 1, 2, 1500); }); + + it('deposit wrapped tokens', async () => { + const [custodian,] = getCustodianPDA(program); + const minterInfo = await tbtc.addMinter(tbtcProgram, authority, custodian); + + // Set up new wallet + const payer = await generatePayer(connection, authority.payer); + + // Check wrapped tBTC mint. + const wrappedTbtcMint = tokenBridge.deriveWrappedMintKey(SOLANA_TOKEN_BRIDGE_ADDRESS, 2, ETHEREUM_TBTC_ADDRESS); + const wrappedTbtcToken = await getOrCreateTokenAccount(connection, payer, wrappedTbtcMint, payer.publicKey); + + // Bridge tbtc to token account. + const published = ethereumTokenBridge.publishTransferTokens( + tryNativeToHexString(ETHEREUM_TBTC_ADDRESS, "ethereum"), + 2, + BigInt("100000000000"), + 1, + wrappedTbtcToken.address.toBuffer().toString("hex"), + BigInt(0), + 0, + 0 + ); + + const signedVaa = await mockSignAndPostVaa(connection, payer, published); + + const tx = await redeemOnSolana( + connection, + SOLANA_CORE_BRIDGE_ADDRESS, + SOLANA_TOKEN_BRIDGE_ADDRESS, + payer.publicKey, + signedVaa, + ); + await web3.sendAndConfirmTransaction(connection, tx, [payer]); + + const recipientToken = await getOrCreateTokenAccount(connection, payer, tbtcMint, payer.publicKey); + + await program.methods + .depositWormholeTbtc(new anchor.BN(500)) + .accounts({ + custodian, + wrappedTbtcToken: gatewayWrappedTbtcToken, + wrappedTbtcMint, + tbtcMint, + recipientWrappedToken: wrappedTbtcToken.address, + recipientToken: recipientToken.address, + recipient: payer.publicKey, + tbtcConfig, + minterInfo, + tbtcProgram: tbtcProgram.programId, + }) + .signers(tbtc.maybeAuthorityAnd(payer, [])) + .rpc(); + + await tbtc.checkState(tbtcProgram, authority, 2, 2, 2000); + }) }); async function mockSignAndPostVaa(connection: web3.Connection, payer: web3.Keypair, published: Buffer) { diff --git a/cross-chain/solana/tests/helpers/tbtcHelpers.ts b/cross-chain/solana/tests/helpers/tbtcHelpers.ts index db05c47cf..19a06deaa 100644 --- a/cross-chain/solana/tests/helpers/tbtcHelpers.ts +++ b/cross-chain/solana/tests/helpers/tbtcHelpers.ts @@ -1,7 +1,16 @@ import * as anchor from "@coral-xyz/anchor"; import { Program } from "@coral-xyz/anchor"; +import * as spl from "@solana/spl-token"; import * as web3 from '@solana/web3.js'; import { Tbtc } from "../../target/types/tbtc"; +import { expect } from 'chai'; + +export function maybeAuthorityAnd( + signer, + signers + ) { + return signers.concat(signer instanceof (anchor.Wallet as any) ? [] : [signer]); + } export function getConfigPDA( program: Program, @@ -32,7 +41,7 @@ export function getMinterPDA( return web3.PublicKey.findProgramAddressSync( [ Buffer.from('minter-info'), - minter.publicKey.toBuffer(), + minter.toBuffer(), ], program.programId ); @@ -51,4 +60,44 @@ export function getGuardianPDA( program.programId ); } - \ No newline at end of file + +export async function checkState( + program: Program, + expectedAuthority, + expectedMinters, + expectedGuardians, + expectedTokensSupply + ) { + const [config,] = getConfigPDA(program); + let configState = await program.account.config.fetch(config); + + expect(configState.authority).to.eql(expectedAuthority.publicKey); + expect(configState.numMinters).to.equal(expectedMinters); + expect(configState.numGuardians).to.equal(expectedGuardians); + + let tbtcMint = configState.mint; + + let mintState = await spl.getMint(program.provider.connection, tbtcMint); + + expect(mintState.supply).to.equal(BigInt(expectedTokensSupply)); + } + +export async function addMinter( + program: Program, + authority, + minter + ): Promise { + const [config,] = getConfigPDA(program); + const [minterInfoPDA, _] = getMinterPDA(program, minter); + await program.methods + .addMinter() + .accounts({ + config, + authority: authority.publicKey, + minter, + minterInfo: minterInfoPDA, + }) + .signers(maybeAuthorityAnd(authority, [])) + .rpc(); + return minterInfoPDA; + } \ No newline at end of file