Skip to content

Commit

Permalink
token-swap: Add slippage to swap / withdraw / deposit (solana-labs#560)
Browse files Browse the repository at this point in the history
* token-swap: Add slippage to swap / withdraw / deposit

* Update JS snake_case -> camelCase

* Run prettier
  • Loading branch information
joncinque authored Oct 2, 2020
1 parent f491739 commit bbc5f57
Show file tree
Hide file tree
Showing 7 changed files with 446 additions and 91 deletions.
22 changes: 14 additions & 8 deletions token-swap/js/cli/token-swap-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,9 @@ let tokenAccountB: PublicKey;

// Initial amount in each swap token
const BASE_AMOUNT = 1000;
// Amount passed to instructions
const USER_AMOUNT = 100;
// Amount passed to swap instruction
const SWAP_AMOUNT_IN = 100;
const SWAP_AMOUNT_OUT = 69;
// Pool token amount minted on init
const DEFAULT_POOL_TOKEN_AMOUNT = 1000000000;
// Pool token amount to withdraw / deposit
Expand Down Expand Up @@ -253,6 +254,8 @@ export async function deposit(): Promise<void> {
newAccountPool,
tokenProgramId,
POOL_TOKEN_AMOUNT,
tokenA,
tokenB,
);

let info;
Expand Down Expand Up @@ -302,6 +305,8 @@ export async function withdraw(): Promise<void> {
userAccountB,
tokenProgramId,
POOL_TOKEN_AMOUNT,
tokenA,
tokenB,
);

//const poolMintInfo = await tokenPool.getMintInfo();
Expand All @@ -323,8 +328,8 @@ export async function withdraw(): Promise<void> {
export async function swap(): Promise<void> {
console.log('Creating swap token a account');
let userAccountA = await mintA.createAccount(owner.publicKey);
await mintA.mintTo(userAccountA, owner, [], USER_AMOUNT);
await mintA.approve(userAccountA, authority, owner, [], USER_AMOUNT);
await mintA.mintTo(userAccountA, owner, [], SWAP_AMOUNT_IN);
await mintA.approve(userAccountA, authority, owner, [], SWAP_AMOUNT_IN);
console.log('Creating swap token b account');
let userAccountB = await mintB.createAccount(owner.publicKey);
const [tokenProgramId] = await GetPrograms(connection);
Expand All @@ -337,18 +342,19 @@ export async function swap(): Promise<void> {
tokenAccountB,
userAccountB,
tokenProgramId,
USER_AMOUNT,
SWAP_AMOUNT_IN,
SWAP_AMOUNT_OUT,
);
await sleep(500);
let info;
info = await mintA.getAccountInfo(userAccountA);
assert(info.amount.toNumber() == 0);
info = await mintA.getAccountInfo(tokenAccountA);
assert(info.amount.toNumber() == BASE_AMOUNT + USER_AMOUNT);
assert(info.amount.toNumber() == BASE_AMOUNT + SWAP_AMOUNT_IN);
info = await mintB.getAccountInfo(tokenAccountB);
assert(info.amount.toNumber() == 931);
assert(info.amount.toNumber() == BASE_AMOUNT - SWAP_AMOUNT_OUT);
info = await mintB.getAccountInfo(userAccountB);
assert(info.amount.toNumber() == 69);
assert(info.amount.toNumber() == SWAP_AMOUNT_OUT);
info = await tokenPool.getAccountInfo(tokenAccountPool);
assert(
info.amount.toNumber() == DEFAULT_POOL_TOKEN_AMOUNT - POOL_TOKEN_AMOUNT,
Expand Down
55 changes: 40 additions & 15 deletions token-swap/js/client/token-swap.js
Original file line number Diff line number Diff line change
Expand Up @@ -345,7 +345,8 @@ export class TokenSwap {
swapDestination: PublicKey,
destination: PublicKey,
tokenProgramId: PublicKey,
amount: number | Numberu64,
amountIn: number | Numberu64,
minimumAmountOut: number | Numberu64,
): Promise<TransactionSignature> {
return await sendAndConfirmTransaction(
'swap',
Expand All @@ -360,7 +361,8 @@ export class TokenSwap {
destination,
this.programId,
tokenProgramId,
amount,
amountIn,
minimumAmountOut,
),
),
this.payer,
Expand All @@ -376,18 +378,21 @@ export class TokenSwap {
destination: PublicKey,
swapProgramId: PublicKey,
tokenProgramId: PublicKey,
amount: number | Numberu64,
amountIn: number | Numberu64,
minimumAmountOut: number | Numberu64,
): TransactionInstruction {
const dataLayout = BufferLayout.struct([
BufferLayout.u8('instruction'),
Layout.uint64('amount'),
Layout.uint64('amountIn'),
Layout.uint64('minimumAmountOut'),
]);

const data = Buffer.alloc(dataLayout.span);
dataLayout.encode(
{
instruction: 1, // Swap instruction
amount: new Numberu64(amount).toBuffer(),
amountIn: new Numberu64(amountIn).toBuffer(),
minimumAmountOut: new Numberu64(minimumAmountOut).toBuffer(),
},
data,
);
Expand Down Expand Up @@ -430,7 +435,9 @@ export class TokenSwap {
poolToken: PublicKey,
poolAccount: PublicKey,
tokenProgramId: PublicKey,
amount: number | Numberu64,
poolTokenAmount: number | Numberu64,
maximumTokenA: number | Numberu64,
maximumTokenB: number | Numberu64,
): Promise<TransactionSignature> {
return await sendAndConfirmTransaction(
'deposit',
Expand All @@ -447,7 +454,9 @@ export class TokenSwap {
poolAccount,
this.programId,
tokenProgramId,
amount,
poolTokenAmount,
maximumTokenA,
maximumTokenB,
),
),
this.payer,
Expand All @@ -465,18 +474,24 @@ export class TokenSwap {
poolAccount: PublicKey,
swapProgramId: PublicKey,
tokenProgramId: PublicKey,
amount: number | Numberu64,
poolTokenAmount: number | Numberu64,
maximumTokenA: number | Numberu64,
maximumTokenB: number | Numberu64,
): TransactionInstruction {
const dataLayout = BufferLayout.struct([
BufferLayout.u8('instruction'),
Layout.uint64('amount'),
Layout.uint64('poolTokenAmount'),
Layout.uint64('maximumTokenA'),
Layout.uint64('maximumTokenB'),
]);

const data = Buffer.alloc(dataLayout.span);
dataLayout.encode(
{
instruction: 2, // Deposit instruction
amount: new Numberu64(amount).toBuffer(),
poolTokenAmount: new Numberu64(poolTokenAmount).toBuffer(),
maximumTokenA: new Numberu64(maximumTokenA).toBuffer(),
maximumTokenB: new Numberu64(maximumTokenB).toBuffer(),
},
data,
);
Expand Down Expand Up @@ -521,7 +536,9 @@ export class TokenSwap {
userAccountA: PublicKey,
userAccountB: PublicKey,
tokenProgramId: PublicKey,
amount: number | Numberu64,
poolTokenAmount: number | Numberu64,
minimumTokenA: number | Numberu64,
minimumTokenB: number | Numberu64,
): Promise<TransactionSignature> {
return await sendAndConfirmTransaction(
'withdraw',
Expand All @@ -538,7 +555,9 @@ export class TokenSwap {
userAccountB,
this.programId,
tokenProgramId,
amount,
poolTokenAmount,
minimumTokenA,
minimumTokenB,
),
),
this.payer,
Expand All @@ -556,18 +575,24 @@ export class TokenSwap {
userAccountB: PublicKey,
swapProgramId: PublicKey,
tokenProgramId: PublicKey,
amount: number | Numberu64,
poolTokenAmount: number | Numberu64,
minimumTokenA: number | Numberu64,
minimumTokenB: number | Numberu64,
): TransactionInstruction {
const dataLayout = BufferLayout.struct([
BufferLayout.u8('instruction'),
Layout.uint64('amount'),
Layout.uint64('poolTokenAmount'),
Layout.uint64('minimumTokenA'),
Layout.uint64('minimumTokenB'),
]);

const data = Buffer.alloc(dataLayout.span);
dataLayout.encode(
{
instruction: 3, // Withdraw instruction
amount: new Numberu64(amount).toBuffer(),
poolTokenAmount: new Numberu64(poolTokenAmount).toBuffer(),
minimumTokenA: new Numberu64(minimumTokenA).toBuffer(),
minimumTokenB: new Numberu64(minimumTokenB).toBuffer(),
},
data,
);
Expand Down
23 changes: 17 additions & 6 deletions token-swap/js/module.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,14 +71,16 @@ declare module '@solana/spl-token-swap' {
): Promise<TokenSwap>;

getInfo(): Promise<TokenSwapInfo>;

swap(
authority: PublicKey,
source: PublicKey,
swapSource: PublicKey,
swapDestination: PublicKey,
destination: PublicKey,
tokenProgramId: PublicKey,
amount: number | Numberu64,
amountIn: number | Numberu64,
minimumAmountOut: number | Numberu64,
): Promise<TransactionSignature>;

static swapInstruction(
Expand All @@ -90,7 +92,8 @@ declare module '@solana/spl-token-swap' {
destination: PublicKey,
swapProgramId: PublicKey,
tokenProgramId: PublicKey,
amount: number | Numberu64,
amountIn: number | Numberu64,
minimumAmountOut: number | Numberu64,
): TransactionInstruction;

deposit(
Expand All @@ -102,7 +105,9 @@ declare module '@solana/spl-token-swap' {
poolToken: PublicKey,
poolAccount: PublicKey,
tokenProgramId: PublicKey,
amount: number | Numberu64,
poolTokenAmount: number | Numberu64,
maximumTokenA: number | Numberu64,
maximumTokenB: number | Numberu64,
): Promise<TransactionSignature>;

static depositInstruction(
Expand All @@ -116,7 +121,9 @@ declare module '@solana/spl-token-swap' {
poolAccount: PublicKey,
swapProgramId: PublicKey,
tokenProgramId: PublicKey,
amount: number | Numberu64,
poolTokenAmount: number | Numberu64,
maximumTokenA: number | Numberu64,
maximumTokenB: number | Numberu64,
): TransactionInstruction;

withdraw(
Expand All @@ -128,7 +135,9 @@ declare module '@solana/spl-token-swap' {
userAccountA: PublicKey,
userAccountB: PublicKey,
tokenProgramId: PublicKey,
amount: number | Numberu64,
poolTokenAmount: number | Numberu64,
minimumTokenA: number | Numberu64,
minimumTokenB: number | Numberu64,
): Promise<TransactionSignature>;

static withdrawInstruction(
Expand All @@ -142,7 +151,9 @@ declare module '@solana/spl-token-swap' {
userAccountB: PublicKey,
swapProgramId: PublicKey,
tokenProgramId: PublicKey,
amount: number | Numberu64,
poolTokenAmount: number | Numberu64,
minimumTokenA: number | Numberu64,
minimumTokenB: number | Numberu64,
): TransactionInstruction;
}
}
22 changes: 16 additions & 6 deletions token-swap/js/module.flow.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,8 @@ declare module '@solana/spl-token-swap' {
swapDestination: PublicKey,
destination: PublicKey,
tokenProgramId: PublicKey,
amount: number | Numberu64,
amountIn: number | Numberu64,
minimumAmountOut: number | Numberu64,
): Promise<TransactionSignature>;

static swapInstruction(
Expand All @@ -87,7 +88,8 @@ declare module '@solana/spl-token-swap' {
destination: PublicKey,
swapProgramId: PublicKey,
tokenProgramId: PublicKey,
amount: number | Numberu64,
amountIn: number | Numberu64,
minimumAmountOut: number | Numberu64,
): TransactionInstruction;

deposit(
Expand All @@ -99,7 +101,9 @@ declare module '@solana/spl-token-swap' {
poolToken: PublicKey,
poolAccount: PublicKey,
tokenProgramId: PublicKey,
amount: number | Numberu64,
poolTokenAmount: number | Numberu64,
maximumTokenA: number | Numberu64,
maximumTokenB: number | Numberu64,
): Promise<TransactionSignature>;

static depositInstruction(
Expand All @@ -113,7 +117,9 @@ declare module '@solana/spl-token-swap' {
poolAccount: PublicKey,
swapProgramId: PublicKey,
tokenProgramId: PublicKey,
amount: number | Numberu64,
poolTokenAmount: number | Numberu64,
maximumTokenA: number | Numberu64,
maximumTokenB: number | Numberu64,
): TransactionInstruction;

withdraw(
Expand All @@ -125,7 +131,9 @@ declare module '@solana/spl-token-swap' {
userAccountA: PublicKey,
userAccountB: PublicKey,
tokenProgramId: PublicKey,
amount: number | Numberu64,
poolTokenAmount: number | Numberu64,
minimumTokenA: number | Numberu64,
minimumTokenB: number | Numberu64,
): Promise<TransactionSignature>;

static withdrawInstruction(
Expand All @@ -139,7 +147,9 @@ declare module '@solana/spl-token-swap' {
userAccountB: PublicKey,
swapProgramId: PublicKey,
tokenProgramId: PublicKey,
amount: number | Numberu64,
poolTokenAmount: number | Numberu64,
minimumTokenA: number | Numberu64,
minimumTokenB: number | Numberu64,
): TransactionInstruction;
}
}
3 changes: 3 additions & 0 deletions token-swap/program/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ pub enum SwapError {
/// Swap input token accounts have the same mint
#[error("Swap input token accounts have the same mint")]
RepeatedMint,
/// Swap instruction exceeds desired slippage limit
#[error("Swap instruction exceeds desired slippage limit")]
ExceededSlippage,
}
impl From<SwapError> for ProgramError {
fn from(e: SwapError) -> Self {
Expand Down
Loading

0 comments on commit bbc5f57

Please sign in to comment.