123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369 |
- import {
- Account,
- AssociatedTokenAccount,
- Constraint,
- Mint,
- PoseidonError,
- Pubkey,
- Seeds,
- Signer,
- TokenAccount,
- TokenProgram,
- i64,
- u8,
- u16,
- u64,
- } from '@solanaturbine/poseidon';
- //Poseidon cannot support custom instructions currently , so most of the amm logic has been commented out
- export default class tokenSwap {
- static PROGRAM_ID = new Pubkey('3dDaJxmPcmQVfSx9rX4xHyP5rJvkwdKcNujcX2z9KB9h');
- create_amm(payer: Signer, amm: AMM, admin: Admin, id: u64, fee: u16) {
- amm
- .derive([id.toBytes()])
- //Custom constraints don't transpile to corresponding anchor constraints yet
- .constraints([new Constraint(fee < new u16(10000), new PoseidonError('invalid fee'))])
- .init();
- admin.derive(['admin']).init();
- amm.id = id;
- amm.admin = admin.key;
- amm.fee = fee;
- }
- create_pool(
- payer: Signer,
- amm: AMM,
- pool: Pool,
- pool_authority: PoolAuthority,
- pool_account_a: AssociatedTokenAccount,
- pool_account_b: AssociatedTokenAccount,
- mint_liquidity: Mint,
- mint_a: Mint,
- mint_b: Mint,
- id: u64,
- ) {
- amm.derive([id.toBytes()]).init();
- pool.derive([amm.key, mint_a.key, mint_b.key]).init();
- pool_authority.derive([amm.key, mint_a.key, mint_b.key, 'authority']);
- mint_liquidity.derive([amm.key, mint_a.key, mint_b.key, 'liquidity']).init();
- pool_account_a.derive(mint_a, pool_authority.key).init();
- pool_account_b.derive(mint_b, pool_authority.key).init();
- pool.amm = amm.key;
- pool.mint_a = mint_a.key;
- pool.mint_b = mint_b.key;
- }
- // The liquidity is a constant value here for testing purposes since theres no way to make custom logic
- deposit_liquidity(
- payer: Signer,
- depositor: Signer,
- pool: Pool,
- pool_authority: PoolAuthority,
- pool_account_a: AssociatedTokenAccount,
- pool_account_b: AssociatedTokenAccount,
- depositor_account_a: AssociatedTokenAccount,
- depositor_account_b: AssociatedTokenAccount,
- depositor_account_liquidity: AssociatedTokenAccount,
- amm: AMM,
- mint_liquidity: Mint,
- mint_a: Mint,
- mint_b: Mint,
- amount_a: u64,
- amount_b: u64,
- ) {
- pool.derive([amm.key, mint_a.key, mint_b.key]).has([mint_a, mint_b]);
- pool_authority.derive([amm.key, mint_a.key, mint_b.key, 'authority']);
- mint_liquidity.derive([amm.key, mint_a.key, mint_b.key, 'liquidity']).init();
- pool_account_a.derive(mint_a, pool_authority.key).init();
- pool_account_b.derive(mint_b, pool_authority.key).init();
- depositor_account_liquidity.derive(mint_liquidity, depositor.key).init();
- depositor_account_a.derive(mint_a, depositor.key).init();
- depositor_account_b.derive(mint_b, depositor.key).init();
- // prevent depositing assets the depositor does not own
- // let amount_a = new i64(amount_a); // Set from actual initial value for `amount_a`
- // let amount_b = new i64(amount_b); // Set from actual initial value for `amount_b`
- // const depositor_account_a_amount = new i64(depositor_account_a.amount);
- // const depositor_account_b_amount = new i64(depositor_account_b.amount);
- // // Limit `amount_a` and `amount_b` to the depositor account balances
- // if (amount_a.gt(depositor_account_a_amount)) {
- // amount_a = depositor_account_a_amount;
- // }
- // if (amount_b.gt(depositor_account_b_amount)) {
- // amount_b = depositor_account_b_amount;
- // }
- // // Define pool account balances
- // const pool_account_a_amount = new i64(pool_account_a.amount);
- // const pool_account_b_amount = new i64(pool_account_b.amount);
- // // Check if pool creation is happening (no liquidity yet)
- // const pool_creation =
- // pool_account_a_amount.eq(new i64(0)) &&
- // pool_account_b_amount.eq(new i64(0));
- // // Calculate `amount_a` and `amount_b` based on existing liquidity
- // if (pool_creation) {
- // // If creating a new pool, add `amount_a` and `amount_b` as is
- // // (already limited by depositor account balances above)
- // } else {
- // // Calculate the pool ratio to maintain proper liquidity proportions
- // const ratio = pool_account_a_amount.mul(pool_account_b_amount);
- // if (pool_account_a_amount.gt(pool_account_b_amount)) {
- // amount_a = amount_b.mul(ratio).toNum();
- // } else {
- // amount_b = amount_a.div(ratio).toNum();
- // }
- // }
- // Computing the amount of liquidity about to be deposited
- // let liquidity = new i64(amount_a)
- // .mul(new i64(amount_b))
- // .sqrt()
- // if pool_creation {
- // if liquidity < MINIMUM_LIQUIDITY {
- // return new PoseidonError("DepositTooSmall");
- // }
- // liquidity -= MINIMUM_LIQUIDITY;
- // }
- // let liquidity = amount_a.mul(Number(amount_b));
- // Transfer tokens to the pool;
- // TokenProgram.transfer(
- // depositor_account_a,
- // pool_account_a,
- // depositor,
- // amount_a
- // );
- // TokenProgram.transfer(
- // depositor_account_b,
- // pool_account_b,
- // depositor,
- // amount_b
- // );
- // // mint the liquidity to the user
- // TokenProgram.mintTo(
- // mint_liquidity,
- // depositor_account_liquidity,
- // pool_authority,
- // liquidity
- // );
- }
- swap_exact_tokens_for_tokens(
- payer: Signer,
- trader: Signer,
- pool: Pool,
- pool_authority: PoolAuthority,
- pool_account_a: AssociatedTokenAccount,
- pool_account_b: AssociatedTokenAccount,
- trader_account_a: AssociatedTokenAccount,
- trader_account_b: AssociatedTokenAccount,
- amm: AMM,
- mint_a: Mint,
- mint_b: Mint,
- fee: u16,
- amount_a: u64,
- amount_b: u64,
- // swap_a:bool
- input_amount: u64,
- min_input_amount: u64,
- id: u64,
- ) {
- amm.derive([id.toBytes()]);
- pool.derive([amm.key, mint_a.key, mint_b.key]).has([amm, mint_a, mint_b]);
- pool_authority.derive([amm.key, mint_a.key, mint_b.key, 'authority']);
- pool_account_a.derive(mint_a, pool_authority.key).init();
- pool_account_b.derive(mint_b, pool_authority.key).init();
- trader_account_a.derive(mint_a, trader.key).init();
- trader_account_b.derive(mint_b, trader.key).init();
- // Prevent depositing assets the depositor does not own
- // let input;
- // if (swap_a && input_amount.gt(trader_account_a.amount)) {
- // input = trader_account_a.amount;
- // } else if (!swap_a && input_amount.gt(trader_account_b.amount)) {
- // input = trader_account_b.amount;
- // } else {
- // input = input_amount;
- // }
- // // Apply trading fee, used to compute the output
- // const taxed_input = input.sub(input.mul(amm.fee).div(new i64(10000)));
- // // Define pool accounts
- // const pool_a = pool_account_a;
- // const pool_b = pool_account_b;
- // // Calculate output based on the pool and trading direction
- // let output;
- // if (swap_a) {
- // output = taxed_input
- // .mul(pool_b.amount)
- // .div(pool_a.amount.add(taxed_input))
- // .toNum();
- // } else {
- // output = taxed_input
- // .mul(pool_a.amount)
- // .div(pool_b.amount.add(taxed_input))
- // .toNum();
- // }
- // // Ensure output is greater than the minimum required output
- // if (output.lt(min_output_amount)) {
- // throw new Error("OutputTooSmall");
- // }
- // // Compute the invariant before the trade
- // const invariant = pool_a.amount.mul(pool_b.amount);
- //Transfer tokens to the pool
- // if (swap_a) {
- // TokenProgram.transfer(
- // trader_account_a,
- // pool_account_a,
- // trader,
- // input
- // )
- // TokenProgram.transfer(
- // pool_account_a,
- // trader_account_a,
- // pool_authority,
- // output
- // )
- // } else {
- // TokenProgram.transfer(
- // pool_account_a,
- // trader_account_a,
- // pool_authority,
- // input
- // )
- // TokenProgram.transfer(
- // trader_account_b,
- // pool_account_b,
- // trader,
- // output
- // )
- // }
- // Verify the invariant still holds
- // Reload accounts because of the CPIs
- // We tolerate if the new invariant is higher because it means a rounding error for LPs
- //pool_account_a.reload()
- //pool_account_b.reload()
- // if invariant > pool_account_a.amount.mul(pool_account_a.amount) {
- // return new PoseidonErr("Invariant Violated");
- // }
- }
- withdraw_liquidity(
- payer: Signer,
- depositor: Signer,
- pool: Pool,
- pool_authority: PoolAuthority,
- pool_account_a: AssociatedTokenAccount,
- pool_account_b: AssociatedTokenAccount,
- depositor_account_a: AssociatedTokenAccount,
- depositor_account_b: AssociatedTokenAccount,
- depositor_account_liquidity: AssociatedTokenAccount,
- amm: AMM,
- mint_liquidity: Mint,
- mint_a: Mint,
- mint_b: Mint,
- amount: u64,
- id: u64,
- ) {
- amm.derive([id.toBytes()]);
- pool.derive([amm.key, mint_a.key, mint_b.key]).has([mint_a, mint_b]);
- pool_authority.derive([amm.key, mint_a.key, mint_b.key, 'authority']);
- pool_account_a.derive(mint_a, pool_authority.key).init();
- pool_account_b.derive(mint_b, pool_authority.key).init();
- pool_account_a.derive(mint_a, pool_authority.key).init();
- pool_account_b.derive(mint_b, pool_authority.key).init();
- depositor_account_liquidity.derive(mint_liquidity, depositor.key).init();
- depositor_account_a.derive(mint_a, depositor.key).initIfNeeded();
- depositor_account_b.derive(mint_b, depositor.key).initIfNeeded();
- // let MINIMUM_LIQUIDITY = 1;
- // Transfer tokens from the pool
- // let amount_a = new i64(amount)
- // .mul(new i64(pool_account_a.amount))
- // .div(new i64(mint_liquidity.supply.add(MINIMUM_LIQUIDITY)))
- // .floor()
- // .toNum();
- // TokenProgram.transfer(
- // pool_account_a,
- // depositor_account_a,
- // pool_authority,
- // amount_a
- // )
- // let amount_b = new i64(amount)
- // .mul(new i64(pool_account_b.amount))
- // .div(new i64(mint_liquidity.supply.add(MINIMUM_LIQUIDITY)))
- // .floor()
- // .toNum();
- // TokenProgram.transfer(
- // pool_account_b,
- // depositor_account_b,
- // pool_authority,
- // amount_b
- // );
- // TokenProgram.burn(
- // mint_liquidity,
- // depositor_account_liquidity,
- // depositor,
- // amount
- // );
- }
- }
- export interface AMM extends Account {
- /// The primary key of the AMM
- id: u64;
- /// Account that has admin authority over the AMM
- admin: Pubkey;
- /// The LP fee taken on each trade, in basis points
- fee: u16;
- }
- export interface Pool extends Account {
- /// Primary key of the AMM
- amm: Pubkey;
- /// Mint of token A
- mint_a: Pubkey;
- /// Mint of token B
- mint_b: Pubkey;
- }
- // The admin of the AMM
- //Read only delegatable creation
- export interface Admin extends Account {}
- //Read only authority
- export interface PoolAuthority extends Account {}
|