diff --git a/src/base/base.ts b/src/base/base.ts index d8750e88..a72848df 100644 --- a/src/base/base.ts +++ b/src/base/base.ts @@ -86,20 +86,32 @@ export class Base { const ata = await Spl.getAssociatedTokenAccount({ mint, owner }); if (Token.WSOL.mint.equals(mint)) { - const newTokenAccount = await Spl.insertCreateWrappedNativeAccountInstructions({ - connection, - owner, - payer, - instructions: frontInstructions, - signers, - amount, - }); - // if no endInstructions provide, no need to close - if (endInstructions) { - endInstructions.push(Spl.makeCloseAccountInstruction({ tokenAccount: newTokenAccount, owner, payer })); + if (!tokenAccount) { + const newTokenAccount = await Spl.insertCreateWrappedNativeAccountInstructions({ + connection, + owner, + payer, + instructions: frontInstructions, + signers, + amount, + }); + // if no endInstructions provide, no need to close + if (endInstructions) { + endInstructions.push(Spl.makeCloseAccountInstruction({ tokenAccount: newTokenAccount, owner, payer })); + } + + return newTokenAccount; + } else { + const newIxs = await Spl.makeEnsureWrappedNativeAccountBalanceInstructions({ + connection, + owner, + accountKey: tokenAccount, + payer, + amount, + }); + frontInstructions.push(...newIxs); + return tokenAccount; } - - return newTokenAccount; } else if (!tokenAccount || (side === "out" && !ata.equals(tokenAccount) && !bypassAssociatedCheck)) { frontInstructions.push( Spl.makeCreateAssociatedTokenAccountInstruction({ diff --git a/src/spl/spl.ts b/src/spl/spl.ts index e3f8ee5a..bfd66dc7 100644 --- a/src/spl/spl.ts +++ b/src/spl/spl.ts @@ -1,6 +1,13 @@ -import { Token as _Token, u64 as _u64 } from "@solana/spl-token"; +// @ts-ignore +import { Token as _Token, u64 as _u64, getAccount, createSyncNativeInstruction } from "@solana/spl-token"; import { - Commitment, Connection, Keypair, PublicKey, Signer, SystemProgram, TransactionInstruction, + Commitment, + Connection, + Keypair, + PublicKey, + Signer, + SystemProgram, + TransactionInstruction, } from "@solana/web3.js"; import BN from "bn.js"; @@ -38,6 +45,50 @@ export class Spl { ); } + // https://github.com/solana-labs/solana-program-library/blob/master/token/js/client/token.js + static async makeEnsureWrappedNativeAccountBalanceInstructions({ + connection, + owner, + accountKey, + payer, + amount, + // baseRentExemption, + commitment, + }: { + connection: Connection; + owner: PublicKey; + accountKey: PublicKey; + payer: PublicKey; + amount: BigNumberish; + // baseRentExemption?: number; + commitment?: Commitment; + }): Promise { + const instructions: TransactionInstruction[] = []; + + const balanceNeededForRent = await connection.getMinimumBalanceForRentExemption( + SPL_ACCOUNT_LAYOUT.span, + commitment, + ); + + const lamportsAlreadyPresent = (await getAccount(connection, accountKey)).lamports; + const lamportsToTransfer = parseBigNumberish(amount) + .add(new BN(balanceNeededForRent)) + .sub(new BN(lamportsAlreadyPresent)); + + instructions.push( + SystemProgram.transfer({ + fromPubkey: payer, + toPubkey: accountKey, + lamports: lamportsToTransfer.toNumber(), + programId: TOKEN_PROGRAM_ID, + }), + ); + + instructions.push(createSyncNativeInstruction(accountKey)); + + return instructions; + } + // https://github.com/solana-labs/solana-program-library/blob/master/token/js/client/token.js static async makeCreateWrappedNativeAccountInstructions({ connection,