Pass TokenSwap state into the constructor to simplify function calls (#586)
* Pass TokenSwap state into the constructor to simplify function calls * WIP: Update program to return token_program_id * Add tokenProgramId to js TokenSwapInfo object * Address pr comments * Remove TokenSwapInfo and use loadTokenSwap as the primary way to fetch TokenSwap metadata * Fix module.d.ts * Address pr comments * Clarification on comments Co-authored-by: Yutaro Mori <yutaro@umaproject.org>
This commit is contained in:
parent
b45e3bf00c
commit
5f56635fde
|
@ -562,13 +562,12 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "curve25519-dalek"
|
||||
version = "2.1.0"
|
||||
source = "git+https://github.com/garious/curve25519-dalek?rev=60efef3553d6bf3d7f3b09b5f97acd54d72529ff#60efef3553d6bf3d7f3b09b5f97acd54d72529ff"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5d85653f070353a16313d0046f173f70d1aadd5b42600a14de626f0dfb3473a5"
|
||||
dependencies = [
|
||||
"borsh",
|
||||
"byteorder",
|
||||
"digest 0.8.1",
|
||||
"rand_core",
|
||||
"serde",
|
||||
"subtle 2.2.3",
|
||||
"zeroize",
|
||||
]
|
||||
|
@ -576,12 +575,13 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "curve25519-dalek"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5d85653f070353a16313d0046f173f70d1aadd5b42600a14de626f0dfb3473a5"
|
||||
source = "git+https://github.com/garious/curve25519-dalek?rev=60efef3553d6bf3d7f3b09b5f97acd54d72529ff#60efef3553d6bf3d7f3b09b5f97acd54d72529ff"
|
||||
dependencies = [
|
||||
"borsh",
|
||||
"byteorder",
|
||||
"digest 0.8.1",
|
||||
"rand_core",
|
||||
"serde",
|
||||
"subtle 2.2.3",
|
||||
"zeroize",
|
||||
]
|
||||
|
|
|
@ -194,24 +194,31 @@ export async function createTokenSwap(): Promise<void> {
|
|||
swapPayer,
|
||||
tokenSwapAccount,
|
||||
authority,
|
||||
nonce,
|
||||
tokenAccountA,
|
||||
tokenAccountB,
|
||||
tokenPool.publicKey,
|
||||
tokenAccountPool,
|
||||
tokenSwapProgramId,
|
||||
tokenProgramId,
|
||||
nonce,
|
||||
1,
|
||||
4,
|
||||
tokenSwapProgramId,
|
||||
);
|
||||
|
||||
console.log('getting token swap');
|
||||
const swapInfo = await tokenSwap.getInfo();
|
||||
assert(swapInfo.tokenAccountA.equals(tokenAccountA));
|
||||
assert(swapInfo.tokenAccountB.equals(tokenAccountB));
|
||||
assert(swapInfo.tokenPool.equals(tokenPool.publicKey));
|
||||
assert(1 == swapInfo.feesNumerator.toNumber());
|
||||
assert(4 == swapInfo.feesDenominator.toNumber());
|
||||
console.log('loading token swap');
|
||||
const fetchedTokenSwap = await TokenSwap.loadTokenSwap(
|
||||
connection,
|
||||
tokenSwapAccount.publicKey,
|
||||
tokenSwapProgramId,
|
||||
swapPayer,
|
||||
);
|
||||
|
||||
assert(fetchedTokenSwap.tokenProgramId.equals(tokenProgramId));
|
||||
assert(fetchedTokenSwap.tokenAccountA.equals(tokenAccountA));
|
||||
assert(fetchedTokenSwap.tokenAccountB.equals(tokenAccountB));
|
||||
assert(fetchedTokenSwap.poolToken.equals(tokenPool.publicKey));
|
||||
assert(1 == fetchedTokenSwap.feeNumerator.toNumber());
|
||||
assert(4 == fetchedTokenSwap.feeDenominator.toNumber());
|
||||
}
|
||||
|
||||
export async function deposit(): Promise<void> {
|
||||
|
@ -232,18 +239,12 @@ export async function deposit(): Promise<void> {
|
|||
await mintB.approve(userAccountB, authority, owner, [], tokenB);
|
||||
console.log('Creating depositor pool token account');
|
||||
const newAccountPool = await tokenPool.createAccount(owner.publicKey);
|
||||
const [tokenProgramId] = await GetPrograms(connection);
|
||||
|
||||
console.log('Depositing into swap');
|
||||
await tokenSwap.deposit(
|
||||
authority,
|
||||
userAccountA,
|
||||
userAccountB,
|
||||
tokenAccountA,
|
||||
tokenAccountB,
|
||||
tokenPool.publicKey,
|
||||
newAccountPool,
|
||||
tokenProgramId,
|
||||
POOL_TOKEN_AMOUNT,
|
||||
tokenA,
|
||||
tokenB,
|
||||
|
@ -283,18 +284,12 @@ export async function withdraw(): Promise<void> {
|
|||
[],
|
||||
POOL_TOKEN_AMOUNT,
|
||||
);
|
||||
const [tokenProgramId] = await GetPrograms(connection);
|
||||
|
||||
console.log('Withdrawing pool tokens for A and B tokens');
|
||||
await tokenSwap.withdraw(
|
||||
authority,
|
||||
tokenPool.publicKey,
|
||||
tokenAccountPool,
|
||||
tokenAccountA,
|
||||
tokenAccountB,
|
||||
userAccountA,
|
||||
userAccountB,
|
||||
tokenProgramId,
|
||||
tokenAccountPool,
|
||||
POOL_TOKEN_AMOUNT,
|
||||
tokenA,
|
||||
tokenB,
|
||||
|
@ -323,16 +318,13 @@ export async function swap(): Promise<void> {
|
|||
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);
|
||||
|
||||
console.log('Swapping');
|
||||
await tokenSwap.swap(
|
||||
authority,
|
||||
userAccountA,
|
||||
tokenAccountA,
|
||||
tokenAccountB,
|
||||
userAccountB,
|
||||
tokenProgramId,
|
||||
SWAP_AMOUNT_IN,
|
||||
SWAP_AMOUNT_OUT,
|
||||
);
|
||||
|
|
|
@ -16,6 +16,7 @@ import {
|
|||
|
||||
import * as Layout from './layout';
|
||||
import {sendAndConfirmTransaction} from './util/send-and-confirm-transaction';
|
||||
import {loadAccount} from './util/account';
|
||||
|
||||
/**
|
||||
* Some amount of tokens
|
||||
|
@ -52,46 +53,6 @@ export class Numberu64 extends BN {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Information about a token swap
|
||||
*/
|
||||
type TokenSwapInfo = {|
|
||||
/**
|
||||
* Nonce. Used to generate the valid program address in the program
|
||||
*/
|
||||
nonce: number,
|
||||
|
||||
/**
|
||||
* Token A. The Liquidity token is issued against this value.
|
||||
*/
|
||||
tokenAccountA: PublicKey,
|
||||
|
||||
/**
|
||||
* Token B
|
||||
*/
|
||||
tokenAccountB: PublicKey,
|
||||
/**
|
||||
* Pool tokens are issued when A or B tokens are deposited
|
||||
* Pool tokens can be withdrawn back to the original A or B token
|
||||
*/
|
||||
tokenPool: PublicKey,
|
||||
|
||||
/**
|
||||
* Fee numerator
|
||||
*/
|
||||
feesNumerator: Numberu64,
|
||||
|
||||
/**
|
||||
* Fee denominator
|
||||
*/
|
||||
feesDenominator: Numberu64,
|
||||
|
||||
/**
|
||||
* Fee ratio applied to the input token amount prior to output calculation
|
||||
*/
|
||||
feeRatio: number,
|
||||
|};
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
|
@ -99,16 +60,17 @@ export const TokenSwapLayout: typeof BufferLayout.Structure = BufferLayout.struc
|
|||
[
|
||||
BufferLayout.u8('isInitialized'),
|
||||
BufferLayout.u8('nonce'),
|
||||
Layout.publicKey('tokenProgramId'),
|
||||
Layout.publicKey('tokenAccountA'),
|
||||
Layout.publicKey('tokenAccountB'),
|
||||
Layout.publicKey('tokenPool'),
|
||||
Layout.uint64('feesNumerator'),
|
||||
Layout.uint64('feesDenominator'),
|
||||
Layout.uint64('feeNumerator'),
|
||||
Layout.uint64('feeDenominator'),
|
||||
],
|
||||
);
|
||||
|
||||
/**
|
||||
* An ERC20-like Token
|
||||
* A program to exchange tokens against a pool of liquidity
|
||||
*/
|
||||
export class TokenSwap {
|
||||
/**
|
||||
|
@ -117,14 +79,49 @@ export class TokenSwap {
|
|||
connection: Connection;
|
||||
|
||||
/**
|
||||
* The public key identifying this token
|
||||
* Program Identifier for the Swap program
|
||||
*/
|
||||
swapProgramId: PublicKey;
|
||||
|
||||
/**
|
||||
* Program Identifier for the Token program
|
||||
*/
|
||||
tokenProgramId: PublicKey;
|
||||
|
||||
/**
|
||||
* The public key identifying this swap program
|
||||
*/
|
||||
tokenSwap: PublicKey;
|
||||
|
||||
/**
|
||||
* Program Identifier for the Token Swap program
|
||||
* The public key for the liquidity pool token mint
|
||||
*/
|
||||
programId: PublicKey;
|
||||
poolToken: PublicKey;
|
||||
|
||||
/**
|
||||
* Authority
|
||||
*/
|
||||
authority: PublicKey;
|
||||
|
||||
/**
|
||||
* The public key for the first token account of the trading pair
|
||||
*/
|
||||
tokenAccountA: PublicKey;
|
||||
|
||||
/**
|
||||
* The public key for the second token account of the trading pair
|
||||
*/
|
||||
tokenAccountB: PublicKey;
|
||||
|
||||
/**
|
||||
* Fee numerator
|
||||
*/
|
||||
feeNumerator: Numberu64;
|
||||
|
||||
/**
|
||||
* Fee denominator
|
||||
*/
|
||||
feeDenominator: Numberu64;
|
||||
|
||||
/**
|
||||
* Fee payer
|
||||
|
@ -135,17 +132,41 @@ export class TokenSwap {
|
|||
* Create a Token object attached to the specific token
|
||||
*
|
||||
* @param connection The connection to use
|
||||
* @param token Public key of the token
|
||||
* @param programId Optional token programId, uses the system programId by default
|
||||
* @param payer Payer of fees
|
||||
* @param tokenSwap The token swap account
|
||||
* @param swapProgramId The program ID of the token-swap program
|
||||
* @param tokenProgramId The program ID of the token program
|
||||
* @param poolToken The pool token
|
||||
* @param authority The authority over the swap and accounts
|
||||
* @param tokenAccountA: The token swap's Token A account
|
||||
* @param tokenAccountB: The token swap's Token B account
|
||||
* @param payer Pays for the transaction
|
||||
*/
|
||||
constructor(
|
||||
connection: Connection,
|
||||
tokenSwap: PublicKey,
|
||||
programId: PublicKey,
|
||||
swapProgramId: PublicKey,
|
||||
tokenProgramId: PublicKey,
|
||||
poolToken: PublicKey,
|
||||
authority: PublicKey,
|
||||
tokenAccountA: PublicKey,
|
||||
tokenAccountB: PublicKey,
|
||||
feeNumerator: Numberu64,
|
||||
feeDenominator: Numberu64,
|
||||
payer: Account,
|
||||
) {
|
||||
Object.assign(this, {connection, tokenSwap, programId, payer});
|
||||
Object.assign(this, {
|
||||
connection,
|
||||
tokenSwap,
|
||||
swapProgramId,
|
||||
tokenProgramId,
|
||||
poolToken,
|
||||
authority,
|
||||
tokenAccountA,
|
||||
tokenAccountB,
|
||||
feeNumerator,
|
||||
feeDenominator,
|
||||
payer,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -209,6 +230,46 @@ export class TokenSwap {
|
|||
});
|
||||
}
|
||||
|
||||
static async loadTokenSwap(
|
||||
connection: Connection,
|
||||
address: PublicKey,
|
||||
programId: PublicKey,
|
||||
payer: Account,
|
||||
): Promise<TokenSwap> {
|
||||
const data = await loadAccount(connection, address, programId);
|
||||
const tokenSwapData = TokenSwapLayout.decode(data);
|
||||
if (!tokenSwapData.isInitialized) {
|
||||
throw new Error(`Invalid token swap state`);
|
||||
}
|
||||
|
||||
const [authority] = await PublicKey.findProgramAddress(
|
||||
[address.toBuffer()],
|
||||
programId,
|
||||
);
|
||||
|
||||
const poolToken = new PublicKey(tokenSwapData.tokenPool);
|
||||
const tokenAccountA = new PublicKey(tokenSwapData.tokenAccountA);
|
||||
const tokenAccountB = new PublicKey(tokenSwapData.tokenAccountB);
|
||||
const tokenProgramId = new PublicKey(tokenSwapData.tokenProgramId);
|
||||
|
||||
const feeNumerator = Numberu64.fromBuffer(tokenSwapData.feeNumerator);
|
||||
const feeDenominator = Numberu64.fromBuffer(tokenSwapData.feeDenominator);
|
||||
|
||||
return new TokenSwap(
|
||||
connection,
|
||||
address,
|
||||
programId,
|
||||
tokenProgramId,
|
||||
poolToken,
|
||||
authority,
|
||||
tokenAccountA,
|
||||
tokenAccountB,
|
||||
feeNumerator,
|
||||
feeDenominator,
|
||||
payer,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new Token Swap
|
||||
*
|
||||
|
@ -216,14 +277,15 @@ export class TokenSwap {
|
|||
* @param payer Pays for the transaction
|
||||
* @param tokenSwapAccount The token swap account
|
||||
* @param authority The authority over the swap and accounts
|
||||
* @param tokenAccountA: The Swap's Token A account
|
||||
* @param tokenAccountB: The Swap's Token B account
|
||||
* @param tokenPool The pool token
|
||||
* @param tokenAccountPool The pool token account
|
||||
* @param tokenProgramId The program id of the token program
|
||||
* @param nonce The nonce used to generate the authority
|
||||
* @param tokenAccountA: The token swap's Token A account
|
||||
* @param tokenAccountB: The token swap's Token B account
|
||||
* @param poolToken The pool token
|
||||
* @param tokenAccountPool The token swap's pool token account
|
||||
* @param tokenProgramId The program ID of the token program
|
||||
* @param swapProgramId The program ID of the token-swap program
|
||||
* @param feeNumerator Numerator of the fee ratio
|
||||
* @param feeDenominator Denominator of the fee ratio
|
||||
* @param swapProgramId Program ID of the token-swap program
|
||||
* @return Token object for the newly minted token, Public key of the account holding the total supply of new tokens
|
||||
*/
|
||||
static async createTokenSwap(
|
||||
|
@ -231,21 +293,28 @@ export class TokenSwap {
|
|||
payer: Account,
|
||||
tokenSwapAccount: Account,
|
||||
authority: PublicKey,
|
||||
nonce: number,
|
||||
tokenAccountA: PublicKey,
|
||||
tokenAccountB: PublicKey,
|
||||
tokenPool: PublicKey,
|
||||
poolToken: PublicKey,
|
||||
tokenAccountPool: PublicKey,
|
||||
swapProgramId: PublicKey,
|
||||
tokenProgramId: PublicKey,
|
||||
nonce: number,
|
||||
feeNumerator: number,
|
||||
feeDenominator: number,
|
||||
swapProgramId: PublicKey,
|
||||
): Promise<TokenSwap> {
|
||||
let transaction;
|
||||
const tokenSwap = new TokenSwap(
|
||||
connection,
|
||||
tokenSwapAccount.publicKey,
|
||||
swapProgramId,
|
||||
tokenProgramId,
|
||||
poolToken,
|
||||
authority,
|
||||
tokenAccountA,
|
||||
tokenAccountB,
|
||||
new Numberu64(feeNumerator),
|
||||
new Numberu64(feeDenominator),
|
||||
payer,
|
||||
);
|
||||
|
||||
|
@ -270,7 +339,7 @@ export class TokenSwap {
|
|||
nonce,
|
||||
tokenAccountA,
|
||||
tokenAccountB,
|
||||
tokenPool,
|
||||
poolToken,
|
||||
tokenAccountPool,
|
||||
tokenProgramId,
|
||||
swapProgramId,
|
||||
|
@ -291,60 +360,20 @@ export class TokenSwap {
|
|||
}
|
||||
|
||||
/**
|
||||
* Retrieve tokenSwap information
|
||||
*/
|
||||
async getInfo(): Promise<TokenSwapInfo> {
|
||||
const accountInfo = await this.connection.getAccountInfo(this.tokenSwap);
|
||||
if (accountInfo === null) {
|
||||
throw new Error('Failed to find token swap account');
|
||||
}
|
||||
if (!accountInfo.owner.equals(this.programId)) {
|
||||
throw new Error(
|
||||
`Invalid token swap owner: ${JSON.stringify(accountInfo.owner)}`,
|
||||
);
|
||||
}
|
||||
|
||||
const data = Buffer.from(accountInfo.data);
|
||||
const tokenSwapInfo = TokenSwapLayout.decode(data);
|
||||
if (!tokenSwapInfo.isInitialized) {
|
||||
throw new Error(`Invalid token swap state`);
|
||||
}
|
||||
// already properly filled in
|
||||
// tokenSwapInfo.nonce = tokenSwapInfo.nonce;
|
||||
tokenSwapInfo.tokenAccountA = new PublicKey(tokenSwapInfo.tokenAccountA);
|
||||
tokenSwapInfo.tokenAccountB = new PublicKey(tokenSwapInfo.tokenAccountB);
|
||||
tokenSwapInfo.tokenPool = new PublicKey(tokenSwapInfo.tokenPool);
|
||||
tokenSwapInfo.feesNumerator = Numberu64.fromBuffer(
|
||||
tokenSwapInfo.feesNumerator,
|
||||
);
|
||||
tokenSwapInfo.feesDenominator = Numberu64.fromBuffer(
|
||||
tokenSwapInfo.feesDenominator,
|
||||
);
|
||||
tokenSwapInfo.feeRatio =
|
||||
tokenSwapInfo.feesNumerator.toNumber() /
|
||||
tokenSwapInfo.feesDenominator.toNumber();
|
||||
|
||||
return tokenSwapInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Swap the tokens in the pool
|
||||
* Swap token A for token B
|
||||
*
|
||||
* @param authority Authority
|
||||
* @param source Source account
|
||||
* @param swapSource Base account to swap into, must be a source token
|
||||
* @param swapDestination Base account to swap from, must be a destination token
|
||||
* @param destination Destination token account
|
||||
* @param tokenProgramId Token program id
|
||||
* @param amount Amount to transfer from source account
|
||||
* @param userSource User's source token account
|
||||
* @param poolSource Pool's source token account
|
||||
* @param poolDestination Pool's destination token account
|
||||
* @param userDestination User's destination token account
|
||||
* @param amountIn Amount to transfer from source account
|
||||
* @param minimumAmountOut Minimum amount of tokens the user will receive
|
||||
*/
|
||||
async swap(
|
||||
authority: PublicKey,
|
||||
source: PublicKey,
|
||||
swapSource: PublicKey,
|
||||
swapDestination: PublicKey,
|
||||
destination: PublicKey,
|
||||
tokenProgramId: PublicKey,
|
||||
userSource: PublicKey,
|
||||
poolSource: PublicKey,
|
||||
poolDestination: PublicKey,
|
||||
userDestination: PublicKey,
|
||||
amountIn: number | Numberu64,
|
||||
minimumAmountOut: number | Numberu64,
|
||||
): Promise<TransactionSignature> {
|
||||
|
@ -354,13 +383,13 @@ export class TokenSwap {
|
|||
new Transaction().add(
|
||||
TokenSwap.swapInstruction(
|
||||
this.tokenSwap,
|
||||
authority,
|
||||
source,
|
||||
swapSource,
|
||||
swapDestination,
|
||||
destination,
|
||||
this.programId,
|
||||
tokenProgramId,
|
||||
this.authority,
|
||||
userSource,
|
||||
poolSource,
|
||||
poolDestination,
|
||||
userDestination,
|
||||
this.swapProgramId,
|
||||
this.tokenProgramId,
|
||||
amountIn,
|
||||
minimumAmountOut,
|
||||
),
|
||||
|
@ -372,10 +401,10 @@ export class TokenSwap {
|
|||
static swapInstruction(
|
||||
tokenSwap: PublicKey,
|
||||
authority: PublicKey,
|
||||
source: PublicKey,
|
||||
swapSource: PublicKey,
|
||||
swapDestination: PublicKey,
|
||||
destination: PublicKey,
|
||||
userSource: PublicKey,
|
||||
poolSource: PublicKey,
|
||||
poolDestination: PublicKey,
|
||||
userDestination: PublicKey,
|
||||
swapProgramId: PublicKey,
|
||||
tokenProgramId: PublicKey,
|
||||
amountIn: number | Numberu64,
|
||||
|
@ -400,10 +429,10 @@ export class TokenSwap {
|
|||
const keys = [
|
||||
{pubkey: tokenSwap, isSigner: false, isWritable: false},
|
||||
{pubkey: authority, isSigner: false, isWritable: false},
|
||||
{pubkey: source, isSigner: false, isWritable: true},
|
||||
{pubkey: swapSource, isSigner: false, isWritable: true},
|
||||
{pubkey: swapDestination, isSigner: false, isWritable: true},
|
||||
{pubkey: destination, isSigner: false, isWritable: true},
|
||||
{pubkey: userSource, isSigner: false, isWritable: true},
|
||||
{pubkey: poolSource, isSigner: false, isWritable: true},
|
||||
{pubkey: poolDestination, isSigner: false, isWritable: true},
|
||||
{pubkey: userDestination, isSigner: false, isWritable: true},
|
||||
{pubkey: tokenProgramId, isSigner: false, isWritable: false},
|
||||
];
|
||||
return new TransactionInstruction({
|
||||
|
@ -414,27 +443,18 @@ export class TokenSwap {
|
|||
}
|
||||
|
||||
/**
|
||||
* Deposit some tokens into the pool
|
||||
*
|
||||
* @param authority Authority
|
||||
* @param sourceA Source account A
|
||||
* @param sourceB Source account B
|
||||
* @param intoA Base account A to deposit into
|
||||
* @param intoB Base account B to deposit into
|
||||
* @param poolToken Pool token
|
||||
* @param poolAccount Pool account to deposit the generated tokens
|
||||
* @param tokenProgramId Token program id
|
||||
* @param amount Amount of pool token to deposit, token A and B amount are set by the exchange rate relative to the total pool token supply
|
||||
* Deposit tokens into the pool
|
||||
* @param userAccountA User account for token A
|
||||
* @param userAccountB User account for token B
|
||||
* @param poolAccount User account for pool token
|
||||
* @param poolTokenAmount Amount of pool tokens to mint
|
||||
* @param maximumTokenA The maximum amount of token A to deposit
|
||||
* @param maximumTokenB The maximum amount of token B to deposit
|
||||
*/
|
||||
async deposit(
|
||||
authority: PublicKey,
|
||||
sourceA: PublicKey,
|
||||
sourceB: PublicKey,
|
||||
intoA: PublicKey,
|
||||
intoB: PublicKey,
|
||||
poolToken: PublicKey,
|
||||
userAccountA: PublicKey,
|
||||
userAccountB: PublicKey,
|
||||
poolAccount: PublicKey,
|
||||
tokenProgramId: PublicKey,
|
||||
poolTokenAmount: number | Numberu64,
|
||||
maximumTokenA: number | Numberu64,
|
||||
maximumTokenB: number | Numberu64,
|
||||
|
@ -445,15 +465,15 @@ export class TokenSwap {
|
|||
new Transaction().add(
|
||||
TokenSwap.depositInstruction(
|
||||
this.tokenSwap,
|
||||
authority,
|
||||
sourceA,
|
||||
sourceB,
|
||||
intoA,
|
||||
intoB,
|
||||
poolToken,
|
||||
this.authority,
|
||||
userAccountA,
|
||||
userAccountB,
|
||||
this.tokenAccountA,
|
||||
this.tokenAccountB,
|
||||
this.poolToken,
|
||||
poolAccount,
|
||||
this.programId,
|
||||
tokenProgramId,
|
||||
this.swapProgramId,
|
||||
this.tokenProgramId,
|
||||
poolTokenAmount,
|
||||
maximumTokenA,
|
||||
maximumTokenB,
|
||||
|
@ -515,27 +535,19 @@ export class TokenSwap {
|
|||
}
|
||||
|
||||
/**
|
||||
* Withdraw the token from the pool at the current ratio
|
||||
* Withdraw tokens from the pool
|
||||
*
|
||||
* @param authority Authority
|
||||
* @param sourcePoolAccount Source pool account
|
||||
* @param poolToken Pool token
|
||||
* @param fromA Base account A to withdraw from
|
||||
* @param fromB Base account B to withdraw from
|
||||
* @param userAccountA Token A user account
|
||||
* @param userAccountB token B user account
|
||||
* @param tokenProgramId Token program id
|
||||
* @param amount Amount of pool token to withdraw, token A and B amount are set by the exchange rate relative to the total pool token supply
|
||||
* @param userAccountA User account for token A
|
||||
* @param userAccountB User account for token B
|
||||
* @param poolAccount User account for pool token
|
||||
* @param poolTokenAmount Amount of pool tokens to burn
|
||||
* @param minimumTokenA The minimum amount of token A to withdraw
|
||||
* @param minimumTokenB The minimum amount of token B to withdraw
|
||||
*/
|
||||
async withdraw(
|
||||
authority: PublicKey,
|
||||
poolMint: PublicKey,
|
||||
sourcePoolAccount: PublicKey,
|
||||
fromA: PublicKey,
|
||||
fromB: PublicKey,
|
||||
userAccountA: PublicKey,
|
||||
userAccountB: PublicKey,
|
||||
tokenProgramId: PublicKey,
|
||||
poolAccount: PublicKey,
|
||||
poolTokenAmount: number | Numberu64,
|
||||
minimumTokenA: number | Numberu64,
|
||||
minimumTokenB: number | Numberu64,
|
||||
|
@ -546,15 +558,15 @@ export class TokenSwap {
|
|||
new Transaction().add(
|
||||
TokenSwap.withdrawInstruction(
|
||||
this.tokenSwap,
|
||||
authority,
|
||||
poolMint,
|
||||
sourcePoolAccount,
|
||||
fromA,
|
||||
fromB,
|
||||
this.authority,
|
||||
this.poolToken,
|
||||
poolAccount,
|
||||
this.tokenAccountA,
|
||||
this.tokenAccountB,
|
||||
userAccountA,
|
||||
userAccountB,
|
||||
this.programId,
|
||||
tokenProgramId,
|
||||
this.swapProgramId,
|
||||
this.tokenProgramId,
|
||||
poolTokenAmount,
|
||||
minimumTokenA,
|
||||
minimumTokenB,
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
import type {Connection} from '@solana/web3.js';
|
||||
import {PublicKey} from '@solana/web3.js';
|
||||
|
||||
export async function loadAccount(
|
||||
connection: Connection,
|
||||
address: PublicKey,
|
||||
programId: PublicKey,
|
||||
): Buffer {
|
||||
const accountInfo = await connection.getAccountInfo(address);
|
||||
if (accountInfo === null) {
|
||||
throw new Error('Failed to find account');
|
||||
}
|
||||
|
||||
if (!accountInfo.owner.equals(programId)) {
|
||||
throw new Error(`Invalid owner: ${JSON.stringify(accountInfo.owner)}`);
|
||||
}
|
||||
|
||||
return Buffer.from(accountInfo.data);
|
||||
}
|
|
@ -16,23 +16,20 @@ declare module '@solana/spl-token-swap' {
|
|||
static fromBuffer(buffer: Buffer): Numberu64;
|
||||
}
|
||||
|
||||
export type TokenSwapInfo = {
|
||||
nonce: number;
|
||||
tokenAccountA: PublicKey;
|
||||
tokenAccountB: PublicKey;
|
||||
tokenPool: PublicKey;
|
||||
feesNumerator: Numberu64;
|
||||
feesDenominator: Numberu64;
|
||||
feeRatio: number;
|
||||
};
|
||||
|
||||
export const TokenSwapLayout: Layout;
|
||||
|
||||
export class TokenSwap {
|
||||
constructor(
|
||||
connection: Connection,
|
||||
swapProgramId: PublicKey,
|
||||
tokenProgramId: PublicKey,
|
||||
tokenSwap: PublicKey,
|
||||
programId: PublicKey,
|
||||
poolToken: PublicKey,
|
||||
authority: PublicKey,
|
||||
tokenAccountA: PublicKey,
|
||||
tokenAccountB: PublicKey,
|
||||
feeNumerator: Numberu64,
|
||||
feeDenominator: Numberu64,
|
||||
payer: Account,
|
||||
);
|
||||
|
||||
|
@ -54,6 +51,13 @@ declare module '@solana/spl-token-swap' {
|
|||
feeDenominator: number,
|
||||
): TransactionInstruction;
|
||||
|
||||
static loadTokenSwap(
|
||||
connection: Connection,
|
||||
address: PublicKey,
|
||||
programId: PublicKey,
|
||||
payer: Account,
|
||||
): Promise<TokenSwap>;
|
||||
|
||||
static createTokenSwap(
|
||||
connection: Connection,
|
||||
payer: Account,
|
||||
|
@ -70,15 +74,11 @@ declare module '@solana/spl-token-swap' {
|
|||
swapProgramId: PublicKey,
|
||||
): Promise<TokenSwap>;
|
||||
|
||||
getInfo(): Promise<TokenSwapInfo>;
|
||||
|
||||
swap(
|
||||
authority: PublicKey,
|
||||
source: PublicKey,
|
||||
swapSource: PublicKey,
|
||||
swapDestination: PublicKey,
|
||||
destination: PublicKey,
|
||||
tokenProgramId: PublicKey,
|
||||
userSource: PublicKey,
|
||||
poolSource: PublicKey,
|
||||
poolDestination: PublicKey,
|
||||
userDestination: PublicKey,
|
||||
amountIn: number | Numberu64,
|
||||
minimumAmountOut: number | Numberu64,
|
||||
): Promise<TransactionSignature>;
|
||||
|
@ -86,10 +86,10 @@ declare module '@solana/spl-token-swap' {
|
|||
static swapInstruction(
|
||||
tokenSwap: PublicKey,
|
||||
authority: PublicKey,
|
||||
source: PublicKey,
|
||||
swapSource: PublicKey,
|
||||
swapDestination: PublicKey,
|
||||
destination: PublicKey,
|
||||
userSource: PublicKey,
|
||||
poolSource: PublicKey,
|
||||
poolDestination: PublicKey,
|
||||
userDestination: PublicKey,
|
||||
swapProgramId: PublicKey,
|
||||
tokenProgramId: PublicKey,
|
||||
amountIn: number | Numberu64,
|
||||
|
|
|
@ -12,23 +12,20 @@ declare module '@solana/spl-token-swap' {
|
|||
static fromBuffer(buffer: Buffer): Numberu64;
|
||||
}
|
||||
|
||||
declare export type TokenSwapInfo = {|
|
||||
nonce: number,
|
||||
tokenAccountA: PublicKey,
|
||||
tokenAccountB: PublicKey,
|
||||
tokenPool: PublicKey,
|
||||
feesNumerator: Numberu64,
|
||||
feesDenominator: Numberu64,
|
||||
feeRatio: number,
|
||||
|};
|
||||
|
||||
declare export var TokenSwapLayout: Layout;
|
||||
|
||||
declare export class TokenSwap {
|
||||
constructor(
|
||||
connection: Connection,
|
||||
swapProgramId: PublicKey,
|
||||
tokenProgramId: PublicKey,
|
||||
tokenSwap: PublicKey,
|
||||
programId: PublicKey,
|
||||
poolToken: PublicKey,
|
||||
authority: PublicKey,
|
||||
tokenAccountA: PublicKey,
|
||||
tokenAccountB: PublicKey,
|
||||
feeNumerator: Numberu64,
|
||||
feeDenominator: Numberu64,
|
||||
payer: Account,
|
||||
): TokenSwap;
|
||||
|
||||
|
@ -50,6 +47,13 @@ declare module '@solana/spl-token-swap' {
|
|||
feeDenominator: number,
|
||||
): TransactionInstruction;
|
||||
|
||||
static loadTokenSwap(
|
||||
connection: Connection,
|
||||
address: PublicKey,
|
||||
programId: PublicKey,
|
||||
payer: Account,
|
||||
): Promise<TokenSwap>;
|
||||
|
||||
static createTokenSwap(
|
||||
connection: Connection,
|
||||
payer: Account,
|
||||
|
@ -66,15 +70,11 @@ declare module '@solana/spl-token-swap' {
|
|||
programId: PublicKey,
|
||||
): Promise<TokenSwap>;
|
||||
|
||||
getInfo(): Promise<TokenSwapInfo>;
|
||||
|
||||
swap(
|
||||
authority: PublicKey,
|
||||
source: PublicKey,
|
||||
swapSource: PublicKey,
|
||||
swapDestination: PublicKey,
|
||||
destination: PublicKey,
|
||||
tokenProgramId: PublicKey,
|
||||
userSource: PublicKey,
|
||||
poolSource: PublicKey,
|
||||
poolDestination: PublicKey,
|
||||
userDestination: PublicKey,
|
||||
amountIn: number | Numberu64,
|
||||
minimumAmountOut: number | Numberu64,
|
||||
): Promise<TransactionSignature>;
|
||||
|
@ -82,10 +82,10 @@ declare module '@solana/spl-token-swap' {
|
|||
static swapInstruction(
|
||||
tokenSwap: PublicKey,
|
||||
authority: PublicKey,
|
||||
source: PublicKey,
|
||||
swapSource: PublicKey,
|
||||
swapDestination: PublicKey,
|
||||
destination: PublicKey,
|
||||
userSource: PublicKey,
|
||||
poolSource: PublicKey,
|
||||
poolDestination: PublicKey,
|
||||
userDestination: PublicKey,
|
||||
swapProgramId: PublicKey,
|
||||
tokenProgramId: PublicKey,
|
||||
amountIn: number | Numberu64,
|
||||
|
|
|
@ -214,6 +214,7 @@ impl Processor {
|
|||
let obj = SwapInfo {
|
||||
is_initialized: true,
|
||||
nonce,
|
||||
token_program_id: *token_program_info.key,
|
||||
token_a: *token_a_info.key,
|
||||
token_b: *token_b_info.key,
|
||||
pool_mint: *pool_mint_info.key,
|
||||
|
|
|
@ -19,6 +19,10 @@ pub struct SwapInfo {
|
|||
/// authority over the swap's token A account, token B account, and pool
|
||||
/// token mint.
|
||||
pub nonce: u8,
|
||||
|
||||
/// Program ID of the tokens being exchanged.
|
||||
pub token_program_id: Pubkey,
|
||||
|
||||
/// Token A
|
||||
/// The Liquidity token is issued against this value.
|
||||
pub token_a: Pubkey,
|
||||
|
@ -27,6 +31,7 @@ pub struct SwapInfo {
|
|||
/// Pool tokens are issued when A or B tokens are deposited.
|
||||
/// Pool tokens can be withdrawn back to the original A or B token.
|
||||
pub pool_mint: Pubkey,
|
||||
|
||||
/// Numerator of fee applied to the input token amount prior to output calculation.
|
||||
pub fee_numerator: u64,
|
||||
/// Denominator of fee applied to the input token amount prior to output calculation.
|
||||
|
@ -41,14 +46,22 @@ impl IsInitialized for SwapInfo {
|
|||
}
|
||||
|
||||
impl Pack for SwapInfo {
|
||||
const LEN: usize = 114;
|
||||
const LEN: usize = 146;
|
||||
|
||||
/// Unpacks a byte buffer into a [SwapInfo](struct.SwapInfo.html).
|
||||
fn unpack_from_slice(input: &[u8]) -> Result<Self, ProgramError> {
|
||||
let input = array_ref![input, 0, 114];
|
||||
let input = array_ref![input, 0, 146];
|
||||
#[allow(clippy::ptr_offset_with_cast)]
|
||||
let (is_initialized, nonce, token_a, token_b, pool_mint, fee_numerator, fee_denominator) =
|
||||
array_refs![input, 1, 1, 32, 32, 32, 8, 8];
|
||||
let (
|
||||
is_initialized,
|
||||
nonce,
|
||||
token_program_id,
|
||||
token_a,
|
||||
token_b,
|
||||
pool_mint,
|
||||
fee_numerator,
|
||||
fee_denominator,
|
||||
) = array_refs![input, 1, 1, 32, 32, 32, 32, 8, 8];
|
||||
Ok(Self {
|
||||
is_initialized: match is_initialized {
|
||||
[0] => false,
|
||||
|
@ -56,6 +69,7 @@ impl Pack for SwapInfo {
|
|||
_ => return Err(ProgramError::InvalidAccountData),
|
||||
},
|
||||
nonce: nonce[0],
|
||||
token_program_id: Pubkey::new_from_array(*token_program_id),
|
||||
token_a: Pubkey::new_from_array(*token_a),
|
||||
token_b: Pubkey::new_from_array(*token_b),
|
||||
pool_mint: Pubkey::new_from_array(*pool_mint),
|
||||
|
@ -65,11 +79,20 @@ impl Pack for SwapInfo {
|
|||
}
|
||||
|
||||
fn pack_into_slice(&self, output: &mut [u8]) {
|
||||
let output = array_mut_ref![output, 0, 114];
|
||||
let (is_initialized, nonce, token_a, token_b, pool_mint, fee_numerator, fee_denominator) =
|
||||
mut_array_refs![output, 1, 1, 32, 32, 32, 8, 8];
|
||||
let output = array_mut_ref![output, 0, 146];
|
||||
let (
|
||||
is_initialized,
|
||||
nonce,
|
||||
token_program_id,
|
||||
token_a,
|
||||
token_b,
|
||||
pool_mint,
|
||||
fee_numerator,
|
||||
fee_denominator,
|
||||
) = mut_array_refs![output, 1, 1, 32, 32, 32, 32, 8, 8];
|
||||
is_initialized[0] = self.is_initialized as u8;
|
||||
nonce[0] = self.nonce;
|
||||
token_program_id.copy_from_slice(self.token_program_id.as_ref());
|
||||
token_a.copy_from_slice(self.token_a.as_ref());
|
||||
token_b.copy_from_slice(self.token_b.as_ref());
|
||||
pool_mint.copy_from_slice(self.pool_mint.as_ref());
|
||||
|
@ -85,9 +108,11 @@ mod tests {
|
|||
#[test]
|
||||
fn test_swap_info_packing() {
|
||||
let nonce = 255;
|
||||
let token_program_id_raw = [1u8; 32];
|
||||
let token_a_raw = [1u8; 32];
|
||||
let token_b_raw = [2u8; 32];
|
||||
let pool_mint_raw = [3u8; 32];
|
||||
let token_program_id = Pubkey::new_from_array(token_program_id_raw);
|
||||
let token_a = Pubkey::new_from_array(token_a_raw);
|
||||
let token_b = Pubkey::new_from_array(token_b_raw);
|
||||
let pool_mint = Pubkey::new_from_array(pool_mint_raw);
|
||||
|
@ -97,6 +122,7 @@ mod tests {
|
|||
let swap_info = SwapInfo {
|
||||
is_initialized,
|
||||
nonce,
|
||||
token_program_id,
|
||||
token_a,
|
||||
token_b,
|
||||
pool_mint,
|
||||
|
@ -112,6 +138,7 @@ mod tests {
|
|||
let mut packed = vec![];
|
||||
packed.push(1 as u8);
|
||||
packed.push(nonce);
|
||||
packed.extend_from_slice(&token_program_id_raw);
|
||||
packed.extend_from_slice(&token_a_raw);
|
||||
packed.extend_from_slice(&token_b_raw);
|
||||
packed.extend_from_slice(&pool_mint_raw);
|
||||
|
|
Loading…
Reference in New Issue