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:
Yutaro Mori 2020-10-14 19:37:58 +09:00 committed by GitHub
parent b45e3bf00c
commit 5f56635fde
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 310 additions and 259 deletions

10
Cargo.lock generated
View File

@ -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",
]

View File

@ -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,
);

View File

@ -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,

View File

@ -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);
}

View File

@ -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,

View File

@ -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,

View File

@ -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,

View File

@ -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);