Skip to content

Commit 3b8cf77

Browse files
authored
fix(svm): L-01 create new vault on deposit if needed (#957)
* fix(svm): L-01 create new vault on deposit if needed Signed-off-by: Reinis Martinsons <reinis@umaproject.org> * fix: use stable toolchain in ci Signed-off-by: Reinis Martinsons <reinis@umaproject.org> * fix(svm): pin rust toolchain for solana (#960) * fix(svm): pin rust toolchain for solana Signed-off-by: Reinis Martinsons <reinis@umaproject.org> * fix: add local toolchain Signed-off-by: Reinis Martinsons <reinis@umaproject.org> * fix: add rustfmt to nightly Signed-off-by: Reinis Martinsons <reinis@umaproject.org> * fix: pin nightly in lint scripts Signed-off-by: Reinis Martinsons <reinis@umaproject.org> --------- Signed-off-by: Reinis Martinsons <reinis@umaproject.org> --------- Signed-off-by: Reinis Martinsons <reinis@umaproject.org>
1 parent a78241f commit 3b8cf77

File tree

2 files changed

+55
-3
lines changed

2 files changed

+55
-3
lines changed

programs/svm-spoke/src/instructions/deposit.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@
44
// implemented. For more details, refer to the documentation: https://docs.across.to
55

66
use anchor_lang::prelude::*;
7-
use anchor_spl::token_interface::{Mint, TokenAccount, TokenInterface};
7+
use anchor_spl::{
8+
associated_token::AssociatedToken,
9+
token_interface::{Mint, TokenAccount, TokenInterface},
10+
};
811

912
use crate::{
1013
constants::{MAX_EXCLUSIVITY_PERIOD_SECONDS, ZERO_DEPOSIT_ID},
@@ -30,6 +33,7 @@ use crate::{
3033
pub struct Deposit<'info> {
3134
#[account(mut)]
3235
pub signer: Signer<'info>,
36+
3337
#[account(
3438
mut,
3539
seeds = [b"state", state.seed.to_le_bytes().as_ref()],
@@ -50,7 +54,8 @@ pub struct Deposit<'info> {
5054
pub depositor_token_account: InterfaceAccount<'info, TokenAccount>,
5155

5256
#[account(
53-
mut,
57+
init_if_needed,
58+
payer = signer,
5459
associated_token::mint = mint,
5560
associated_token::authority = state, // Ensure owner is the state as tokens are sent here on deposit.
5661
associated_token::token_program = token_program
@@ -64,6 +69,10 @@ pub struct Deposit<'info> {
6469
pub mint: InterfaceAccount<'info, Mint>,
6570

6671
pub token_program: Interface<'info, TokenInterface>,
72+
73+
pub associated_token_program: Program<'info, AssociatedToken>,
74+
75+
pub system_program: Program<'info, System>,
6776
}
6877

6978
pub fn _deposit(

test/svm/SvmSpoke.Deposit.ts

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
pipe,
1313
} from "@solana/kit";
1414
import {
15+
ASSOCIATED_TOKEN_PROGRAM_ID,
1516
ExtensionType,
1617
NATIVE_MINT,
1718
TOKEN_2022_PROGRAM_ID,
@@ -163,9 +164,13 @@ describe("svm_spoke.deposit", () => {
163164
.accounts(calledDepositAccounts)
164165
.instruction();
165166
const depositTx = new Transaction().add(approveIx, depositIx);
166-
return sendAndConfirmTransaction(connection, depositTx, [payer, depositor]);
167+
return sendAndConfirmTransaction(connection, depositTx, [depositor]);
167168
};
168169

170+
before(async () => {
171+
await connection.requestAirdrop(depositor.publicKey, 10_000_000_000); // 10 SOL
172+
});
173+
169174
beforeEach(async () => {
170175
({ state, seed } = await initializeState());
171176

@@ -730,6 +735,44 @@ describe("svm_spoke.deposit", () => {
730735
);
731736
});
732737

738+
it("Deposits tokens to a new vault", async () => {
739+
// Create new input token without creating a new vault for it.
740+
await setupInputToken();
741+
const inputTokenAccount = await provider.connection.getAccountInfo(inputToken);
742+
if (inputTokenAccount === null) throw new Error("Input mint account not found");
743+
vault = getAssociatedTokenAddressSync(
744+
inputToken,
745+
state,
746+
true,
747+
inputTokenAccount.owner,
748+
ASSOCIATED_TOKEN_PROGRAM_ID
749+
);
750+
751+
// Update global variables using the new input token.
752+
depositData.inputToken = inputToken;
753+
depositAccounts.depositorTokenAccount = depositorTA;
754+
depositAccounts.vault = vault;
755+
depositAccounts.mint = inputToken;
756+
757+
// Verify there is no vault account before the deposit.
758+
assert.isNull(await provider.connection.getAccountInfo(vault), "Vault should not exist before the deposit");
759+
760+
// Execute the deposit call
761+
await approvedDeposit(depositData);
762+
763+
// Verify tokens leave the depositor's account
764+
const depositorAccount = await getAccount(connection, depositorTA);
765+
assertSE(
766+
depositorAccount.amount,
767+
seedBalance - depositData.inputAmount.toNumber(),
768+
"Depositor's balance should be reduced by the deposited amount"
769+
);
770+
771+
// Verify tokens are credited into the new vault
772+
const vaultAccount = await getAccount(connection, vault);
773+
assertSE(vaultAccount.amount, depositData.inputAmount, "Vault balance should equal the deposited amount");
774+
});
775+
733776
describe("codama client and solana kit", () => {
734777
it("Deposit with with solana kit and codama client", async () => {
735778
// typescript is not happy with the depositData object

0 commit comments

Comments
 (0)