Skip to content
This repository was archived by the owner on Mar 11, 2025. It is now read-only.

Commit bbc5f57

Browse files
authored
token-swap: Add slippage to swap / withdraw / deposit (#560)
* token-swap: Add slippage to swap / withdraw / deposit * Update JS snake_case -> camelCase * Run prettier
1 parent f491739 commit bbc5f57

File tree

7 files changed

+446
-91
lines changed

7 files changed

+446
-91
lines changed

token-swap/js/cli/token-swap-test.js

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,9 @@ let tokenAccountB: PublicKey;
3737

3838
// Initial amount in each swap token
3939
const BASE_AMOUNT = 1000;
40-
// Amount passed to instructions
41-
const USER_AMOUNT = 100;
40+
// Amount passed to swap instruction
41+
const SWAP_AMOUNT_IN = 100;
42+
const SWAP_AMOUNT_OUT = 69;
4243
// Pool token amount minted on init
4344
const DEFAULT_POOL_TOKEN_AMOUNT = 1000000000;
4445
// Pool token amount to withdraw / deposit
@@ -253,6 +254,8 @@ export async function deposit(): Promise<void> {
253254
newAccountPool,
254255
tokenProgramId,
255256
POOL_TOKEN_AMOUNT,
257+
tokenA,
258+
tokenB,
256259
);
257260

258261
let info;
@@ -302,6 +305,8 @@ export async function withdraw(): Promise<void> {
302305
userAccountB,
303306
tokenProgramId,
304307
POOL_TOKEN_AMOUNT,
308+
tokenA,
309+
tokenB,
305310
);
306311

307312
//const poolMintInfo = await tokenPool.getMintInfo();
@@ -323,8 +328,8 @@ export async function withdraw(): Promise<void> {
323328
export async function swap(): Promise<void> {
324329
console.log('Creating swap token a account');
325330
let userAccountA = await mintA.createAccount(owner.publicKey);
326-
await mintA.mintTo(userAccountA, owner, [], USER_AMOUNT);
327-
await mintA.approve(userAccountA, authority, owner, [], USER_AMOUNT);
331+
await mintA.mintTo(userAccountA, owner, [], SWAP_AMOUNT_IN);
332+
await mintA.approve(userAccountA, authority, owner, [], SWAP_AMOUNT_IN);
328333
console.log('Creating swap token b account');
329334
let userAccountB = await mintB.createAccount(owner.publicKey);
330335
const [tokenProgramId] = await GetPrograms(connection);
@@ -337,18 +342,19 @@ export async function swap(): Promise<void> {
337342
tokenAccountB,
338343
userAccountB,
339344
tokenProgramId,
340-
USER_AMOUNT,
345+
SWAP_AMOUNT_IN,
346+
SWAP_AMOUNT_OUT,
341347
);
342348
await sleep(500);
343349
let info;
344350
info = await mintA.getAccountInfo(userAccountA);
345351
assert(info.amount.toNumber() == 0);
346352
info = await mintA.getAccountInfo(tokenAccountA);
347-
assert(info.amount.toNumber() == BASE_AMOUNT + USER_AMOUNT);
353+
assert(info.amount.toNumber() == BASE_AMOUNT + SWAP_AMOUNT_IN);
348354
info = await mintB.getAccountInfo(tokenAccountB);
349-
assert(info.amount.toNumber() == 931);
355+
assert(info.amount.toNumber() == BASE_AMOUNT - SWAP_AMOUNT_OUT);
350356
info = await mintB.getAccountInfo(userAccountB);
351-
assert(info.amount.toNumber() == 69);
357+
assert(info.amount.toNumber() == SWAP_AMOUNT_OUT);
352358
info = await tokenPool.getAccountInfo(tokenAccountPool);
353359
assert(
354360
info.amount.toNumber() == DEFAULT_POOL_TOKEN_AMOUNT - POOL_TOKEN_AMOUNT,

token-swap/js/client/token-swap.js

Lines changed: 40 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -345,7 +345,8 @@ export class TokenSwap {
345345
swapDestination: PublicKey,
346346
destination: PublicKey,
347347
tokenProgramId: PublicKey,
348-
amount: number | Numberu64,
348+
amountIn: number | Numberu64,
349+
minimumAmountOut: number | Numberu64,
349350
): Promise<TransactionSignature> {
350351
return await sendAndConfirmTransaction(
351352
'swap',
@@ -360,7 +361,8 @@ export class TokenSwap {
360361
destination,
361362
this.programId,
362363
tokenProgramId,
363-
amount,
364+
amountIn,
365+
minimumAmountOut,
364366
),
365367
),
366368
this.payer,
@@ -376,18 +378,21 @@ export class TokenSwap {
376378
destination: PublicKey,
377379
swapProgramId: PublicKey,
378380
tokenProgramId: PublicKey,
379-
amount: number | Numberu64,
381+
amountIn: number | Numberu64,
382+
minimumAmountOut: number | Numberu64,
380383
): TransactionInstruction {
381384
const dataLayout = BufferLayout.struct([
382385
BufferLayout.u8('instruction'),
383-
Layout.uint64('amount'),
386+
Layout.uint64('amountIn'),
387+
Layout.uint64('minimumAmountOut'),
384388
]);
385389

386390
const data = Buffer.alloc(dataLayout.span);
387391
dataLayout.encode(
388392
{
389393
instruction: 1, // Swap instruction
390-
amount: new Numberu64(amount).toBuffer(),
394+
amountIn: new Numberu64(amountIn).toBuffer(),
395+
minimumAmountOut: new Numberu64(minimumAmountOut).toBuffer(),
391396
},
392397
data,
393398
);
@@ -430,7 +435,9 @@ export class TokenSwap {
430435
poolToken: PublicKey,
431436
poolAccount: PublicKey,
432437
tokenProgramId: PublicKey,
433-
amount: number | Numberu64,
438+
poolTokenAmount: number | Numberu64,
439+
maximumTokenA: number | Numberu64,
440+
maximumTokenB: number | Numberu64,
434441
): Promise<TransactionSignature> {
435442
return await sendAndConfirmTransaction(
436443
'deposit',
@@ -447,7 +454,9 @@ export class TokenSwap {
447454
poolAccount,
448455
this.programId,
449456
tokenProgramId,
450-
amount,
457+
poolTokenAmount,
458+
maximumTokenA,
459+
maximumTokenB,
451460
),
452461
),
453462
this.payer,
@@ -465,18 +474,24 @@ export class TokenSwap {
465474
poolAccount: PublicKey,
466475
swapProgramId: PublicKey,
467476
tokenProgramId: PublicKey,
468-
amount: number | Numberu64,
477+
poolTokenAmount: number | Numberu64,
478+
maximumTokenA: number | Numberu64,
479+
maximumTokenB: number | Numberu64,
469480
): TransactionInstruction {
470481
const dataLayout = BufferLayout.struct([
471482
BufferLayout.u8('instruction'),
472-
Layout.uint64('amount'),
483+
Layout.uint64('poolTokenAmount'),
484+
Layout.uint64('maximumTokenA'),
485+
Layout.uint64('maximumTokenB'),
473486
]);
474487

475488
const data = Buffer.alloc(dataLayout.span);
476489
dataLayout.encode(
477490
{
478491
instruction: 2, // Deposit instruction
479-
amount: new Numberu64(amount).toBuffer(),
492+
poolTokenAmount: new Numberu64(poolTokenAmount).toBuffer(),
493+
maximumTokenA: new Numberu64(maximumTokenA).toBuffer(),
494+
maximumTokenB: new Numberu64(maximumTokenB).toBuffer(),
480495
},
481496
data,
482497
);
@@ -521,7 +536,9 @@ export class TokenSwap {
521536
userAccountA: PublicKey,
522537
userAccountB: PublicKey,
523538
tokenProgramId: PublicKey,
524-
amount: number | Numberu64,
539+
poolTokenAmount: number | Numberu64,
540+
minimumTokenA: number | Numberu64,
541+
minimumTokenB: number | Numberu64,
525542
): Promise<TransactionSignature> {
526543
return await sendAndConfirmTransaction(
527544
'withdraw',
@@ -538,7 +555,9 @@ export class TokenSwap {
538555
userAccountB,
539556
this.programId,
540557
tokenProgramId,
541-
amount,
558+
poolTokenAmount,
559+
minimumTokenA,
560+
minimumTokenB,
542561
),
543562
),
544563
this.payer,
@@ -556,18 +575,24 @@ export class TokenSwap {
556575
userAccountB: PublicKey,
557576
swapProgramId: PublicKey,
558577
tokenProgramId: PublicKey,
559-
amount: number | Numberu64,
578+
poolTokenAmount: number | Numberu64,
579+
minimumTokenA: number | Numberu64,
580+
minimumTokenB: number | Numberu64,
560581
): TransactionInstruction {
561582
const dataLayout = BufferLayout.struct([
562583
BufferLayout.u8('instruction'),
563-
Layout.uint64('amount'),
584+
Layout.uint64('poolTokenAmount'),
585+
Layout.uint64('minimumTokenA'),
586+
Layout.uint64('minimumTokenB'),
564587
]);
565588

566589
const data = Buffer.alloc(dataLayout.span);
567590
dataLayout.encode(
568591
{
569592
instruction: 3, // Withdraw instruction
570-
amount: new Numberu64(amount).toBuffer(),
593+
poolTokenAmount: new Numberu64(poolTokenAmount).toBuffer(),
594+
minimumTokenA: new Numberu64(minimumTokenA).toBuffer(),
595+
minimumTokenB: new Numberu64(minimumTokenB).toBuffer(),
571596
},
572597
data,
573598
);

token-swap/js/module.d.ts

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -71,14 +71,16 @@ declare module '@solana/spl-token-swap' {
7171
): Promise<TokenSwap>;
7272

7373
getInfo(): Promise<TokenSwapInfo>;
74+
7475
swap(
7576
authority: PublicKey,
7677
source: PublicKey,
7778
swapSource: PublicKey,
7879
swapDestination: PublicKey,
7980
destination: PublicKey,
8081
tokenProgramId: PublicKey,
81-
amount: number | Numberu64,
82+
amountIn: number | Numberu64,
83+
minimumAmountOut: number | Numberu64,
8284
): Promise<TransactionSignature>;
8385

8486
static swapInstruction(
@@ -90,7 +92,8 @@ declare module '@solana/spl-token-swap' {
9092
destination: PublicKey,
9193
swapProgramId: PublicKey,
9294
tokenProgramId: PublicKey,
93-
amount: number | Numberu64,
95+
amountIn: number | Numberu64,
96+
minimumAmountOut: number | Numberu64,
9497
): TransactionInstruction;
9598

9699
deposit(
@@ -102,7 +105,9 @@ declare module '@solana/spl-token-swap' {
102105
poolToken: PublicKey,
103106
poolAccount: PublicKey,
104107
tokenProgramId: PublicKey,
105-
amount: number | Numberu64,
108+
poolTokenAmount: number | Numberu64,
109+
maximumTokenA: number | Numberu64,
110+
maximumTokenB: number | Numberu64,
106111
): Promise<TransactionSignature>;
107112

108113
static depositInstruction(
@@ -116,7 +121,9 @@ declare module '@solana/spl-token-swap' {
116121
poolAccount: PublicKey,
117122
swapProgramId: PublicKey,
118123
tokenProgramId: PublicKey,
119-
amount: number | Numberu64,
124+
poolTokenAmount: number | Numberu64,
125+
maximumTokenA: number | Numberu64,
126+
maximumTokenB: number | Numberu64,
120127
): TransactionInstruction;
121128

122129
withdraw(
@@ -128,7 +135,9 @@ declare module '@solana/spl-token-swap' {
128135
userAccountA: PublicKey,
129136
userAccountB: PublicKey,
130137
tokenProgramId: PublicKey,
131-
amount: number | Numberu64,
138+
poolTokenAmount: number | Numberu64,
139+
minimumTokenA: number | Numberu64,
140+
minimumTokenB: number | Numberu64,
132141
): Promise<TransactionSignature>;
133142

134143
static withdrawInstruction(
@@ -142,7 +151,9 @@ declare module '@solana/spl-token-swap' {
142151
userAccountB: PublicKey,
143152
swapProgramId: PublicKey,
144153
tokenProgramId: PublicKey,
145-
amount: number | Numberu64,
154+
poolTokenAmount: number | Numberu64,
155+
minimumTokenA: number | Numberu64,
156+
minimumTokenB: number | Numberu64,
146157
): TransactionInstruction;
147158
}
148159
}

token-swap/js/module.flow.js

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,8 @@ declare module '@solana/spl-token-swap' {
7575
swapDestination: PublicKey,
7676
destination: PublicKey,
7777
tokenProgramId: PublicKey,
78-
amount: number | Numberu64,
78+
amountIn: number | Numberu64,
79+
minimumAmountOut: number | Numberu64,
7980
): Promise<TransactionSignature>;
8081

8182
static swapInstruction(
@@ -87,7 +88,8 @@ declare module '@solana/spl-token-swap' {
8788
destination: PublicKey,
8889
swapProgramId: PublicKey,
8990
tokenProgramId: PublicKey,
90-
amount: number | Numberu64,
91+
amountIn: number | Numberu64,
92+
minimumAmountOut: number | Numberu64,
9193
): TransactionInstruction;
9294

9395
deposit(
@@ -99,7 +101,9 @@ declare module '@solana/spl-token-swap' {
99101
poolToken: PublicKey,
100102
poolAccount: PublicKey,
101103
tokenProgramId: PublicKey,
102-
amount: number | Numberu64,
104+
poolTokenAmount: number | Numberu64,
105+
maximumTokenA: number | Numberu64,
106+
maximumTokenB: number | Numberu64,
103107
): Promise<TransactionSignature>;
104108

105109
static depositInstruction(
@@ -113,7 +117,9 @@ declare module '@solana/spl-token-swap' {
113117
poolAccount: PublicKey,
114118
swapProgramId: PublicKey,
115119
tokenProgramId: PublicKey,
116-
amount: number | Numberu64,
120+
poolTokenAmount: number | Numberu64,
121+
maximumTokenA: number | Numberu64,
122+
maximumTokenB: number | Numberu64,
117123
): TransactionInstruction;
118124

119125
withdraw(
@@ -125,7 +131,9 @@ declare module '@solana/spl-token-swap' {
125131
userAccountA: PublicKey,
126132
userAccountB: PublicKey,
127133
tokenProgramId: PublicKey,
128-
amount: number | Numberu64,
134+
poolTokenAmount: number | Numberu64,
135+
minimumTokenA: number | Numberu64,
136+
minimumTokenB: number | Numberu64,
129137
): Promise<TransactionSignature>;
130138

131139
static withdrawInstruction(
@@ -139,7 +147,9 @@ declare module '@solana/spl-token-swap' {
139147
userAccountB: PublicKey,
140148
swapProgramId: PublicKey,
141149
tokenProgramId: PublicKey,
142-
amount: number | Numberu64,
150+
poolTokenAmount: number | Numberu64,
151+
minimumTokenA: number | Numberu64,
152+
minimumTokenB: number | Numberu64,
143153
): TransactionInstruction;
144154
}
145155
}

token-swap/program/src/error.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ pub enum SwapError {
5555
/// Swap input token accounts have the same mint
5656
#[error("Swap input token accounts have the same mint")]
5757
RepeatedMint,
58+
/// Swap instruction exceeds desired slippage limit
59+
#[error("Swap instruction exceeds desired slippage limit")]
60+
ExceededSlippage,
5861
}
5962
impl From<SwapError> for ProgramError {
6063
fn from(e: SwapError) -> Self {

0 commit comments

Comments
 (0)