From 387e68a303f75f29ec89360c942c7067e7f4a4fa Mon Sep 17 00:00:00 2001 From: Reinis Martinsons Date: Wed, 16 Apr 2025 10:28:14 +0000 Subject: [PATCH 1/3] fix(svm): L-01 create new vault on deposit if needed Signed-off-by: Reinis Martinsons --- .../svm-spoke/src/instructions/deposit.rs | 13 +++++- test/svm/SvmSpoke.Deposit.ts | 46 ++++++++++++++++++- 2 files changed, 56 insertions(+), 3 deletions(-) diff --git a/programs/svm-spoke/src/instructions/deposit.rs b/programs/svm-spoke/src/instructions/deposit.rs index 80497bc8b..8c712ebfa 100644 --- a/programs/svm-spoke/src/instructions/deposit.rs +++ b/programs/svm-spoke/src/instructions/deposit.rs @@ -4,7 +4,10 @@ // implemented. For more details, refer to the documentation: https://docs.across.to use anchor_lang::prelude::*; -use anchor_spl::token_interface::{Mint, TokenAccount, TokenInterface}; +use anchor_spl::{ + associated_token::AssociatedToken, + token_interface::{Mint, TokenAccount, TokenInterface}, +}; use crate::{ constants::{MAX_EXCLUSIVITY_PERIOD_SECONDS, ZERO_DEPOSIT_ID}, @@ -28,6 +31,7 @@ use crate::{ pub struct Deposit<'info> { #[account(mut)] pub signer: Signer<'info>, + #[account( mut, seeds = [b"state", state.seed.to_le_bytes().as_ref()], @@ -45,7 +49,8 @@ pub struct Deposit<'info> { pub depositor_token_account: InterfaceAccount<'info, TokenAccount>, #[account( - mut, + init_if_needed, + payer = signer, associated_token::mint = mint, associated_token::authority = state, // Ensure owner is the state as tokens are sent here on deposit. associated_token::token_program = token_program @@ -59,6 +64,10 @@ pub struct Deposit<'info> { pub mint: InterfaceAccount<'info, Mint>, pub token_program: Interface<'info, TokenInterface>, + + pub associated_token_program: Program<'info, AssociatedToken>, + + pub system_program: Program<'info, System>, } pub fn _deposit( diff --git a/test/svm/SvmSpoke.Deposit.ts b/test/svm/SvmSpoke.Deposit.ts index c99a12430..3d27a465a 100644 --- a/test/svm/SvmSpoke.Deposit.ts +++ b/test/svm/SvmSpoke.Deposit.ts @@ -21,6 +21,7 @@ import { createMint, createReallocateInstruction, getAccount, + getAssociatedTokenAddressSync, getOrCreateAssociatedTokenAccount, mintTo, } from "@solana/spl-token"; @@ -115,10 +116,14 @@ describe("svm_spoke.deposit", () => { .accounts(calledDepositAccounts) .instruction(); const depositTx = new Transaction().add(approveIx, depositIx); - const tx = await sendAndConfirmTransaction(connection, depositTx, [payer, depositor]); + const tx = await sendAndConfirmTransaction(connection, depositTx, [depositor]); return tx; }; + before(async () => { + await connection.requestAirdrop(depositor.publicKey, 10_000_000_000); // 10 SOL + }); + beforeEach(async () => { ({ state } = await initializeState()); @@ -578,6 +583,45 @@ describe("svm_spoke.deposit", () => { } }); + it("Deposits tokens to a new vault", async () => { + // Create new input token without creating a new vault for it. + await setupInputToken(); + const inputTokenAccount = await provider.connection.getAccountInfo(inputToken); + if (inputTokenAccount === null) throw new Error("Input mint account not found"); + vault = getAssociatedTokenAddressSync( + inputToken, + state, + true, + inputTokenAccount.owner, + ASSOCIATED_TOKEN_PROGRAM_ID + ); + + // Update global variables using the new input token. + depositData.inputToken = inputToken; + depositAccounts.depositorTokenAccount = depositorTA; + depositAccounts.vault = vault; + depositAccounts.mint = inputToken; + + // Verify there is no vault account before the deposit. + assert.isNull(await provider.connection.getAccountInfo(vault), "Vault should not exist before the deposit"); + + // Execute the deposit call + const depositDataValues = Object.values(depositData) as DepositDataValues; + await approvedDeposit(depositDataValues); + + // Verify tokens leave the depositor's account + const depositorAccount = await getAccount(connection, depositorTA); + assertSE( + depositorAccount.amount, + seedBalance - depositData.inputAmount.toNumber(), + "Depositor's balance should be reduced by the deposited amount" + ); + + // Verify tokens are credited into the new vault + const vaultAccount = await getAccount(connection, vault); + assertSE(vaultAccount.amount, depositData.inputAmount, "Vault balance should equal the deposited amount"); + }); + describe("codama client and solana kit", () => { it("Deposit with with solana kit and codama client", async () => { // typescript is not happy with the depositData object From 5a911fdbe9bb787ce6cdb95dec10105e571cfde0 Mon Sep 17 00:00:00 2001 From: Reinis Martinsons Date: Wed, 16 Apr 2025 11:36:20 +0000 Subject: [PATCH 2/3] fix: use stable toolchain in ci Signed-off-by: Reinis Martinsons --- .github/workflows/pr.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 3b85c6d59..51805e5ad 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -28,11 +28,11 @@ jobs: - name: Install Cargo toolchain uses: actions-rs/toolchain@v1 with: - toolchain: nightly + toolchain: stable profile: minimal components: rustc - name: Install packages - run: yarn install --frozen-lockfile && rustup component add --toolchain nightly-x86_64-unknown-linux-gnu rustfmt + run: yarn install --frozen-lockfile && rustup component add --toolchain stable-x86_64-unknown-linux-gnu rustfmt - name: Lint js shell: bash run: yarn lint-js From 9d0168416bcf3fe73c0ae61222dad4a028c38414 Mon Sep 17 00:00:00 2001 From: Reinis Martinsons <77973553+Reinis-FRP@users.noreply.github.com> Date: Thu, 17 Apr 2025 15:37:49 +0300 Subject: [PATCH 3/3] fix(svm): pin rust toolchain for solana (#960) * fix(svm): pin rust toolchain for solana Signed-off-by: Reinis Martinsons * fix: add local toolchain Signed-off-by: Reinis Martinsons * fix: add rustfmt to nightly Signed-off-by: Reinis Martinsons * fix: pin nightly in lint scripts Signed-off-by: Reinis Martinsons --------- Signed-off-by: Reinis Martinsons --- .github/workflows/pr.yml | 6 +++--- package.json | 11 ++++++----- rust-toolchain.toml | 2 ++ scripts/anchor-build.sh | 16 ++++++++++++++++ scripts/anchor-test.sh | 19 +++++++++++++++++++ 5 files changed, 46 insertions(+), 8 deletions(-) create mode 100644 rust-toolchain.toml create mode 100644 scripts/anchor-build.sh create mode 100644 scripts/anchor-test.sh diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 51805e5ad..3b93ab3c0 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -28,11 +28,11 @@ jobs: - name: Install Cargo toolchain uses: actions-rs/toolchain@v1 with: - toolchain: stable + toolchain: nightly-2025-04-01 profile: minimal components: rustc - name: Install packages - run: yarn install --frozen-lockfile && rustup component add --toolchain stable-x86_64-unknown-linux-gnu rustfmt + run: yarn install --frozen-lockfile && rustup component add --toolchain nightly-2025-04-01-x86_64-unknown-linux-gnu rustfmt - name: Lint js shell: bash run: yarn lint-js @@ -69,7 +69,7 @@ jobs: - name: Install Cargo toolchain uses: actions-rs/toolchain@v1 with: - toolchain: stable + toolchain: nightly-2025-04-01 profile: minimal components: rustc - name: Cache Cargo dependencies diff --git a/package.json b/package.json index 7ae0acdae..8faafdbe0 100644 --- a/package.json +++ b/package.json @@ -22,24 +22,25 @@ "lint": "yarn lint-solidity && yarn lint-js && yarn lint-rust", "lint-solidity": "yarn solhint ./contracts/**/*.sol", "lint-js": "yarn prettier --list-different **/*.js **/*.ts", - "lint-rust": "cargo +nightly fmt --all -- --check && cargo clippy", - "lint-fix": "yarn prettier --write **/*.js **/*.ts ./programs/**/*.rs ./contracts**/*.sol && cargo +nightly fmt --all && cargo clippy", + "lint-rust": "cargo +nightly-2025-04-01 fmt --all -- --check && cargo clippy", + "lint-fix": "yarn prettier --write **/*.js **/*.ts ./programs/**/*.rs ./contracts**/*.sol && cargo +nightly-2025-04-01 fmt --all && cargo clippy", "clean-fast": "for dir in node_modules cache cache-zk artifacts artifacts-zk dist typechain; do mv \"${dir}\" \"_${dir}\"; rm -rf \"_${dir}\" &; done", "clean": "rm -rf node_modules cache cache-zk artifacts artifacts-zk dist typechain", "generate-svm-assets": "sh ./scripts/generate-svm-assets.sh && yarn generate-svm-clients", "generate-svm-clients": "yarn ts-node ./scripts/svm/utils/generate-svm-clients.ts && yarn ts-node ./scripts/svm/utils/rename-clients-imports.ts", "build-evm": "hardhat compile", - "build-svm": "echo 'Generating IDLs...' && anchor build > /dev/null 2>&1 || true && anchor run generateExternalTypes && anchor build", + "build-svm": "echo 'Generating IDLs...' && yarn anchor-build > /dev/null 2>&1 || true && anchor run generateExternalTypes && yarn anchor-build", "build-ts": "rm -rf ./dist && tsc && rsync -a --include '*/' --include '*.d.ts' --exclude '*' ./typechain ./dist/", "copy-idl": "mkdir -p dist/src/svm/assets/idl && cp src/svm/assets/idl/*.json dist/src/svm/assets/idl/", "build": "yarn build-evm && yarn build-svm && yarn generate-svm-assets && yarn build-ts && yarn copy-idl", "test-evm": "IS_TEST=true hardhat test", - "test-svm": "anchor test -- --features test", + "test-svm": "sh ./scripts/anchor-test.sh", "test": "yarn test-evm && yarn test-svm", "test:report-gas": "IS_TEST=true REPORT_GAS=true hardhat test", "generate-evm-assets": "rm -rf typechain && TYPECHAIN=ethers yarn hardhat typechain", "prepublish": "yarn build && hardhat export --export-all ./cache/massExport.json && ts-node ./scripts/processHardhatExport.ts && prettier --write ./deployments/deployments.json && yarn generate-evm-assets", - "pre-commit-hook": "sh scripts/preCommitHook.sh" + "pre-commit-hook": "sh scripts/preCommitHook.sh", + "anchor-build": "sh ./scripts/anchor-build.sh" }, "dependencies": { "@across-protocol/constants": "^3.1.46", diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 000000000..e5cd56d0f --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,2 @@ +[toolchain] +channel = "nightly-2025-04-01" diff --git a/scripts/anchor-build.sh b/scripts/anchor-build.sh new file mode 100644 index 000000000..73752644c --- /dev/null +++ b/scripts/anchor-build.sh @@ -0,0 +1,16 @@ +#!/bin/sh + +echo "๐Ÿ”จ Building anchor programs (no IDL)..." +anchor build --no-idl + +echo "๐Ÿ“ฆ Generating IDLs (using nightly)..." + +for program in programs/*; do + [ -d "$program" ] || continue + + dir_name=$(basename "$program") + program_name=$(echo "$dir_name" | tr '-' '_') + + echo "โ†’ IDL for $program_name" + RUSTUP_TOOLCHAIN="nightly-2025-04-01" anchor idl build -p "$dir_name" -o "target/idl/$program_name.json" -t "target/types/$program_name.ts" +done diff --git a/scripts/anchor-test.sh b/scripts/anchor-test.sh new file mode 100644 index 000000000..a5f121bfa --- /dev/null +++ b/scripts/anchor-test.sh @@ -0,0 +1,19 @@ +#!/bin/sh + +echo "๐Ÿ”จ Building anchor programs (with test feature, no IDL)..." +anchor build --no-idl -- --features test + +echo "๐Ÿ“ฆ Generating IDLs (using nightly)..." + +for program in programs/*; do + [ -d "$program" ] || continue + + dir_name=$(basename "$program") + program_name=$(echo "$dir_name" | tr '-' '_') + + echo "โ†’ IDL for $program_name" + RUSTUP_TOOLCHAIN="nightly-2025-04-01" anchor idl build -p "$dir_name" -o "target/idl/$program_name.json" -t "target/types/$program_name.ts" +done + +echo "๐Ÿงช Running anchor tests..." +anchor test --skip-build