Skip to content

Commit 5ff8680

Browse files
committed
js
1 parent 7b1128d commit 5ff8680

5 files changed

Lines changed: 178 additions & 0 deletions

File tree

clients/js-legacy/src/instructions.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,4 +86,19 @@ export class SinglePoolInstruction {
8686
);
8787
return modernInstructionToLegacy(instruction);
8888
}
89+
90+
static async depositSol(
91+
voteAccount: PublicKey,
92+
userWallet: PublicKey,
93+
userTokenAccount: PublicKey,
94+
lamports: number | bigint,
95+
): Promise<TransactionInstruction> {
96+
const instruction = await PoolInstructionModern.depositSol(
97+
voteAccount.toBase58() as VoteAccountAddress,
98+
userWallet.toBase58() as Address,
99+
userTokenAccount.toBase58() as Address,
100+
BigInt(lamports),
101+
);
102+
return modernInstructionToLegacy(instruction);
103+
}
89104
}

clients/js-legacy/src/transactions.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,14 @@ interface WithdrawParams {
2727
userTokenAuthority?: PublicKey;
2828
}
2929

30+
interface DepositSolParams {
31+
connection: Connection;
32+
voteAccount: PublicKey;
33+
userWallet: PublicKey;
34+
lamports: number | bigint;
35+
userTokenAccount?: PublicKey;
36+
}
37+
3038
export class SinglePoolProgram {
3139
static programId: PublicKey = new PublicKey(PoolProgramModern.programAddress);
3240
static space: number = Number(PoolProgramModern.space);
@@ -105,4 +113,11 @@ export class SinglePoolProgram {
105113

106114
return modernTransactionToLegacy(modernTransaction);
107115
}
116+
117+
static async depositSol(params: DepositSolParams) {
118+
const modernParams = paramsToModern(params);
119+
const modernTransaction = await PoolProgramModern.depositSol(modernParams);
120+
121+
return modernTransactionToLegacy(modernTransaction);
122+
}
108123
}

clients/js-legacy/tests/transactions.test.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -448,3 +448,36 @@ test('get vote account address', async (t) => {
448448
const chainVoteAccount = await getVoteAccountAddressForPool(connection, poolAddress);
449449
t.true(chainVoteAccount.equals(voteAccountAddress), 'got correct vote account');
450450
});
451+
452+
test('deposit sol', async (t) => {
453+
const context = await startWithContext();
454+
const svm = context.svm;
455+
const payer = context.payer;
456+
const connection = new LiteConnection(svm, payer);
457+
458+
const voteAccountAddress = new PublicKey(voteAccount.pubkey);
459+
const poolAddress = await findPoolAddress(SinglePoolProgram.programId, voteAccountAddress);
460+
const onrampAddress = await findPoolOnRampAddress(SinglePoolProgram.programId, poolAddress);
461+
462+
// initialize pool
463+
let transaction = await SinglePoolProgram.initialize(
464+
connection,
465+
voteAccountAddress,
466+
payer.publicKey,
467+
);
468+
await processTransaction(context, transaction);
469+
context.advanceEpoch();
470+
471+
// deposit sol
472+
transaction = await SinglePoolProgram.depositSol({
473+
connection,
474+
voteAccount: voteAccountAddress,
475+
userWallet: payer.publicKey,
476+
lamports: LAMPORTS_PER_SOL,
477+
});
478+
await processTransaction(context, transaction);
479+
480+
const stakeRent = await connection.getMinimumBalanceForRentExemption(StakeProgram.space);
481+
const onrampAccount = svm.getAccount(onrampAddress);
482+
t.is(onrampAccount.lamports, LAMPORTS_PER_SOL + stakeRent, 'sol has been deposited');
483+
});

clients/js/src/instructions.ts

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,28 @@ type InitializeOnRampInstruction = Instruction<typeof SINGLE_POOL_PROGRAM_ID> &
157157
> &
158158
InstructionWithData<Uint8Array>;
159159

160+
type DepositSolInstruction = Instruction<typeof SINGLE_POOL_PROGRAM_ID> &
161+
InstructionWithAccounts<
162+
[
163+
ReadonlyAccount<VoteAccountAddress>,
164+
ReadonlyAccount<PoolAddress>,
165+
WritableAccount<PoolStakeAddress>,
166+
WritableAccount<PoolOnRampAddress>,
167+
WritableAccount<PoolMintAddress>,
168+
ReadonlyAccount<PoolStakeAuthorityAddress>,
169+
ReadonlyAccount<PoolMintAuthorityAddress>,
170+
WritableSignerAccount<Address>, // user lamport
171+
WritableAccount<Address>, // user token
172+
ReadonlyAccount<typeof SYSVAR_CLOCK_ID>,
173+
ReadonlyAccount<typeof SYSVAR_STAKE_HISTORY_ID>,
174+
ReadonlyAccount<typeof STAKE_CONFIG_ID>,
175+
ReadonlyAccount<typeof SYSTEM_PROGRAM_ID>,
176+
ReadonlyAccount<typeof TOKEN_PROGRAM_ID>,
177+
ReadonlyAccount<typeof STAKE_PROGRAM_ID>,
178+
]
179+
> &
180+
InstructionWithData<Uint8Array>;
181+
160182
const enum SinglePoolInstructionType {
161183
InitializePool = 0,
162184
ReplenishPool,
@@ -165,6 +187,7 @@ const enum SinglePoolInstructionType {
165187
CreateTokenMetadata,
166188
UpdateTokenMetadata,
167189
InitializeOnRamp,
190+
DepositSol,
168191
}
169192

170193
export const SinglePoolInstruction = {
@@ -175,6 +198,7 @@ export const SinglePoolInstruction = {
175198
createTokenMetadata: createTokenMetadataInstruction,
176199
updateTokenMetadata: updateTokenMetadataInstruction,
177200
initializeOnRamp: initializeOnRampInstruction,
201+
depositSol: depositSolInstruction,
178202
};
179203

180204
export async function initializePoolInstruction(
@@ -430,3 +454,44 @@ export async function initializeOnRampInstruction(
430454
programAddress,
431455
};
432456
}
457+
458+
export async function depositSolInstruction(
459+
voteAccount: VoteAccountAddress,
460+
userLamportAccount: Address,
461+
userTokenAccount: Address,
462+
lamports: bigint,
463+
): Promise<DepositSolInstruction> {
464+
const programAddress = SINGLE_POOL_PROGRAM_ID;
465+
const pool = await findPoolAddress(programAddress, voteAccount);
466+
const [stake, onramp, mint, stakeAuthority, mintAuthority] = await Promise.all([
467+
findPoolStakeAddress(programAddress, pool),
468+
findPoolOnRampAddress(programAddress, pool),
469+
findPoolMintAddress(programAddress, pool),
470+
findPoolStakeAuthorityAddress(programAddress, pool),
471+
findPoolMintAuthorityAddress(programAddress, pool),
472+
]);
473+
474+
const data = new Uint8Array([SinglePoolInstructionType.DepositSol, ...u64(lamports)]);
475+
476+
return {
477+
data,
478+
accounts: [
479+
{ address: voteAccount, role: AccountRole.READONLY },
480+
{ address: pool, role: AccountRole.READONLY },
481+
{ address: stake, role: AccountRole.WRITABLE },
482+
{ address: onramp, role: AccountRole.WRITABLE },
483+
{ address: mint, role: AccountRole.WRITABLE },
484+
{ address: stakeAuthority, role: AccountRole.READONLY },
485+
{ address: mintAuthority, role: AccountRole.READONLY },
486+
{ address: userLamportAccount, role: AccountRole.WRITABLE_SIGNER },
487+
{ address: userTokenAccount, role: AccountRole.WRITABLE },
488+
{ address: SYSVAR_CLOCK_ID, role: AccountRole.READONLY },
489+
{ address: SYSVAR_STAKE_HISTORY_ID, role: AccountRole.READONLY },
490+
{ address: STAKE_CONFIG_ID, role: AccountRole.READONLY },
491+
{ address: SYSTEM_PROGRAM_ID, role: AccountRole.READONLY },
492+
{ address: TOKEN_PROGRAM_ID, role: AccountRole.READONLY },
493+
{ address: STAKE_PROGRAM_ID, role: AccountRole.READONLY },
494+
],
495+
programAddress,
496+
};
497+
}

clients/js/src/transactions.ts

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ import {
4040
createTokenMetadataInstruction,
4141
updateTokenMetadataInstruction,
4242
initializeOnRampInstruction,
43+
depositSolInstruction,
4344
} from './instructions.js';
4445
import {
4546
STAKE_PROGRAM_ID,
@@ -74,6 +75,14 @@ interface WithdrawParams {
7475
userTokenAuthority?: Address;
7576
}
7677

78+
interface DepositSolParams {
79+
rpc: Rpc<GetAccountInfoApi & GetMinimumBalanceForRentExemptionApi & GetStakeMinimumDelegationApi>;
80+
voteAccount: VoteAccountAddress;
81+
userWallet: Address;
82+
lamports: bigint;
83+
userTokenAccount?: Address;
84+
}
85+
7786
export const SINGLE_POOL_ACCOUNT_SIZE = 33n;
7887

7988
export const SinglePoolProgram = {
@@ -86,6 +95,7 @@ export const SinglePoolProgram = {
8695
createTokenMetadata: createTokenMetadataTransaction,
8796
updateTokenMetadata: updateTokenMetadataTransaction,
8897
initializeOnRamp: initializeOnRampTransaction,
98+
depositSol: depositSolTransaction,
8999
};
90100

91101
async function getInitializeInstructionPlan(
@@ -336,3 +346,43 @@ export async function initializeOnRampTransaction(
336346

337347
return transaction;
338348
}
349+
350+
export async function depositSolTransaction(params: DepositSolParams) {
351+
const { rpc, voteAccount, userWallet, lamports } = params;
352+
353+
let transaction = { instructions: [] as any, version: 'legacy' as TransactionVersion };
354+
355+
const pool = await findPoolAddress(SINGLE_POOL_PROGRAM_ID, voteAccount);
356+
const mint = await findPoolMintAddress(SINGLE_POOL_PROGRAM_ID, pool);
357+
358+
const userAssociatedTokenAccount = await getAssociatedTokenAddress(mint, userWallet);
359+
const userTokenAccount = params.userTokenAccount || userAssociatedTokenAccount;
360+
361+
if (
362+
userTokenAccount == userAssociatedTokenAccount &&
363+
(await rpc.getAccountInfo(userAssociatedTokenAccount).send()) == null
364+
) {
365+
transaction = appendTransactionMessageInstruction(
366+
TokenInstruction.createAssociatedTokenAccount({
367+
payer: userWallet,
368+
associatedAccount: userAssociatedTokenAccount,
369+
owner: userWallet,
370+
mint,
371+
}),
372+
transaction,
373+
);
374+
}
375+
376+
// NOTE in our rust instruction builder, we transfer lamports to an escrow account.
377+
// this allows us to give greater assurance to the end user that their signing
378+
// authority cannot be misused by our benevolent, yet untrusted, program.
379+
// unfortunately this is not possible in js middleware but dapps may wish to consider
380+
// doing similar by injecting a system transfer between these two instructions
381+
382+
transaction = appendTransactionMessageInstruction(
383+
await depositSolInstruction(voteAccount, userWallet, userTokenAccount, lamports),
384+
transaction,
385+
);
386+
387+
return transaction;
388+
}

0 commit comments

Comments
 (0)