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
This commit is contained in:
parent
020b13d80c
commit
7190672a0f
|
@ -9,8 +9,10 @@ import {
|
|||
createAccountAndSwapAtomic,
|
||||
createTokenSwap,
|
||||
swap,
|
||||
deposit,
|
||||
withdraw,
|
||||
depositAllTokenTypes,
|
||||
withdrawAllTokenTypes,
|
||||
depositSingleTokenTypeExactAmountIn,
|
||||
withdrawSingleTokenTypeExactAmountOut,
|
||||
} from './token-swap-test';
|
||||
|
||||
async function main() {
|
||||
|
@ -19,14 +21,18 @@ async function main() {
|
|||
await loadPrograms();
|
||||
console.log('Run test: createTokenSwap');
|
||||
await createTokenSwap();
|
||||
console.log('Run test: deposit');
|
||||
await deposit();
|
||||
console.log('Run test: withdraw');
|
||||
await withdraw();
|
||||
console.log('Run test: deposit all token types');
|
||||
await depositAllTokenTypes();
|
||||
console.log('Run test: withdraw all token types');
|
||||
await withdrawAllTokenTypes();
|
||||
console.log('Run test: swap');
|
||||
await swap();
|
||||
console.log('Run test: create account, approve, swap all at once');
|
||||
await createAccountAndSwapAtomic();
|
||||
console.log('Run test: deposit one exact amount in');
|
||||
await depositSingleTokenTypeExactAmountIn();
|
||||
console.log('Run test: withrdaw one exact amount out');
|
||||
await withdrawSingleTokenTypeExactAmountOut();
|
||||
console.log('Success\n');
|
||||
}
|
||||
|
||||
|
|
|
@ -287,13 +287,19 @@ export async function createTokenSwap(): Promise<void> {
|
|||
assert(CURVE_TYPE == fetchedTokenSwap.curveType);
|
||||
}
|
||||
|
||||
export async function deposit(): Promise<void> {
|
||||
export async function depositAllTokenTypes(): Promise<void> {
|
||||
const poolMintInfo = await tokenPool.getMintInfo();
|
||||
const supply = poolMintInfo.supply.toNumber();
|
||||
const swapTokenA = await mintA.getAccountInfo(tokenAccountA);
|
||||
const tokenA = Math.floor((swapTokenA.amount.toNumber() * POOL_TOKEN_AMOUNT) / (supply + POOL_TOKEN_AMOUNT));
|
||||
const tokenA = Math.floor(
|
||||
(swapTokenA.amount.toNumber() * POOL_TOKEN_AMOUNT) /
|
||||
(supply + POOL_TOKEN_AMOUNT),
|
||||
);
|
||||
const swapTokenB = await mintB.getAccountInfo(tokenAccountB);
|
||||
const tokenB = Math.floor((swapTokenB.amount.toNumber() * POOL_TOKEN_AMOUNT) / (supply + POOL_TOKEN_AMOUNT));
|
||||
const tokenB = Math.floor(
|
||||
(swapTokenB.amount.toNumber() * POOL_TOKEN_AMOUNT) /
|
||||
(supply + POOL_TOKEN_AMOUNT),
|
||||
);
|
||||
|
||||
console.log('Creating depositor token a account');
|
||||
const userAccountA = await mintA.createAccount(owner.publicKey);
|
||||
|
@ -307,7 +313,7 @@ export async function deposit(): Promise<void> {
|
|||
const newAccountPool = await tokenPool.createAccount(owner.publicKey);
|
||||
|
||||
console.log('Depositing into swap');
|
||||
await tokenSwap.deposit(
|
||||
await tokenSwap.depositAllTokenTypes(
|
||||
userAccountA,
|
||||
userAccountB,
|
||||
newAccountPool,
|
||||
|
@ -331,7 +337,7 @@ export async function deposit(): Promise<void> {
|
|||
assert(info.amount.toNumber() == POOL_TOKEN_AMOUNT);
|
||||
}
|
||||
|
||||
export async function withdraw(): Promise<void> {
|
||||
export async function withdrawAllTokenTypes(): Promise<void> {
|
||||
const poolMintInfo = await tokenPool.getMintInfo();
|
||||
const supply = poolMintInfo.supply.toNumber();
|
||||
let swapTokenA = await mintA.getAccountInfo(tokenAccountA);
|
||||
|
@ -366,7 +372,7 @@ export async function withdraw(): Promise<void> {
|
|||
);
|
||||
|
||||
console.log('Withdrawing pool tokens for A and B tokens');
|
||||
await tokenSwap.withdraw(
|
||||
await tokenSwap.withdrawAllTokenTypes(
|
||||
userAccountA,
|
||||
userAccountB,
|
||||
tokenAccountPool,
|
||||
|
@ -463,6 +469,12 @@ export async function createAccountAndSwapAtomic(): Promise<void> {
|
|||
owner,
|
||||
newAccount,
|
||||
);
|
||||
|
||||
let info;
|
||||
info = await mintA.getAccountInfo(tokenAccountA);
|
||||
currentSwapTokenA = info.amount.toNumber();
|
||||
info = await mintB.getAccountInfo(tokenAccountB);
|
||||
currentSwapTokenB = info.amount.toNumber();
|
||||
}
|
||||
|
||||
export async function swap(): Promise<void> {
|
||||
|
@ -515,3 +527,163 @@ export async function swap(): Promise<void> {
|
|||
assert(info.amount.toNumber() == HOST_SWAP_FEE);
|
||||
}
|
||||
}
|
||||
|
||||
function tradingTokensToPoolTokens(
|
||||
sourceAmount: number,
|
||||
swapSourceAmount: number,
|
||||
poolAmount: number,
|
||||
): number {
|
||||
const tradingFee =
|
||||
(sourceAmount / 2) * (TRADING_FEE_NUMERATOR / TRADING_FEE_DENOMINATOR);
|
||||
const sourceAmountPostFee = sourceAmount - tradingFee;
|
||||
const root = Math.sqrt(sourceAmountPostFee / swapSourceAmount + 1);
|
||||
return Math.floor(poolAmount * (root - 1));
|
||||
}
|
||||
|
||||
export async function depositSingleTokenTypeExactAmountIn(): Promise<void> {
|
||||
// Pool token amount to deposit on one side
|
||||
const depositAmount = 10000;
|
||||
|
||||
const poolMintInfo = await tokenPool.getMintInfo();
|
||||
const supply = poolMintInfo.supply.toNumber();
|
||||
const swapTokenA = await mintA.getAccountInfo(tokenAccountA);
|
||||
const poolTokenA = tradingTokensToPoolTokens(
|
||||
depositAmount,
|
||||
swapTokenA.amount.toNumber(),
|
||||
supply,
|
||||
);
|
||||
const swapTokenB = await mintB.getAccountInfo(tokenAccountB);
|
||||
const poolTokenB = tradingTokensToPoolTokens(
|
||||
depositAmount,
|
||||
swapTokenB.amount.toNumber(),
|
||||
supply,
|
||||
);
|
||||
|
||||
console.log('Creating depositor token a account');
|
||||
const userAccountA = await mintA.createAccount(owner.publicKey);
|
||||
await mintA.mintTo(userAccountA, owner, [], depositAmount);
|
||||
await mintA.approve(userAccountA, authority, owner, [], depositAmount);
|
||||
console.log('Creating depositor token b account');
|
||||
const userAccountB = await mintB.createAccount(owner.publicKey);
|
||||
await mintB.mintTo(userAccountB, owner, [], depositAmount);
|
||||
await mintB.approve(userAccountB, authority, owner, [], depositAmount);
|
||||
console.log('Creating depositor pool token account');
|
||||
const newAccountPool = await tokenPool.createAccount(owner.publicKey);
|
||||
|
||||
console.log('Depositing token A into swap');
|
||||
await tokenSwap.depositSingleTokenTypeExactAmountIn(
|
||||
userAccountA,
|
||||
newAccountPool,
|
||||
depositAmount,
|
||||
poolTokenA,
|
||||
);
|
||||
|
||||
let info;
|
||||
info = await mintA.getAccountInfo(userAccountA);
|
||||
assert(info.amount.toNumber() == 0);
|
||||
info = await mintA.getAccountInfo(tokenAccountA);
|
||||
assert(info.amount.toNumber() == currentSwapTokenA + depositAmount);
|
||||
currentSwapTokenA += depositAmount;
|
||||
|
||||
console.log('Depositing token B into swap');
|
||||
await tokenSwap.depositSingleTokenTypeExactAmountIn(
|
||||
userAccountB,
|
||||
newAccountPool,
|
||||
depositAmount,
|
||||
poolTokenB,
|
||||
);
|
||||
|
||||
info = await mintB.getAccountInfo(userAccountB);
|
||||
assert(info.amount.toNumber() == 0);
|
||||
info = await mintB.getAccountInfo(tokenAccountB);
|
||||
assert(info.amount.toNumber() == currentSwapTokenB + depositAmount);
|
||||
currentSwapTokenB += depositAmount;
|
||||
info = await tokenPool.getAccountInfo(newAccountPool);
|
||||
assert(info.amount.toNumber() >= poolTokenA + poolTokenB);
|
||||
}
|
||||
|
||||
export async function withdrawSingleTokenTypeExactAmountOut(): Promise<void> {
|
||||
// Pool token amount to withdraw on one side
|
||||
const withdrawAmount = 50000;
|
||||
const roundingAmount = 1.0001; // make math a little easier
|
||||
|
||||
const poolMintInfo = await tokenPool.getMintInfo();
|
||||
const supply = poolMintInfo.supply.toNumber();
|
||||
|
||||
const swapTokenA = await mintA.getAccountInfo(tokenAccountA);
|
||||
const swapTokenAPost = swapTokenA.amount.toNumber() - withdrawAmount;
|
||||
const poolTokenA = tradingTokensToPoolTokens(
|
||||
withdrawAmount,
|
||||
swapTokenAPost,
|
||||
supply,
|
||||
);
|
||||
let adjustedPoolTokenA = poolTokenA * roundingAmount;
|
||||
if (OWNER_WITHDRAW_FEE_NUMERATOR !== 0) {
|
||||
adjustedPoolTokenA *=
|
||||
1 + OWNER_WITHDRAW_FEE_NUMERATOR / OWNER_WITHDRAW_FEE_DENOMINATOR;
|
||||
}
|
||||
|
||||
const swapTokenB = await mintB.getAccountInfo(tokenAccountB);
|
||||
const swapTokenBPost = swapTokenB.amount.toNumber() - withdrawAmount;
|
||||
const poolTokenB = tradingTokensToPoolTokens(
|
||||
withdrawAmount,
|
||||
swapTokenBPost,
|
||||
supply,
|
||||
);
|
||||
let adjustedPoolTokenB = poolTokenB * roundingAmount;
|
||||
if (OWNER_WITHDRAW_FEE_NUMERATOR !== 0) {
|
||||
adjustedPoolTokenB *=
|
||||
1 + OWNER_WITHDRAW_FEE_NUMERATOR / OWNER_WITHDRAW_FEE_DENOMINATOR;
|
||||
}
|
||||
|
||||
console.log('Creating withdraw token a account');
|
||||
const userAccountA = await mintA.createAccount(owner.publicKey);
|
||||
console.log('Creating withdraw token b account');
|
||||
const userAccountB = await mintB.createAccount(owner.publicKey);
|
||||
console.log('Creating withdraw pool token account');
|
||||
const poolAccount = await tokenPool.getAccountInfo(tokenAccountPool);
|
||||
const poolTokenAmount = poolAccount.amount.toNumber();
|
||||
await tokenPool.approve(
|
||||
tokenAccountPool,
|
||||
authority,
|
||||
owner,
|
||||
[],
|
||||
adjustedPoolTokenA + adjustedPoolTokenB,
|
||||
);
|
||||
|
||||
console.log('Withdrawing token A only');
|
||||
await tokenSwap.withdrawSingleTokenTypeExactAmountOut(
|
||||
userAccountA,
|
||||
tokenAccountPool,
|
||||
withdrawAmount,
|
||||
adjustedPoolTokenA,
|
||||
);
|
||||
|
||||
let info;
|
||||
info = await mintA.getAccountInfo(userAccountA);
|
||||
assert(info.amount.toNumber() == withdrawAmount);
|
||||
info = await mintA.getAccountInfo(tokenAccountA);
|
||||
assert(info.amount.toNumber() == currentSwapTokenA - withdrawAmount);
|
||||
currentSwapTokenA += withdrawAmount;
|
||||
info = await tokenPool.getAccountInfo(tokenAccountPool);
|
||||
assert(info.amount.toNumber() >= poolTokenAmount - adjustedPoolTokenA);
|
||||
|
||||
console.log('Withdrawing token B only');
|
||||
await tokenSwap.withdrawSingleTokenTypeExactAmountOut(
|
||||
userAccountB,
|
||||
tokenAccountPool,
|
||||
withdrawAmount,
|
||||
adjustedPoolTokenB,
|
||||
);
|
||||
|
||||
info = await mintB.getAccountInfo(userAccountB);
|
||||
assert(info.amount.toNumber() == withdrawAmount);
|
||||
info = await mintB.getAccountInfo(tokenAccountB);
|
||||
assert(info.amount.toNumber() == currentSwapTokenB - withdrawAmount);
|
||||
currentSwapTokenB += withdrawAmount;
|
||||
info = await tokenPool.getAccountInfo(tokenAccountPool);
|
||||
assert(
|
||||
info.amount.toNumber() >=
|
||||
poolTokenAmount - adjustedPoolTokenA - adjustedPoolTokenB,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -638,7 +638,7 @@ export class TokenSwap {
|
|||
* @param maximumTokenA The maximum amount of token A to deposit
|
||||
* @param maximumTokenB The maximum amount of token B to deposit
|
||||
*/
|
||||
async deposit(
|
||||
async depositAllTokenTypes(
|
||||
userAccountA: PublicKey,
|
||||
userAccountB: PublicKey,
|
||||
poolAccount: PublicKey,
|
||||
|
@ -647,10 +647,10 @@ export class TokenSwap {
|
|||
maximumTokenB: number | Numberu64,
|
||||
): Promise<TransactionSignature> {
|
||||
return await sendAndConfirmTransaction(
|
||||
'deposit',
|
||||
'depositAllTokenTypes',
|
||||
this.connection,
|
||||
new Transaction().add(
|
||||
TokenSwap.depositInstruction(
|
||||
TokenSwap.depositAllTokenTypesInstruction(
|
||||
this.tokenSwap,
|
||||
this.authority,
|
||||
userAccountA,
|
||||
|
@ -670,7 +670,7 @@ export class TokenSwap {
|
|||
);
|
||||
}
|
||||
|
||||
static depositInstruction(
|
||||
static depositAllTokenTypesInstruction(
|
||||
tokenSwap: PublicKey,
|
||||
authority: PublicKey,
|
||||
sourceA: PublicKey,
|
||||
|
@ -731,7 +731,7 @@ export class TokenSwap {
|
|||
* @param minimumTokenA The minimum amount of token A to withdraw
|
||||
* @param minimumTokenB The minimum amount of token B to withdraw
|
||||
*/
|
||||
async withdraw(
|
||||
async withdrawAllTokenTypes(
|
||||
userAccountA: PublicKey,
|
||||
userAccountB: PublicKey,
|
||||
poolAccount: PublicKey,
|
||||
|
@ -743,7 +743,7 @@ export class TokenSwap {
|
|||
'withdraw',
|
||||
this.connection,
|
||||
new Transaction().add(
|
||||
TokenSwap.withdrawInstruction(
|
||||
TokenSwap.withdrawAllTokenTypesInstruction(
|
||||
this.tokenSwap,
|
||||
this.authority,
|
||||
this.poolToken,
|
||||
|
@ -764,7 +764,7 @@ export class TokenSwap {
|
|||
);
|
||||
}
|
||||
|
||||
static withdrawInstruction(
|
||||
static withdrawAllTokenTypesInstruction(
|
||||
tokenSwap: PublicKey,
|
||||
authority: PublicKey,
|
||||
poolMint: PublicKey,
|
||||
|
@ -816,4 +816,176 @@ export class TokenSwap {
|
|||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Deposit one side of tokens into the pool
|
||||
* @param userAccount User account to deposit token A or B
|
||||
* @param poolAccount User account to receive pool tokens
|
||||
* @param sourceTokenAmount The amount of token A or B to deposit
|
||||
* @param minimumPoolTokenAmount Minimum amount of pool tokens to mint
|
||||
*/
|
||||
async depositSingleTokenTypeExactAmountIn(
|
||||
userAccount: PublicKey,
|
||||
poolAccount: PublicKey,
|
||||
sourceTokenAmount: number | Numberu64,
|
||||
minimumPoolTokenAmount: number | Numberu64,
|
||||
): Promise<TransactionSignature> {
|
||||
return await sendAndConfirmTransaction(
|
||||
'depositSingleTokenTypeExactAmountIn',
|
||||
this.connection,
|
||||
new Transaction().add(
|
||||
TokenSwap.depositSingleTokenTypeExactAmountInInstruction(
|
||||
this.tokenSwap,
|
||||
this.authority,
|
||||
userAccount,
|
||||
this.tokenAccountA,
|
||||
this.tokenAccountB,
|
||||
this.poolToken,
|
||||
poolAccount,
|
||||
this.swapProgramId,
|
||||
this.tokenProgramId,
|
||||
sourceTokenAmount,
|
||||
minimumPoolTokenAmount,
|
||||
),
|
||||
),
|
||||
this.payer,
|
||||
);
|
||||
}
|
||||
|
||||
static depositSingleTokenTypeExactAmountInInstruction(
|
||||
tokenSwap: PublicKey,
|
||||
authority: PublicKey,
|
||||
source: PublicKey,
|
||||
intoA: PublicKey,
|
||||
intoB: PublicKey,
|
||||
poolToken: PublicKey,
|
||||
poolAccount: PublicKey,
|
||||
swapProgramId: PublicKey,
|
||||
tokenProgramId: PublicKey,
|
||||
sourceTokenAmount: number | Numberu64,
|
||||
minimumPoolTokenAmount: number | Numberu64,
|
||||
): TransactionInstruction {
|
||||
const dataLayout = BufferLayout.struct([
|
||||
BufferLayout.u8('instruction'),
|
||||
Layout.uint64('sourceTokenAmount'),
|
||||
Layout.uint64('minimumPoolTokenAmount'),
|
||||
]);
|
||||
|
||||
const data = Buffer.alloc(dataLayout.span);
|
||||
dataLayout.encode(
|
||||
{
|
||||
instruction: 4, // depositSingleTokenTypeExactAmountIn instruction
|
||||
sourceTokenAmount: new Numberu64(sourceTokenAmount).toBuffer(),
|
||||
minimumPoolTokenAmount: new Numberu64(
|
||||
minimumPoolTokenAmount,
|
||||
).toBuffer(),
|
||||
},
|
||||
data,
|
||||
);
|
||||
|
||||
const keys = [
|
||||
{pubkey: tokenSwap, isSigner: false, isWritable: false},
|
||||
{pubkey: authority, isSigner: false, isWritable: false},
|
||||
{pubkey: source, isSigner: false, isWritable: true},
|
||||
{pubkey: intoA, isSigner: false, isWritable: true},
|
||||
{pubkey: intoB, isSigner: false, isWritable: true},
|
||||
{pubkey: poolToken, isSigner: false, isWritable: true},
|
||||
{pubkey: poolAccount, isSigner: false, isWritable: true},
|
||||
{pubkey: tokenProgramId, isSigner: false, isWritable: false},
|
||||
];
|
||||
return new TransactionInstruction({
|
||||
keys,
|
||||
programId: swapProgramId,
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Withdraw tokens from the pool
|
||||
*
|
||||
* @param userAccount User account to receive token A or B
|
||||
* @param poolAccount User account to burn pool token
|
||||
* @param destinationTokenAmount The amount of token A or B to withdraw
|
||||
* @param maximumPoolTokenAmount Maximum amount of pool tokens to burn
|
||||
*/
|
||||
async withdrawSingleTokenTypeExactAmountOut(
|
||||
userAccount: PublicKey,
|
||||
poolAccount: PublicKey,
|
||||
destinationTokenAmount: number | Numberu64,
|
||||
maximumPoolTokenAmount: number | Numberu64,
|
||||
): Promise<TransactionSignature> {
|
||||
return await sendAndConfirmTransaction(
|
||||
'withdrawSingleTokenTypeExactAmountOut',
|
||||
this.connection,
|
||||
new Transaction().add(
|
||||
TokenSwap.withdrawSingleTokenTypeExactAmountOutInstruction(
|
||||
this.tokenSwap,
|
||||
this.authority,
|
||||
this.poolToken,
|
||||
this.feeAccount,
|
||||
poolAccount,
|
||||
this.tokenAccountA,
|
||||
this.tokenAccountB,
|
||||
userAccount,
|
||||
this.swapProgramId,
|
||||
this.tokenProgramId,
|
||||
destinationTokenAmount,
|
||||
maximumPoolTokenAmount,
|
||||
),
|
||||
),
|
||||
this.payer,
|
||||
);
|
||||
}
|
||||
|
||||
static withdrawSingleTokenTypeExactAmountOutInstruction(
|
||||
tokenSwap: PublicKey,
|
||||
authority: PublicKey,
|
||||
poolMint: PublicKey,
|
||||
feeAccount: PublicKey,
|
||||
sourcePoolAccount: PublicKey,
|
||||
fromA: PublicKey,
|
||||
fromB: PublicKey,
|
||||
userAccount: PublicKey,
|
||||
swapProgramId: PublicKey,
|
||||
tokenProgramId: PublicKey,
|
||||
destinationTokenAmount: number | Numberu64,
|
||||
maximumPoolTokenAmount: number | Numberu64,
|
||||
): TransactionInstruction {
|
||||
const dataLayout = BufferLayout.struct([
|
||||
BufferLayout.u8('instruction'),
|
||||
Layout.uint64('destinationTokenAmount'),
|
||||
Layout.uint64('maximumPoolTokenAmount'),
|
||||
]);
|
||||
|
||||
const data = Buffer.alloc(dataLayout.span);
|
||||
dataLayout.encode(
|
||||
{
|
||||
instruction: 5, // withdrawSingleTokenTypeExactAmountOut instruction
|
||||
destinationTokenAmount: new Numberu64(
|
||||
destinationTokenAmount,
|
||||
).toBuffer(),
|
||||
maximumPoolTokenAmount: new Numberu64(
|
||||
maximumPoolTokenAmount,
|
||||
).toBuffer(),
|
||||
},
|
||||
data,
|
||||
);
|
||||
|
||||
const keys = [
|
||||
{pubkey: tokenSwap, isSigner: false, isWritable: false},
|
||||
{pubkey: authority, isSigner: false, isWritable: false},
|
||||
{pubkey: poolMint, isSigner: false, isWritable: true},
|
||||
{pubkey: sourcePoolAccount, isSigner: false, isWritable: true},
|
||||
{pubkey: fromA, isSigner: false, isWritable: true},
|
||||
{pubkey: fromB, isSigner: false, isWritable: true},
|
||||
{pubkey: userAccount, isSigner: false, isWritable: true},
|
||||
{pubkey: feeAccount, isSigner: false, isWritable: true},
|
||||
{pubkey: tokenProgramId, isSigner: false, isWritable: false},
|
||||
];
|
||||
return new TransactionInstruction({
|
||||
keys,
|
||||
programId: swapProgramId,
|
||||
data,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -129,7 +129,7 @@ declare module '@solana/spl-token-swap' {
|
|||
minimumAmountOut: number | Numberu64,
|
||||
): TransactionInstruction;
|
||||
|
||||
deposit(
|
||||
depositAllTokenTypes(
|
||||
userAccountA: PublicKey,
|
||||
userAccountB: PublicKey,
|
||||
poolAccount: PublicKey,
|
||||
|
@ -138,7 +138,7 @@ declare module '@solana/spl-token-swap' {
|
|||
maximumTokenB: number | Numberu64,
|
||||
): Promise<TransactionSignature>;
|
||||
|
||||
static depositInstruction(
|
||||
static depositAllTokenTypesInstruction(
|
||||
tokenSwap: PublicKey,
|
||||
authority: PublicKey,
|
||||
sourceA: PublicKey,
|
||||
|
@ -154,7 +154,7 @@ declare module '@solana/spl-token-swap' {
|
|||
maximumTokenB: number | Numberu64,
|
||||
): TransactionInstruction;
|
||||
|
||||
withdraw(
|
||||
withdrawAllTokenTypes(
|
||||
userAccountA: PublicKey,
|
||||
userAccountB: PublicKey,
|
||||
poolTokenAmount: number | Numberu64,
|
||||
|
@ -162,7 +162,7 @@ declare module '@solana/spl-token-swap' {
|
|||
minimumTokenB: number | Numberu64,
|
||||
): Promise<TransactionSignature>;
|
||||
|
||||
static withdrawInstruction(
|
||||
static withdrawAllTokenTypesInstruction(
|
||||
tokenSwap: PublicKey,
|
||||
authority: PublicKey,
|
||||
poolMint: PublicKey,
|
||||
|
@ -178,5 +178,48 @@ declare module '@solana/spl-token-swap' {
|
|||
minimumTokenA: number | Numberu64,
|
||||
minimumTokenB: number | Numberu64,
|
||||
): TransactionInstruction;
|
||||
|
||||
depositSingleTokenTypeExactAmountIn(
|
||||
userAccount: PublicKey,
|
||||
poolAccount: PublicKey,
|
||||
sourceTokenAmount: number | Numberu64,
|
||||
minimumPoolTokenAmount: number | Numberu64,
|
||||
): Promise<TransactionSignature>;
|
||||
|
||||
static depositSingleTokenTypeExactAmountInInstruction(
|
||||
tokenSwap: PublicKey,
|
||||
authority: PublicKey,
|
||||
source: PublicKey,
|
||||
intoA: PublicKey,
|
||||
intoB: PublicKey,
|
||||
poolToken: PublicKey,
|
||||
poolAccount: PublicKey,
|
||||
swapProgramId: PublicKey,
|
||||
tokenProgramId: PublicKey,
|
||||
sourceTokenAmount: number | Numberu64,
|
||||
minimumPoolTokenAmount: number | Numberu64,
|
||||
): TransactionInstruction;
|
||||
|
||||
withdrawSingleTokenTypeExactAmountOut(
|
||||
userAccount: PublicKey,
|
||||
poolAccount: PublicKey,
|
||||
destinationTokenAmount: number | Numberu64,
|
||||
maximumPoolTokenAmount: number | Numberu64,
|
||||
): Promise<TransactionSignature>;
|
||||
|
||||
static withdrawSingleTokenTypeExactAmountOutInstruction(
|
||||
tokenSwap: PublicKey,
|
||||
authority: PublicKey,
|
||||
poolMint: PublicKey,
|
||||
feeAccount: PublicKey,
|
||||
sourcePoolAccount: PublicKey,
|
||||
fromA: PublicKey,
|
||||
fromB: PublicKey,
|
||||
userAccount: PublicKey,
|
||||
swapProgramId: PublicKey,
|
||||
tokenProgramId: PublicKey,
|
||||
destinationTokenAmount: number | Numberu64,
|
||||
maximumPoolTokenAmount: number | Numberu64,
|
||||
): TransactionInstruction;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -126,7 +126,7 @@ declare module '@solana/spl-token-swap' {
|
|||
minimumAmountOut: number | Numberu64,
|
||||
): TransactionInstruction;
|
||||
|
||||
deposit(
|
||||
depositAllTokenTypes(
|
||||
userAccountA: PublicKey,
|
||||
userAccountB: PublicKey,
|
||||
poolAccount: PublicKey,
|
||||
|
@ -135,7 +135,7 @@ declare module '@solana/spl-token-swap' {
|
|||
maximumTokenB: number | Numberu64,
|
||||
): Promise<TransactionSignature>;
|
||||
|
||||
static depositInstruction(
|
||||
static depositAllTokenTypesInstruction(
|
||||
tokenSwap: PublicKey,
|
||||
authority: PublicKey,
|
||||
sourceA: PublicKey,
|
||||
|
@ -151,7 +151,7 @@ declare module '@solana/spl-token-swap' {
|
|||
maximumTokenB: number | Numberu64,
|
||||
): TransactionInstruction;
|
||||
|
||||
withdraw(
|
||||
withdrawAllTokenTypes(
|
||||
userAccountA: PublicKey,
|
||||
userAccountB: PublicKey,
|
||||
poolAccount: PublicKey,
|
||||
|
@ -160,7 +160,7 @@ declare module '@solana/spl-token-swap' {
|
|||
minimumTokenB: number | Numberu64,
|
||||
): Promise<TransactionSignature>;
|
||||
|
||||
static withdrawInstruction(
|
||||
static withdrawAllTokenTypesInstruction(
|
||||
tokenSwap: PublicKey,
|
||||
authority: PublicKey,
|
||||
poolMint: PublicKey,
|
||||
|
@ -176,5 +176,48 @@ declare module '@solana/spl-token-swap' {
|
|||
minimumTokenA: number | Numberu64,
|
||||
minimumTokenB: number | Numberu64,
|
||||
): TransactionInstruction;
|
||||
|
||||
depositSingleTokenTypeExactAmountIn(
|
||||
userAccount: PublicKey,
|
||||
poolAccount: PublicKey,
|
||||
sourceTokenAmount: number | Numberu64,
|
||||
minimumPoolTokenAmount: number | Numberu64,
|
||||
): Promise<TransactionSignature>;
|
||||
|
||||
static depositSingleTokenTypeExactAmountInInstruction(
|
||||
tokenSwap: PublicKey,
|
||||
authority: PublicKey,
|
||||
source: PublicKey,
|
||||
intoA: PublicKey,
|
||||
intoB: PublicKey,
|
||||
poolToken: PublicKey,
|
||||
poolAccount: PublicKey,
|
||||
swapProgramId: PublicKey,
|
||||
tokenProgramId: PublicKey,
|
||||
sourceTokenAmount: number | Numberu64,
|
||||
minimumPoolTokenAmount: number | Numberu64,
|
||||
): TransactionInstruction;
|
||||
|
||||
withdrawSingleTokenTypeExactAmountOut(
|
||||
userAccount: PublicKey,
|
||||
poolAccount: PublicKey,
|
||||
destinationTokenAmount: number | Numberu64,
|
||||
maximumPoolTokenAmount: number | Numberu64,
|
||||
): Promise<TransactionSignature>;
|
||||
|
||||
static withdrawSingleTokenTypeExactAmountOutInstruction(
|
||||
tokenSwap: PublicKey,
|
||||
authority: PublicKey,
|
||||
poolMint: PublicKey,
|
||||
feeAccount: PublicKey,
|
||||
sourcePoolAccount: PublicKey,
|
||||
fromA: PublicKey,
|
||||
fromB: PublicKey,
|
||||
userAccount: PublicKey,
|
||||
swapProgramId: PublicKey,
|
||||
tokenProgramId: PublicKey,
|
||||
destinationTokenAmount: number | Numberu64,
|
||||
maximumPoolTokenAmount: number | Numberu64,
|
||||
): TransactionInstruction;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ use spl_token_swap::{
|
|||
fees::Fees,
|
||||
},
|
||||
error::SwapError,
|
||||
instruction::{Deposit, Swap, Withdraw},
|
||||
instruction::{DepositAllTokenTypes, Swap, WithdrawAllTokenTypes},
|
||||
};
|
||||
|
||||
use spl_token::error::TokenError;
|
||||
|
@ -28,17 +28,17 @@ enum FuzzInstruction {
|
|||
trade_direction: TradeDirection,
|
||||
instruction: Swap,
|
||||
},
|
||||
Deposit {
|
||||
DepositAllTokenTypes {
|
||||
token_a_id: AccountId,
|
||||
token_b_id: AccountId,
|
||||
pool_token_id: AccountId,
|
||||
instruction: Deposit,
|
||||
instruction: DepositAllTokenTypes,
|
||||
},
|
||||
Withdraw {
|
||||
WithdrawAllTokenTypes {
|
||||
token_a_id: AccountId,
|
||||
token_b_id: AccountId,
|
||||
pool_token_id: AccountId,
|
||||
instruction: Withdraw,
|
||||
instruction: WithdrawAllTokenTypes,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -206,7 +206,7 @@ fn run_fuzz_instruction(
|
|||
}
|
||||
}
|
||||
}
|
||||
FuzzInstruction::Deposit {
|
||||
FuzzInstruction::DepositAllTokenTypes {
|
||||
token_a_id,
|
||||
token_b_id,
|
||||
pool_token_id,
|
||||
|
@ -228,7 +228,7 @@ fn run_fuzz_instruction(
|
|||
instruction,
|
||||
)
|
||||
}
|
||||
FuzzInstruction::Withdraw {
|
||||
FuzzInstruction::WithdrawAllTokenTypes {
|
||||
token_a_id,
|
||||
token_b_id,
|
||||
pool_token_id,
|
||||
|
@ -271,8 +271,12 @@ fn get_total_token_a_amount(fuzz_instructions: &[FuzzInstruction]) -> u64 {
|
|||
for fuzz_instruction in fuzz_instructions.iter() {
|
||||
match fuzz_instruction {
|
||||
FuzzInstruction::Swap { token_a_id, .. } => token_a_ids.insert(token_a_id),
|
||||
FuzzInstruction::Deposit { token_a_id, .. } => token_a_ids.insert(token_a_id),
|
||||
FuzzInstruction::Withdraw { token_a_id, .. } => token_a_ids.insert(token_a_id),
|
||||
FuzzInstruction::DepositAllTokenTypes { token_a_id, .. } => {
|
||||
token_a_ids.insert(token_a_id)
|
||||
}
|
||||
FuzzInstruction::WithdrawAllTokenTypes { token_a_id, .. } => {
|
||||
token_a_ids.insert(token_a_id)
|
||||
}
|
||||
};
|
||||
}
|
||||
(token_a_ids.len() as u64) * INITIAL_USER_TOKEN_A_AMOUNT
|
||||
|
@ -283,8 +287,12 @@ fn get_total_token_b_amount(fuzz_instructions: &[FuzzInstruction]) -> u64 {
|
|||
for fuzz_instruction in fuzz_instructions.iter() {
|
||||
match fuzz_instruction {
|
||||
FuzzInstruction::Swap { token_b_id, .. } => token_b_ids.insert(token_b_id),
|
||||
FuzzInstruction::Deposit { token_b_id, .. } => token_b_ids.insert(token_b_id),
|
||||
FuzzInstruction::Withdraw { token_b_id, .. } => token_b_ids.insert(token_b_id),
|
||||
FuzzInstruction::DepositAllTokenTypes { token_b_id, .. } => {
|
||||
token_b_ids.insert(token_b_id)
|
||||
}
|
||||
FuzzInstruction::WithdrawAllTokenTypes { token_b_id, .. } => {
|
||||
token_b_ids.insert(token_b_id)
|
||||
}
|
||||
};
|
||||
}
|
||||
(token_b_ids.len() as u64) * INITIAL_USER_TOKEN_B_AMOUNT
|
||||
|
|
|
@ -6,7 +6,7 @@ use crate::native_token;
|
|||
|
||||
use spl_token_swap::{
|
||||
curve::{base::SwapCurve, fees::Fees},
|
||||
instruction::{self, Deposit, Swap, Withdraw},
|
||||
instruction::{self, DepositAllTokenTypes, Swap, WithdrawAllTokenTypes},
|
||||
state::SwapInfo,
|
||||
};
|
||||
|
||||
|
@ -261,7 +261,7 @@ impl NativeTokenSwap {
|
|||
token_a_account: &mut NativeAccountData,
|
||||
token_b_account: &mut NativeAccountData,
|
||||
pool_account: &mut NativeAccountData,
|
||||
mut instruction: Deposit,
|
||||
mut instruction: DepositAllTokenTypes,
|
||||
) -> ProgramResult {
|
||||
do_process_instruction(
|
||||
approve(
|
||||
|
@ -341,7 +341,7 @@ impl NativeTokenSwap {
|
|||
pool_account: &mut NativeAccountData,
|
||||
token_a_account: &mut NativeAccountData,
|
||||
token_b_account: &mut NativeAccountData,
|
||||
mut instruction: Withdraw,
|
||||
mut instruction: WithdrawAllTokenTypes,
|
||||
) -> ProgramResult {
|
||||
let pool_token_amount = native_token::get_token_balance(&pool_account);
|
||||
// special logic to avoid withdrawing down to 1 pool token, which
|
||||
|
@ -408,7 +408,7 @@ impl NativeTokenSwap {
|
|||
) -> ProgramResult {
|
||||
let pool_token_amount = native_token::get_token_balance(&pool_account);
|
||||
if pool_token_amount > 0 {
|
||||
let instruction = Withdraw {
|
||||
let instruction = WithdrawAllTokenTypes {
|
||||
pool_token_amount,
|
||||
minimum_token_a_amount: 0,
|
||||
minimum_token_b_amount: 0,
|
||||
|
|
|
@ -40,11 +40,11 @@ pub struct Swap {
|
|||
pub minimum_amount_out: u64,
|
||||
}
|
||||
|
||||
/// Deposit instruction data
|
||||
/// DepositAllTokenTypes instruction data
|
||||
#[cfg_attr(feature = "fuzz", derive(Arbitrary))]
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct Deposit {
|
||||
pub struct DepositAllTokenTypes {
|
||||
/// Pool token amount to transfer. token_a and token_b amount are set by
|
||||
/// the current exchange rate and size of the pool
|
||||
pub pool_token_amount: u64,
|
||||
|
@ -54,11 +54,11 @@ pub struct Deposit {
|
|||
pub maximum_token_b_amount: u64,
|
||||
}
|
||||
|
||||
/// Withdraw instruction data
|
||||
/// WithdrawAllTokenTypes instruction data
|
||||
#[cfg_attr(feature = "fuzz", derive(Arbitrary))]
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct Withdraw {
|
||||
pub struct WithdrawAllTokenTypes {
|
||||
/// Amount of pool tokens to burn. User receives an output of token a
|
||||
/// and b based on the percentage of the pool tokens that are returned.
|
||||
pub pool_token_amount: u64,
|
||||
|
@ -68,6 +68,30 @@ pub struct Withdraw {
|
|||
pub minimum_token_b_amount: u64,
|
||||
}
|
||||
|
||||
/// Deposit one token type, exact amount in instruction data
|
||||
#[cfg_attr(feature = "fuzz", derive(Arbitrary))]
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct DepositSingleTokenTypeExactAmountIn {
|
||||
/// Token amount to deposit
|
||||
pub source_token_amount: u64,
|
||||
/// Pool token amount to receive in exchange. The amount is set by
|
||||
/// the current exchange rate and size of the pool
|
||||
pub minimum_pool_token_amount: u64,
|
||||
}
|
||||
|
||||
/// WithdrawAllTokenTypes instruction data
|
||||
#[cfg_attr(feature = "fuzz", derive(Arbitrary))]
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct WithdrawSingleTokenTypeExactAmountOut {
|
||||
/// Amount of token A or B to receive
|
||||
pub destination_token_amount: u64,
|
||||
/// Maximum amount of pool tokens to burn. User receives an output of token A
|
||||
/// or B based on the percentage of the pool tokens that are returned.
|
||||
pub maximum_pool_token_amount: u64,
|
||||
}
|
||||
|
||||
/// Instructions supported by the SwapInfo program.
|
||||
#[repr(C)]
|
||||
#[derive(Debug, PartialEq)]
|
||||
|
@ -100,8 +124,9 @@ pub enum SwapInstruction {
|
|||
/// 9. `[optional, writable]` Host fee account to receive additional trading fees
|
||||
Swap(Swap),
|
||||
|
||||
/// Deposit some tokens into the pool. The output is a "pool" token representing ownership
|
||||
/// into the pool. Inputs are converted to the current ratio.
|
||||
/// Deposit both types of tokens into the pool. The output is a "pool"
|
||||
/// token representing ownership in the pool. Inputs are converted to
|
||||
/// the current ratio.
|
||||
///
|
||||
/// 0. `[]` Token-swap
|
||||
/// 1. `[]` $authority
|
||||
|
@ -112,9 +137,11 @@ pub enum SwapInstruction {
|
|||
/// 6. `[writable]` Pool MINT account, $authority is the owner.
|
||||
/// 7. `[writable]` Pool Account to deposit the generated tokens, user is the owner.
|
||||
/// 8. '[]` Token program id
|
||||
Deposit(Deposit),
|
||||
DepositAllTokenTypes(DepositAllTokenTypes),
|
||||
|
||||
/// Withdraw the token from the pool at the current ratio.
|
||||
/// Withdraw both types of tokens from the pool at the current ratio, given
|
||||
/// pool tokens. The pool tokens are burned in exchange for an equivalent
|
||||
/// amount of token A and B.
|
||||
///
|
||||
/// 0. `[]` Token-swap
|
||||
/// 1. `[]` $authority
|
||||
|
@ -126,7 +153,35 @@ pub enum SwapInstruction {
|
|||
/// 7. `[writable]` token_b user Account to credit.
|
||||
/// 8. `[writable]` Fee account, to receive withdrawal fees
|
||||
/// 9. '[]` Token program id
|
||||
Withdraw(Withdraw),
|
||||
WithdrawAllTokenTypes(WithdrawAllTokenTypes),
|
||||
|
||||
/// Deposit one type of tokens into the pool. The output is a "pool" token
|
||||
/// representing ownership into the pool. Input token is converted as if
|
||||
/// a swap and deposit all token types were performed.
|
||||
///
|
||||
/// 0. `[]` Token-swap
|
||||
/// 1. `[]` $authority
|
||||
/// 2. `[writable]` token_(A|B) SOURCE Account, amount is transferable by $authority,
|
||||
/// 3. `[writable]` token_a Swap Account, may deposit INTO.
|
||||
/// 4. `[writable]` token_b Swap Account, may deposit INTO.
|
||||
/// 5. `[writable]` Pool MINT account, $authority is the owner.
|
||||
/// 6. `[writable]` Pool Account to deposit the generated tokens, user is the owner.
|
||||
/// 7. '[]` Token program id
|
||||
DepositSingleTokenTypeExactAmountIn(DepositSingleTokenTypeExactAmountIn),
|
||||
|
||||
/// Withdraw one token type from the pool at the current ratio given the
|
||||
/// exact amount out expected.
|
||||
///
|
||||
/// 0. `[]` Token-swap
|
||||
/// 1. `[]` $authority
|
||||
/// 2. `[writable]` Pool mint account, $authority is the owner
|
||||
/// 3. `[writable]` SOURCE Pool account, amount is transferable by $authority.
|
||||
/// 4. `[writable]` token_a Swap Account to potentially withdraw from.
|
||||
/// 5. `[writable]` token_b Swap Account to potentially withdraw from.
|
||||
/// 6. `[writable]` token_(A|B) User Account to credit
|
||||
/// 7. `[writable]` Fee account, to receive withdrawal fees
|
||||
/// 8. '[]` Token program id
|
||||
WithdrawSingleTokenTypeExactAmountOut(WithdrawSingleTokenTypeExactAmountOut),
|
||||
}
|
||||
|
||||
impl SwapInstruction {
|
||||
|
@ -161,7 +216,7 @@ impl SwapInstruction {
|
|||
let (pool_token_amount, rest) = Self::unpack_u64(rest)?;
|
||||
let (maximum_token_a_amount, rest) = Self::unpack_u64(rest)?;
|
||||
let (maximum_token_b_amount, _rest) = Self::unpack_u64(rest)?;
|
||||
Self::Deposit(Deposit {
|
||||
Self::DepositAllTokenTypes(DepositAllTokenTypes {
|
||||
pool_token_amount,
|
||||
maximum_token_a_amount,
|
||||
maximum_token_b_amount,
|
||||
|
@ -171,12 +226,28 @@ impl SwapInstruction {
|
|||
let (pool_token_amount, rest) = Self::unpack_u64(rest)?;
|
||||
let (minimum_token_a_amount, rest) = Self::unpack_u64(rest)?;
|
||||
let (minimum_token_b_amount, _rest) = Self::unpack_u64(rest)?;
|
||||
Self::Withdraw(Withdraw {
|
||||
Self::WithdrawAllTokenTypes(WithdrawAllTokenTypes {
|
||||
pool_token_amount,
|
||||
minimum_token_a_amount,
|
||||
minimum_token_b_amount,
|
||||
})
|
||||
}
|
||||
4 => {
|
||||
let (source_token_amount, rest) = Self::unpack_u64(rest)?;
|
||||
let (minimum_pool_token_amount, _rest) = Self::unpack_u64(rest)?;
|
||||
Self::DepositSingleTokenTypeExactAmountIn(DepositSingleTokenTypeExactAmountIn {
|
||||
source_token_amount,
|
||||
minimum_pool_token_amount,
|
||||
})
|
||||
}
|
||||
5 => {
|
||||
let (destination_token_amount, rest) = Self::unpack_u64(rest)?;
|
||||
let (maximum_pool_token_amount, _rest) = Self::unpack_u64(rest)?;
|
||||
Self::WithdrawSingleTokenTypeExactAmountOut(WithdrawSingleTokenTypeExactAmountOut {
|
||||
destination_token_amount,
|
||||
maximum_pool_token_amount,
|
||||
})
|
||||
}
|
||||
_ => return Err(SwapError::InvalidInstruction.into()),
|
||||
})
|
||||
}
|
||||
|
@ -221,7 +292,7 @@ impl SwapInstruction {
|
|||
buf.extend_from_slice(&amount_in.to_le_bytes());
|
||||
buf.extend_from_slice(&minimum_amount_out.to_le_bytes());
|
||||
}
|
||||
Self::Deposit(Deposit {
|
||||
Self::DepositAllTokenTypes(DepositAllTokenTypes {
|
||||
pool_token_amount,
|
||||
maximum_token_a_amount,
|
||||
maximum_token_b_amount,
|
||||
|
@ -231,7 +302,7 @@ impl SwapInstruction {
|
|||
buf.extend_from_slice(&maximum_token_a_amount.to_le_bytes());
|
||||
buf.extend_from_slice(&maximum_token_b_amount.to_le_bytes());
|
||||
}
|
||||
Self::Withdraw(Withdraw {
|
||||
Self::WithdrawAllTokenTypes(WithdrawAllTokenTypes {
|
||||
pool_token_amount,
|
||||
minimum_token_a_amount,
|
||||
minimum_token_b_amount,
|
||||
|
@ -241,6 +312,24 @@ impl SwapInstruction {
|
|||
buf.extend_from_slice(&minimum_token_a_amount.to_le_bytes());
|
||||
buf.extend_from_slice(&minimum_token_b_amount.to_le_bytes());
|
||||
}
|
||||
Self::DepositSingleTokenTypeExactAmountIn(DepositSingleTokenTypeExactAmountIn {
|
||||
source_token_amount,
|
||||
minimum_pool_token_amount,
|
||||
}) => {
|
||||
buf.push(4);
|
||||
buf.extend_from_slice(&source_token_amount.to_le_bytes());
|
||||
buf.extend_from_slice(&minimum_pool_token_amount.to_le_bytes());
|
||||
}
|
||||
Self::WithdrawSingleTokenTypeExactAmountOut(
|
||||
WithdrawSingleTokenTypeExactAmountOut {
|
||||
destination_token_amount,
|
||||
maximum_pool_token_amount,
|
||||
},
|
||||
) => {
|
||||
buf.push(5);
|
||||
buf.extend_from_slice(&destination_token_amount.to_le_bytes());
|
||||
buf.extend_from_slice(&maximum_pool_token_amount.to_le_bytes());
|
||||
}
|
||||
}
|
||||
buf
|
||||
}
|
||||
|
@ -298,9 +387,9 @@ pub fn deposit(
|
|||
swap_token_b_pubkey: &Pubkey,
|
||||
pool_mint_pubkey: &Pubkey,
|
||||
destination_pubkey: &Pubkey,
|
||||
instruction: Deposit,
|
||||
instruction: DepositAllTokenTypes,
|
||||
) -> Result<Instruction, ProgramError> {
|
||||
let data = SwapInstruction::Deposit(instruction).pack();
|
||||
let data = SwapInstruction::DepositAllTokenTypes(instruction).pack();
|
||||
|
||||
let accounts = vec![
|
||||
AccountMeta::new_readonly(*swap_pubkey, false),
|
||||
|
@ -334,9 +423,9 @@ pub fn withdraw(
|
|||
swap_token_b_pubkey: &Pubkey,
|
||||
destination_token_a_pubkey: &Pubkey,
|
||||
destination_token_b_pubkey: &Pubkey,
|
||||
instruction: Withdraw,
|
||||
instruction: WithdrawAllTokenTypes,
|
||||
) -> Result<Instruction, ProgramError> {
|
||||
let data = SwapInstruction::Withdraw(instruction).pack();
|
||||
let data = SwapInstruction::WithdrawAllTokenTypes(instruction).pack();
|
||||
|
||||
let accounts = vec![
|
||||
AccountMeta::new_readonly(*swap_pubkey, false),
|
||||
|
@ -358,6 +447,74 @@ pub fn withdraw(
|
|||
})
|
||||
}
|
||||
|
||||
/// Creates a 'deposit_one_exact_in' instruction.
|
||||
pub fn deposit_one_exact_in(
|
||||
program_id: &Pubkey,
|
||||
token_program_id: &Pubkey,
|
||||
swap_pubkey: &Pubkey,
|
||||
authority_pubkey: &Pubkey,
|
||||
source_token_pubkey: &Pubkey,
|
||||
swap_token_a_pubkey: &Pubkey,
|
||||
swap_token_b_pubkey: &Pubkey,
|
||||
pool_mint_pubkey: &Pubkey,
|
||||
destination_pubkey: &Pubkey,
|
||||
instruction: DepositSingleTokenTypeExactAmountIn,
|
||||
) -> Result<Instruction, ProgramError> {
|
||||
let data = SwapInstruction::DepositSingleTokenTypeExactAmountIn(instruction).pack();
|
||||
|
||||
let accounts = vec![
|
||||
AccountMeta::new_readonly(*swap_pubkey, false),
|
||||
AccountMeta::new_readonly(*authority_pubkey, false),
|
||||
AccountMeta::new(*source_token_pubkey, false),
|
||||
AccountMeta::new(*swap_token_a_pubkey, false),
|
||||
AccountMeta::new(*swap_token_b_pubkey, false),
|
||||
AccountMeta::new(*pool_mint_pubkey, false),
|
||||
AccountMeta::new(*destination_pubkey, false),
|
||||
AccountMeta::new_readonly(*token_program_id, false),
|
||||
];
|
||||
|
||||
Ok(Instruction {
|
||||
program_id: *program_id,
|
||||
accounts,
|
||||
data,
|
||||
})
|
||||
}
|
||||
|
||||
/// Creates a 'withdraw_one_exact_out' instruction.
|
||||
pub fn withdraw_one_exact_out(
|
||||
program_id: &Pubkey,
|
||||
token_program_id: &Pubkey,
|
||||
swap_pubkey: &Pubkey,
|
||||
authority_pubkey: &Pubkey,
|
||||
pool_mint_pubkey: &Pubkey,
|
||||
fee_account_pubkey: &Pubkey,
|
||||
pool_token_source_pubkey: &Pubkey,
|
||||
swap_token_a_pubkey: &Pubkey,
|
||||
swap_token_b_pubkey: &Pubkey,
|
||||
destination_pubkey: &Pubkey,
|
||||
instruction: WithdrawSingleTokenTypeExactAmountOut,
|
||||
) -> Result<Instruction, ProgramError> {
|
||||
let data = SwapInstruction::WithdrawSingleTokenTypeExactAmountOut(instruction).pack();
|
||||
|
||||
let accounts = vec![
|
||||
AccountMeta::new_readonly(*swap_pubkey, false),
|
||||
AccountMeta::new_readonly(*authority_pubkey, false),
|
||||
AccountMeta::new(*pool_mint_pubkey, false),
|
||||
AccountMeta::new(*pool_token_source_pubkey, false),
|
||||
AccountMeta::new(*swap_token_a_pubkey, false),
|
||||
AccountMeta::new(*swap_token_b_pubkey, false),
|
||||
AccountMeta::new(*destination_pubkey, false),
|
||||
AccountMeta::new(*fee_account_pubkey, false),
|
||||
AccountMeta::new_readonly(*token_program_id, false),
|
||||
];
|
||||
|
||||
Ok(Instruction {
|
||||
program_id: *program_id,
|
||||
accounts,
|
||||
data,
|
||||
})
|
||||
}
|
||||
|
||||
/// Creates a 'swap' instruction.
|
||||
pub fn swap(
|
||||
program_id: &Pubkey,
|
||||
|
@ -415,7 +572,7 @@ mod tests {
|
|||
use crate::curve::{base::CurveType, stable::StableCurve};
|
||||
|
||||
#[test]
|
||||
fn test_instruction_packing() {
|
||||
fn pack_intialize() {
|
||||
let trade_fee_numerator: u64 = 1;
|
||||
let trade_fee_denominator: u64 = 4;
|
||||
let owner_trade_fee_numerator: u64 = 2;
|
||||
|
@ -465,7 +622,10 @@ mod tests {
|
|||
assert_eq!(packed, expect);
|
||||
let unpacked = SwapInstruction::unpack(&expect).unwrap();
|
||||
assert_eq!(unpacked, check);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pack_swap() {
|
||||
let amount_in: u64 = 2;
|
||||
let minimum_amount_out: u64 = 10;
|
||||
let check = SwapInstruction::Swap(Swap {
|
||||
|
@ -479,11 +639,14 @@ mod tests {
|
|||
assert_eq!(packed, expect);
|
||||
let unpacked = SwapInstruction::unpack(&expect).unwrap();
|
||||
assert_eq!(unpacked, check);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pack_deposit() {
|
||||
let pool_token_amount: u64 = 5;
|
||||
let maximum_token_a_amount: u64 = 10;
|
||||
let maximum_token_b_amount: u64 = 20;
|
||||
let check = SwapInstruction::Deposit(Deposit {
|
||||
let check = SwapInstruction::DepositAllTokenTypes(DepositAllTokenTypes {
|
||||
pool_token_amount,
|
||||
maximum_token_a_amount,
|
||||
maximum_token_b_amount,
|
||||
|
@ -496,11 +659,14 @@ mod tests {
|
|||
assert_eq!(packed, expect);
|
||||
let unpacked = SwapInstruction::unpack(&expect).unwrap();
|
||||
assert_eq!(unpacked, check);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pack_withdraw() {
|
||||
let pool_token_amount: u64 = 1212438012089;
|
||||
let minimum_token_a_amount: u64 = 102198761982612;
|
||||
let minimum_token_b_amount: u64 = 2011239855213;
|
||||
let check = SwapInstruction::Withdraw(Withdraw {
|
||||
let check = SwapInstruction::WithdrawAllTokenTypes(WithdrawAllTokenTypes {
|
||||
pool_token_amount,
|
||||
minimum_token_a_amount,
|
||||
minimum_token_b_amount,
|
||||
|
@ -514,4 +680,42 @@ mod tests {
|
|||
let unpacked = SwapInstruction::unpack(&expect).unwrap();
|
||||
assert_eq!(unpacked, check);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pack_deposit_one_exact_in() {
|
||||
let source_token_amount: u64 = 10;
|
||||
let minimum_pool_token_amount: u64 = 5;
|
||||
let check = SwapInstruction::DepositSingleTokenTypeExactAmountIn(
|
||||
DepositSingleTokenTypeExactAmountIn {
|
||||
source_token_amount,
|
||||
minimum_pool_token_amount,
|
||||
},
|
||||
);
|
||||
let packed = check.pack();
|
||||
let mut expect = vec![4];
|
||||
expect.extend_from_slice(&source_token_amount.to_le_bytes());
|
||||
expect.extend_from_slice(&minimum_pool_token_amount.to_le_bytes());
|
||||
assert_eq!(packed, expect);
|
||||
let unpacked = SwapInstruction::unpack(&expect).unwrap();
|
||||
assert_eq!(unpacked, check);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pack_withdraw_one_exact_out() {
|
||||
let destination_token_amount: u64 = 102198761982612;
|
||||
let maximum_pool_token_amount: u64 = 1212438012089;
|
||||
let check = SwapInstruction::WithdrawSingleTokenTypeExactAmountOut(
|
||||
WithdrawSingleTokenTypeExactAmountOut {
|
||||
destination_token_amount,
|
||||
maximum_pool_token_amount,
|
||||
},
|
||||
);
|
||||
let packed = check.pack();
|
||||
let mut expect = vec![5];
|
||||
expect.extend_from_slice(&destination_token_amount.to_le_bytes());
|
||||
expect.extend_from_slice(&maximum_pool_token_amount.to_le_bytes());
|
||||
assert_eq!(packed, expect);
|
||||
let unpacked = SwapInstruction::unpack(&expect).unwrap();
|
||||
assert_eq!(unpacked, check);
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue