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

Commit 7190672

Browse files
authored
token-swap: Add instructions to deposit / withdraw one token (#937)
* Add instructions to deposit / withdraw one token * Run cargo fmt * Fix clippy issues * Add JS interface * Add tests for new instructions * Run prettier * Rename deposit and withdraw * Rename withdraw -> withdraw all in program * Rename single token instructions
1 parent 020b13d commit 7190672

9 files changed

Lines changed: 2389 additions & 141 deletions

File tree

token-swap/js/cli/main.js

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,10 @@ import {
99
createAccountAndSwapAtomic,
1010
createTokenSwap,
1111
swap,
12-
deposit,
13-
withdraw,
12+
depositAllTokenTypes,
13+
withdrawAllTokenTypes,
14+
depositSingleTokenTypeExactAmountIn,
15+
withdrawSingleTokenTypeExactAmountOut,
1416
} from './token-swap-test';
1517

1618
async function main() {
@@ -19,14 +21,18 @@ async function main() {
1921
await loadPrograms();
2022
console.log('Run test: createTokenSwap');
2123
await createTokenSwap();
22-
console.log('Run test: deposit');
23-
await deposit();
24-
console.log('Run test: withdraw');
25-
await withdraw();
24+
console.log('Run test: deposit all token types');
25+
await depositAllTokenTypes();
26+
console.log('Run test: withdraw all token types');
27+
await withdrawAllTokenTypes();
2628
console.log('Run test: swap');
2729
await swap();
2830
console.log('Run test: create account, approve, swap all at once');
2931
await createAccountAndSwapAtomic();
32+
console.log('Run test: deposit one exact amount in');
33+
await depositSingleTokenTypeExactAmountIn();
34+
console.log('Run test: withrdaw one exact amount out');
35+
await withdrawSingleTokenTypeExactAmountOut();
3036
console.log('Success\n');
3137
}
3238

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

Lines changed: 178 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -287,13 +287,19 @@ export async function createTokenSwap(): Promise<void> {
287287
assert(CURVE_TYPE == fetchedTokenSwap.curveType);
288288
}
289289

290-
export async function deposit(): Promise<void> {
290+
export async function depositAllTokenTypes(): Promise<void> {
291291
const poolMintInfo = await tokenPool.getMintInfo();
292292
const supply = poolMintInfo.supply.toNumber();
293293
const swapTokenA = await mintA.getAccountInfo(tokenAccountA);
294-
const tokenA = Math.floor((swapTokenA.amount.toNumber() * POOL_TOKEN_AMOUNT) / (supply + POOL_TOKEN_AMOUNT));
294+
const tokenA = Math.floor(
295+
(swapTokenA.amount.toNumber() * POOL_TOKEN_AMOUNT) /
296+
(supply + POOL_TOKEN_AMOUNT),
297+
);
295298
const swapTokenB = await mintB.getAccountInfo(tokenAccountB);
296-
const tokenB = Math.floor((swapTokenB.amount.toNumber() * POOL_TOKEN_AMOUNT) / (supply + POOL_TOKEN_AMOUNT));
299+
const tokenB = Math.floor(
300+
(swapTokenB.amount.toNumber() * POOL_TOKEN_AMOUNT) /
301+
(supply + POOL_TOKEN_AMOUNT),
302+
);
297303

298304
console.log('Creating depositor token a account');
299305
const userAccountA = await mintA.createAccount(owner.publicKey);
@@ -307,7 +313,7 @@ export async function deposit(): Promise<void> {
307313
const newAccountPool = await tokenPool.createAccount(owner.publicKey);
308314

309315
console.log('Depositing into swap');
310-
await tokenSwap.deposit(
316+
await tokenSwap.depositAllTokenTypes(
311317
userAccountA,
312318
userAccountB,
313319
newAccountPool,
@@ -331,7 +337,7 @@ export async function deposit(): Promise<void> {
331337
assert(info.amount.toNumber() == POOL_TOKEN_AMOUNT);
332338
}
333339

334-
export async function withdraw(): Promise<void> {
340+
export async function withdrawAllTokenTypes(): Promise<void> {
335341
const poolMintInfo = await tokenPool.getMintInfo();
336342
const supply = poolMintInfo.supply.toNumber();
337343
let swapTokenA = await mintA.getAccountInfo(tokenAccountA);
@@ -366,7 +372,7 @@ export async function withdraw(): Promise<void> {
366372
);
367373

368374
console.log('Withdrawing pool tokens for A and B tokens');
369-
await tokenSwap.withdraw(
375+
await tokenSwap.withdrawAllTokenTypes(
370376
userAccountA,
371377
userAccountB,
372378
tokenAccountPool,
@@ -463,6 +469,12 @@ export async function createAccountAndSwapAtomic(): Promise<void> {
463469
owner,
464470
newAccount,
465471
);
472+
473+
let info;
474+
info = await mintA.getAccountInfo(tokenAccountA);
475+
currentSwapTokenA = info.amount.toNumber();
476+
info = await mintB.getAccountInfo(tokenAccountB);
477+
currentSwapTokenB = info.amount.toNumber();
466478
}
467479

468480
export async function swap(): Promise<void> {
@@ -515,3 +527,163 @@ export async function swap(): Promise<void> {
515527
assert(info.amount.toNumber() == HOST_SWAP_FEE);
516528
}
517529
}
530+
531+
function tradingTokensToPoolTokens(
532+
sourceAmount: number,
533+
swapSourceAmount: number,
534+
poolAmount: number,
535+
): number {
536+
const tradingFee =
537+
(sourceAmount / 2) * (TRADING_FEE_NUMERATOR / TRADING_FEE_DENOMINATOR);
538+
const sourceAmountPostFee = sourceAmount - tradingFee;
539+
const root = Math.sqrt(sourceAmountPostFee / swapSourceAmount + 1);
540+
return Math.floor(poolAmount * (root - 1));
541+
}
542+
543+
export async function depositSingleTokenTypeExactAmountIn(): Promise<void> {
544+
// Pool token amount to deposit on one side
545+
const depositAmount = 10000;
546+
547+
const poolMintInfo = await tokenPool.getMintInfo();
548+
const supply = poolMintInfo.supply.toNumber();
549+
const swapTokenA = await mintA.getAccountInfo(tokenAccountA);
550+
const poolTokenA = tradingTokensToPoolTokens(
551+
depositAmount,
552+
swapTokenA.amount.toNumber(),
553+
supply,
554+
);
555+
const swapTokenB = await mintB.getAccountInfo(tokenAccountB);
556+
const poolTokenB = tradingTokensToPoolTokens(
557+
depositAmount,
558+
swapTokenB.amount.toNumber(),
559+
supply,
560+
);
561+
562+
console.log('Creating depositor token a account');
563+
const userAccountA = await mintA.createAccount(owner.publicKey);
564+
await mintA.mintTo(userAccountA, owner, [], depositAmount);
565+
await mintA.approve(userAccountA, authority, owner, [], depositAmount);
566+
console.log('Creating depositor token b account');
567+
const userAccountB = await mintB.createAccount(owner.publicKey);
568+
await mintB.mintTo(userAccountB, owner, [], depositAmount);
569+
await mintB.approve(userAccountB, authority, owner, [], depositAmount);
570+
console.log('Creating depositor pool token account');
571+
const newAccountPool = await tokenPool.createAccount(owner.publicKey);
572+
573+
console.log('Depositing token A into swap');
574+
await tokenSwap.depositSingleTokenTypeExactAmountIn(
575+
userAccountA,
576+
newAccountPool,
577+
depositAmount,
578+
poolTokenA,
579+
);
580+
581+
let info;
582+
info = await mintA.getAccountInfo(userAccountA);
583+
assert(info.amount.toNumber() == 0);
584+
info = await mintA.getAccountInfo(tokenAccountA);
585+
assert(info.amount.toNumber() == currentSwapTokenA + depositAmount);
586+
currentSwapTokenA += depositAmount;
587+
588+
console.log('Depositing token B into swap');
589+
await tokenSwap.depositSingleTokenTypeExactAmountIn(
590+
userAccountB,
591+
newAccountPool,
592+
depositAmount,
593+
poolTokenB,
594+
);
595+
596+
info = await mintB.getAccountInfo(userAccountB);
597+
assert(info.amount.toNumber() == 0);
598+
info = await mintB.getAccountInfo(tokenAccountB);
599+
assert(info.amount.toNumber() == currentSwapTokenB + depositAmount);
600+
currentSwapTokenB += depositAmount;
601+
info = await tokenPool.getAccountInfo(newAccountPool);
602+
assert(info.amount.toNumber() >= poolTokenA + poolTokenB);
603+
}
604+
605+
export async function withdrawSingleTokenTypeExactAmountOut(): Promise<void> {
606+
// Pool token amount to withdraw on one side
607+
const withdrawAmount = 50000;
608+
const roundingAmount = 1.0001; // make math a little easier
609+
610+
const poolMintInfo = await tokenPool.getMintInfo();
611+
const supply = poolMintInfo.supply.toNumber();
612+
613+
const swapTokenA = await mintA.getAccountInfo(tokenAccountA);
614+
const swapTokenAPost = swapTokenA.amount.toNumber() - withdrawAmount;
615+
const poolTokenA = tradingTokensToPoolTokens(
616+
withdrawAmount,
617+
swapTokenAPost,
618+
supply,
619+
);
620+
let adjustedPoolTokenA = poolTokenA * roundingAmount;
621+
if (OWNER_WITHDRAW_FEE_NUMERATOR !== 0) {
622+
adjustedPoolTokenA *=
623+
1 + OWNER_WITHDRAW_FEE_NUMERATOR / OWNER_WITHDRAW_FEE_DENOMINATOR;
624+
}
625+
626+
const swapTokenB = await mintB.getAccountInfo(tokenAccountB);
627+
const swapTokenBPost = swapTokenB.amount.toNumber() - withdrawAmount;
628+
const poolTokenB = tradingTokensToPoolTokens(
629+
withdrawAmount,
630+
swapTokenBPost,
631+
supply,
632+
);
633+
let adjustedPoolTokenB = poolTokenB * roundingAmount;
634+
if (OWNER_WITHDRAW_FEE_NUMERATOR !== 0) {
635+
adjustedPoolTokenB *=
636+
1 + OWNER_WITHDRAW_FEE_NUMERATOR / OWNER_WITHDRAW_FEE_DENOMINATOR;
637+
}
638+
639+
console.log('Creating withdraw token a account');
640+
const userAccountA = await mintA.createAccount(owner.publicKey);
641+
console.log('Creating withdraw token b account');
642+
const userAccountB = await mintB.createAccount(owner.publicKey);
643+
console.log('Creating withdraw pool token account');
644+
const poolAccount = await tokenPool.getAccountInfo(tokenAccountPool);
645+
const poolTokenAmount = poolAccount.amount.toNumber();
646+
await tokenPool.approve(
647+
tokenAccountPool,
648+
authority,
649+
owner,
650+
[],
651+
adjustedPoolTokenA + adjustedPoolTokenB,
652+
);
653+
654+
console.log('Withdrawing token A only');
655+
await tokenSwap.withdrawSingleTokenTypeExactAmountOut(
656+
userAccountA,
657+
tokenAccountPool,
658+
withdrawAmount,
659+
adjustedPoolTokenA,
660+
);
661+
662+
let info;
663+
info = await mintA.getAccountInfo(userAccountA);
664+
assert(info.amount.toNumber() == withdrawAmount);
665+
info = await mintA.getAccountInfo(tokenAccountA);
666+
assert(info.amount.toNumber() == currentSwapTokenA - withdrawAmount);
667+
currentSwapTokenA += withdrawAmount;
668+
info = await tokenPool.getAccountInfo(tokenAccountPool);
669+
assert(info.amount.toNumber() >= poolTokenAmount - adjustedPoolTokenA);
670+
671+
console.log('Withdrawing token B only');
672+
await tokenSwap.withdrawSingleTokenTypeExactAmountOut(
673+
userAccountB,
674+
tokenAccountPool,
675+
withdrawAmount,
676+
adjustedPoolTokenB,
677+
);
678+
679+
info = await mintB.getAccountInfo(userAccountB);
680+
assert(info.amount.toNumber() == withdrawAmount);
681+
info = await mintB.getAccountInfo(tokenAccountB);
682+
assert(info.amount.toNumber() == currentSwapTokenB - withdrawAmount);
683+
currentSwapTokenB += withdrawAmount;
684+
info = await tokenPool.getAccountInfo(tokenAccountPool);
685+
assert(
686+
info.amount.toNumber() >=
687+
poolTokenAmount - adjustedPoolTokenA - adjustedPoolTokenB,
688+
);
689+
}

0 commit comments

Comments
 (0)