@w3lib/solana-batch-call 0.4.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +45 -0
- package/README.md +343 -3
- package/dist/approvals.d.ts +129 -0
- package/dist/approvals.d.ts.map +1 -0
- package/dist/approvals.js +221 -0
- package/dist/approvals.js.map +1 -0
- package/dist/batchPlan.d.ts +52 -0
- package/dist/batchPlan.d.ts.map +1 -0
- package/dist/batchPlan.js +85 -0
- package/dist/batchPlan.js.map +1 -0
- package/dist/claim.d.ts +161 -0
- package/dist/claim.d.ts.map +1 -0
- package/dist/claim.js +197 -0
- package/dist/claim.js.map +1 -0
- package/dist/decode.d.ts +22 -0
- package/dist/decode.d.ts.map +1 -0
- package/dist/decode.js +187 -0
- package/dist/decode.js.map +1 -0
- package/dist/describe.d.ts +26 -0
- package/dist/describe.d.ts.map +1 -0
- package/dist/describe.js +58 -0
- package/dist/describe.js.map +1 -0
- package/dist/fees.d.ts +89 -0
- package/dist/fees.d.ts.map +1 -0
- package/dist/fees.js +166 -0
- package/dist/fees.js.map +1 -0
- package/dist/history.d.ts +125 -0
- package/dist/history.d.ts.map +1 -0
- package/dist/history.js +231 -0
- package/dist/history.js.map +1 -0
- package/dist/historyHelius.d.ts +52 -0
- package/dist/historyHelius.d.ts.map +1 -0
- package/dist/historyHelius.js +125 -0
- package/dist/historyHelius.js.map +1 -0
- package/dist/layout.d.ts +2 -0
- package/dist/layout.d.ts.map +1 -1
- package/dist/layout.js +2 -2
- package/dist/layout.js.map +1 -1
- package/dist/liquidity/orca.d.ts +6 -0
- package/dist/liquidity/orca.d.ts.map +1 -1
- package/dist/liquidity/orca.js +14 -3
- package/dist/liquidity/orca.js.map +1 -1
- package/dist/liquidity/raydiumClmm.d.ts +6 -0
- package/dist/liquidity/raydiumClmm.d.ts.map +1 -1
- package/dist/liquidity/raydiumClmm.js +12 -5
- package/dist/liquidity/raydiumClmm.js.map +1 -1
- package/dist/lp.d.ts +55 -15
- package/dist/lp.d.ts.map +1 -1
- package/dist/lp.js +98 -46
- package/dist/lp.js.map +1 -1
- package/dist/lpMath.d.ts +22 -0
- package/dist/lpMath.d.ts.map +1 -1
- package/dist/lpMath.js +21 -0
- package/dist/lpMath.js.map +1 -1
- package/dist/names.d.ts +68 -0
- package/dist/names.d.ts.map +1 -0
- package/dist/names.js +257 -0
- package/dist/names.js.map +1 -0
- package/dist/pools.d.ts +9 -0
- package/dist/pools.d.ts.map +1 -0
- package/dist/pools.js +45 -0
- package/dist/pools.js.map +1 -0
- package/dist/portfolio.d.ts +64 -0
- package/dist/portfolio.d.ts.map +1 -0
- package/dist/portfolio.js +57 -0
- package/dist/portfolio.js.map +1 -0
- package/dist/price.d.ts +90 -0
- package/dist/price.d.ts.map +1 -0
- package/dist/price.js +287 -0
- package/dist/price.js.map +1 -0
- package/dist/programs.d.ts +19 -0
- package/dist/programs.d.ts.map +1 -0
- package/dist/programs.js +175 -0
- package/dist/programs.js.map +1 -0
- package/dist/reclaim.d.ts +190 -0
- package/dist/reclaim.d.ts.map +1 -0
- package/dist/reclaim.js +399 -0
- package/dist/reclaim.js.map +1 -0
- package/dist/risk.d.ts +84 -0
- package/dist/risk.d.ts.map +1 -0
- package/dist/risk.js +211 -0
- package/dist/risk.js.map +1 -0
- package/dist/rpc.d.ts +2 -0
- package/dist/rpc.d.ts.map +1 -1
- package/dist/rpc.js +36 -10
- package/dist/rpc.js.map +1 -1
- package/dist/simulate.d.ts +106 -0
- package/dist/simulate.d.ts.map +1 -0
- package/dist/simulate.js +418 -0
- package/dist/simulate.js.map +1 -0
- package/dist/subpaths/approvals.d.ts +29 -0
- package/dist/subpaths/approvals.d.ts.map +1 -0
- package/dist/subpaths/approvals.js +30 -0
- package/dist/subpaths/approvals.js.map +1 -0
- package/dist/subpaths/claim.d.ts +31 -0
- package/dist/subpaths/claim.d.ts.map +1 -0
- package/dist/subpaths/claim.js +31 -0
- package/dist/subpaths/claim.js.map +1 -0
- package/dist/subpaths/fees.d.ts +23 -0
- package/dist/subpaths/fees.d.ts.map +1 -0
- package/dist/subpaths/fees.js +25 -0
- package/dist/subpaths/fees.js.map +1 -0
- package/dist/subpaths/history.d.ts +21 -0
- package/dist/subpaths/history.d.ts.map +1 -0
- package/dist/subpaths/history.js +22 -0
- package/dist/subpaths/history.js.map +1 -0
- package/dist/subpaths/lp.d.ts +2 -2
- package/dist/subpaths/lp.d.ts.map +1 -1
- package/dist/subpaths/lp.js +2 -2
- package/dist/subpaths/lp.js.map +1 -1
- package/dist/subpaths/names.d.ts +37 -0
- package/dist/subpaths/names.d.ts.map +1 -0
- package/dist/subpaths/names.js +27 -0
- package/dist/subpaths/names.js.map +1 -0
- package/dist/subpaths/price.d.ts +40 -0
- package/dist/subpaths/price.d.ts.map +1 -0
- package/dist/subpaths/price.js +43 -0
- package/dist/subpaths/price.js.map +1 -0
- package/dist/subpaths/reclaim.d.ts +34 -0
- package/dist/subpaths/reclaim.d.ts.map +1 -0
- package/dist/subpaths/reclaim.js +34 -0
- package/dist/subpaths/reclaim.js.map +1 -0
- package/dist/subpaths/risk.d.ts +28 -0
- package/dist/subpaths/risk.d.ts.map +1 -0
- package/dist/subpaths/risk.js +30 -0
- package/dist/subpaths/risk.js.map +1 -0
- package/dist/subpaths/simulate.d.ts +22 -0
- package/dist/subpaths/simulate.d.ts.map +1 -0
- package/dist/subpaths/simulate.js +23 -0
- package/dist/subpaths/simulate.js.map +1 -0
- package/dist/subpaths/swap.d.ts +22 -0
- package/dist/subpaths/swap.d.ts.map +1 -0
- package/dist/subpaths/swap.js +21 -0
- package/dist/subpaths/swap.js.map +1 -0
- package/dist/subpaths/write.d.ts +1 -1
- package/dist/subpaths/write.d.ts.map +1 -1
- package/dist/subpaths/write.js +1 -1
- package/dist/subpaths/write.js.map +1 -1
- package/dist/swap/amm.d.ts +20 -0
- package/dist/swap/amm.d.ts.map +1 -0
- package/dist/swap/amm.js +77 -0
- package/dist/swap/amm.js.map +1 -0
- package/dist/swap/clmmMath.d.ts +24 -0
- package/dist/swap/clmmMath.d.ts.map +1 -0
- package/dist/swap/clmmMath.js +82 -0
- package/dist/swap/clmmMath.js.map +1 -0
- package/dist/swap/common.d.ts +68 -0
- package/dist/swap/common.d.ts.map +1 -0
- package/dist/swap/common.js +65 -0
- package/dist/swap/common.js.map +1 -0
- package/dist/swap/cpmm.d.ts +28 -0
- package/dist/swap/cpmm.d.ts.map +1 -0
- package/dist/swap/cpmm.js +113 -0
- package/dist/swap/cpmm.js.map +1 -0
- package/dist/swap/index.d.ts +145 -0
- package/dist/swap/index.d.ts.map +1 -0
- package/dist/swap/index.js +349 -0
- package/dist/swap/index.js.map +1 -0
- package/dist/swap/orca.d.ts +50 -0
- package/dist/swap/orca.d.ts.map +1 -0
- package/dist/swap/orca.js +382 -0
- package/dist/swap/orca.js.map +1 -0
- package/dist/swap/raydiumClmm.d.ts +62 -0
- package/dist/swap/raydiumClmm.d.ts.map +1 -0
- package/dist/swap/raydiumClmm.js +447 -0
- package/dist/swap/raydiumClmm.js.map +1 -0
- package/dist/tradeCheck.d.ts +45 -0
- package/dist/tradeCheck.d.ts.map +1 -0
- package/dist/tradeCheck.js +131 -0
- package/dist/tradeCheck.js.map +1 -0
- package/dist/write/instructions.d.ts +9 -0
- package/dist/write/instructions.d.ts.map +1 -1
- package/dist/write/instructions.js +40 -1
- package/dist/write/instructions.js.map +1 -1
- package/dist/write/transaction.d.ts +23 -0
- package/dist/write/transaction.d.ts.map +1 -1
- package/dist/write/transaction.js +50 -0
- package/dist/write/transaction.js.map +1 -1
- package/package.json +66 -14
- package/src/approvals.ts +358 -0
- package/src/batchPlan.ts +137 -0
- package/src/claim.ts +323 -0
- package/src/decode.ts +202 -0
- package/src/describe.ts +77 -0
- package/src/fees.ts +259 -0
- package/src/history.ts +336 -0
- package/src/historyHelius.ts +136 -0
- package/src/layout.ts +2 -2
- package/src/liquidity/orca.ts +15 -5
- package/src/liquidity/raydiumClmm.ts +13 -5
- package/src/lp.ts +148 -59
- package/src/lpMath.ts +38 -0
- package/src/names.ts +329 -0
- package/src/pools.ts +43 -0
- package/src/portfolio.ts +124 -0
- package/src/price.ts +366 -0
- package/src/programs.ts +216 -0
- package/src/reclaim.ts +547 -0
- package/src/risk.ts +243 -0
- package/src/rpc.ts +39 -10
- package/src/simulate.ts +535 -0
- package/src/subpaths/approvals.ts +47 -0
- package/src/subpaths/claim.ts +53 -0
- package/src/subpaths/fees.ts +41 -0
- package/src/subpaths/history.ts +38 -0
- package/src/subpaths/lp.ts +5 -1
- package/src/subpaths/names.ts +45 -0
- package/src/subpaths/price.ts +62 -0
- package/src/subpaths/reclaim.ts +57 -0
- package/src/subpaths/risk.ts +36 -0
- package/src/subpaths/simulate.ts +37 -0
- package/src/subpaths/swap.ts +41 -0
- package/src/subpaths/write.ts +2 -0
- package/src/swap/amm.ts +88 -0
- package/src/swap/clmmMath.ts +96 -0
- package/src/swap/common.ts +113 -0
- package/src/swap/cpmm.ts +132 -0
- package/src/swap/index.ts +467 -0
- package/src/swap/orca.ts +397 -0
- package/src/swap/raydiumClmm.ts +464 -0
- package/src/tradeCheck.ts +166 -0
- package/src/write/instructions.ts +43 -1
- package/src/write/transaction.ts +62 -0
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { TOKEN_2022_PROGRAM_ID, TOKEN_PROGRAM_ID } from '../constants.js'
|
|
2
|
+
import { findExtension, parseMint, parseTransferFeeConfig, type AccountInfo } from '../layout.js'
|
|
3
|
+
import { Bytes } from '../lp.js'
|
|
4
|
+
import type { Instruction } from '../write/transaction.js'
|
|
5
|
+
|
|
6
|
+
export type SolanaSwapProtocol = 'raydium-clmm' | 'orca-whirlpool' | 'raydium-cpmm' | 'raydium-amm'
|
|
7
|
+
|
|
8
|
+
/** 报价时的链上环境:Clock sysvar 的时间(秒)和 epoch(Token-2022 转账手续费按 epoch 选配置;动态费率按时间衰减) */
|
|
9
|
+
export interface SwapEnv {
|
|
10
|
+
timestamp: bigint
|
|
11
|
+
epoch: bigint
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export const CLOCK_SYSVAR_ID = 'SysvarC1ock11111111111111111111111111111111'
|
|
15
|
+
|
|
16
|
+
/** Clock:slot u64、epoch_start_timestamp i64、epoch u64、leader_schedule_epoch u64、unix_timestamp i64 */
|
|
17
|
+
export function parseClock(data: Uint8Array): SwapEnv {
|
|
18
|
+
if (data.length < 40) throw new Error('Unexpected Clock sysvar data')
|
|
19
|
+
const view = new DataView(data.buffer, data.byteOffset, data.byteLength)
|
|
20
|
+
return { epoch: view.getBigUint64(16, true), timestamp: view.getBigInt64(32, true) }
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** 读到的账户:address → 账户(不存在为 null);没读的为 undefined */
|
|
24
|
+
export type AccountGetter = (address: string) => AccountInfo | null | undefined
|
|
25
|
+
|
|
26
|
+
/** 池子不支持本地报价 / 兑换(跳过这个池子,原因在 plan 里能看到) */
|
|
27
|
+
export class UnsupportedPool extends Error {}
|
|
28
|
+
|
|
29
|
+
/** 报价还需要读这些账户(如兑换走得比预读的 tick 数组更远):读完后重新报价 */
|
|
30
|
+
export class NeedAccounts extends Error {
|
|
31
|
+
constructor(readonly addresses: string[]) {
|
|
32
|
+
super(`Need ${addresses.length} more accounts`)
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export const U64_MAX = (1n << 64n) - 1n
|
|
37
|
+
export const mulDivFloor = (a: bigint, b: bigint, d: bigint) => (a * b) / d
|
|
38
|
+
export const mulDivCeil = (a: bigint, b: bigint, d: bigint) => (a * b + d - 1n) / d
|
|
39
|
+
|
|
40
|
+
export function need(get: AccountGetter, address: string, what: string): AccountInfo {
|
|
41
|
+
const account = get(address)
|
|
42
|
+
if (account === undefined) throw new Error(`${what} was not loaded: ${address}`)
|
|
43
|
+
if (account === null) throw new UnsupportedPool(`${what} not found: ${address}`)
|
|
44
|
+
return account
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** 交易里要用的代币信息 */
|
|
48
|
+
export interface SwapMint {
|
|
49
|
+
mint: string
|
|
50
|
+
program: string
|
|
51
|
+
decimals: number
|
|
52
|
+
/** 原始 mint 账户(算 Token-2022 转账手续费) */
|
|
53
|
+
account: AccountInfo
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const EXTENSION_TRANSFER_HOOK = 14
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* 解析池子里一种代币的 mint:SPL Token / Token-2022;带转账 hook(需要额外账户)的不支持。
|
|
60
|
+
* 带转账手续费的支持(按当前 epoch 的费率算)
|
|
61
|
+
*/
|
|
62
|
+
export function swapMint(mint: string, account: AccountInfo): SwapMint {
|
|
63
|
+
if (account.owner !== TOKEN_PROGRAM_ID && account.owner !== TOKEN_2022_PROGRAM_ID) {
|
|
64
|
+
throw new UnsupportedPool(`${mint} is not a token mint`)
|
|
65
|
+
}
|
|
66
|
+
if (account.owner === TOKEN_2022_PROGRAM_ID) {
|
|
67
|
+
const hook = findExtension(account.data, EXTENSION_TRANSFER_HOOK)
|
|
68
|
+
if (hook && hook.length >= 64 && hook.subarray(32, 64).some((b) => b !== 0)) {
|
|
69
|
+
throw new UnsupportedPool(`${mint} has a transfer hook, which is not supported`)
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return { mint, program: account.owner, decimals: parseMint(account.data).decimals, account }
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** Token-2022 转账手续费:ceil(amount × 费率 / 10000),不超过单笔上限;SPL Token 为 0(与 Token-2022 的 calculate_epoch_fee 一致) */
|
|
76
|
+
export function transferFee(mint: SwapMint, amount: bigint, epoch: bigint): bigint {
|
|
77
|
+
if (mint.program !== TOKEN_2022_PROGRAM_ID || amount === 0n) return 0n
|
|
78
|
+
const config = parseTransferFeeConfig(mint.account.data)
|
|
79
|
+
if (!config) return 0n
|
|
80
|
+
const fee = epoch >= config.newer.epoch ? config.newer : config.older
|
|
81
|
+
if (fee.basisPoints === 0) return 0n
|
|
82
|
+
const raw = (amount * BigInt(fee.basisPoints) + 9999n) / 10000n
|
|
83
|
+
return raw < fee.maximumFee ? raw : fee.maximumFee
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** 一跳的报价:用户付出 amountIn(含输入代币的转账手续费),实际收到 amountOut(已扣输出代币的转账手续费) */
|
|
87
|
+
export interface HopQuote {
|
|
88
|
+
amountIn: bigint
|
|
89
|
+
amountOut: bigint
|
|
90
|
+
/** 交易里要传的额外账户(tick 数组等),由各协议的 instruction 使用 */
|
|
91
|
+
accounts: string[]
|
|
92
|
+
/** 集中流动性:穿过的已初始化 tick 数、成交的限价单 tick 数(Raydium) */
|
|
93
|
+
crossed?: number
|
|
94
|
+
orders?: number
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/** 一个可以兑换的池子(已解析) */
|
|
98
|
+
export interface SwapPool {
|
|
99
|
+
protocol: SolanaSwapProtocol
|
|
100
|
+
address: string
|
|
101
|
+
mint0: string
|
|
102
|
+
mint1: string
|
|
103
|
+
/** 报价要读的账户(池子账户之外):按方向(zeroForOne:卖出 mint0) */
|
|
104
|
+
accounts(zeroForOne: boolean): string[]
|
|
105
|
+
/** 本地报价(只用读到的账户,纯计算);池子不支持时抛 UnsupportedPool */
|
|
106
|
+
quote(get: AccountGetter, amountIn: bigint, zeroForOne: boolean, env: SwapEnv): HopQuote
|
|
107
|
+
/** 兑换指令:从 input 代币账户卖出 amountIn,output 代币账户至少收到 minOut */
|
|
108
|
+
instruction(get: AccountGetter, owner: string, input: string, output: string, zeroForOne: boolean, quote: HopQuote, minOut: bigint): Instruction
|
|
109
|
+
/** 两种代币的 mint 信息(报价后可用) */
|
|
110
|
+
mints(get: AccountGetter): [SwapMint, SwapMint]
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export { Bytes }
|
package/src/swap/cpmm.ts
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Raydium CPMM 的兑换:swap_base_input。报价照搬程序(raydium-cp-swap curve/calculator.rs):
|
|
3
|
+
* 交易费(含创建者手续费,从输入或输出扣)向上取整,恒定乘积向下取整,储备 = 金库余额 − 协议 / 基金 / 创建者手续费;输入输出的 Token-2022 转账手续费都算
|
|
4
|
+
*/
|
|
5
|
+
import { parseTokenAccount, type AccountInfo } from '../layout.js'
|
|
6
|
+
import { RAYDIUM_CPMM_AUTHORITY, RAYDIUM_CPMM_PROGRAM_ID } from '../lp.js'
|
|
7
|
+
import { Writer, anchorIx, r, w } from '../liquidity/common.js'
|
|
8
|
+
import type { Instruction } from '../write/transaction.js'
|
|
9
|
+
import { Bytes, UnsupportedPool, mulDivCeil, mulDivFloor, need, swapMint, transferFee, type AccountGetter, type HopQuote, type SwapEnv, type SwapMint, type SwapPool } from './common.js'
|
|
10
|
+
|
|
11
|
+
const FEE_DENOMINATOR = 1_000_000n
|
|
12
|
+
const POOL_SIZE = 637
|
|
13
|
+
|
|
14
|
+
interface CpmmState {
|
|
15
|
+
address: string
|
|
16
|
+
config: string
|
|
17
|
+
vault0: string
|
|
18
|
+
vault1: string
|
|
19
|
+
mint0: string
|
|
20
|
+
mint1: string
|
|
21
|
+
observation: string
|
|
22
|
+
status: number
|
|
23
|
+
openTime: bigint
|
|
24
|
+
reserved0: bigint
|
|
25
|
+
reserved1: bigint
|
|
26
|
+
creatorFeeOn: number
|
|
27
|
+
creatorFeeEnabled: boolean
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** PoolState:amm_config 8、vault 72 / 104、mint 168 / 200、observation 296、status 329、协议 / 基金手续费 341…、open_time 373、creator_fee_on 389、enable_creator_fee 390、创建者手续费 397 / 405 */
|
|
31
|
+
export function parseCpmmPool(account: AccountInfo): CpmmState | null {
|
|
32
|
+
if (account.owner !== RAYDIUM_CPMM_PROGRAM_ID || account.data.length !== POOL_SIZE) return null
|
|
33
|
+
const b = new Bytes(account.data)
|
|
34
|
+
return {
|
|
35
|
+
address: account.address,
|
|
36
|
+
config: b.key(8),
|
|
37
|
+
vault0: b.key(72),
|
|
38
|
+
vault1: b.key(104),
|
|
39
|
+
mint0: b.key(168),
|
|
40
|
+
mint1: b.key(200),
|
|
41
|
+
observation: b.key(296),
|
|
42
|
+
status: b.u8(329),
|
|
43
|
+
openTime: b.u64(373),
|
|
44
|
+
reserved0: b.u64(341) + b.u64(357) + b.u64(397),
|
|
45
|
+
reserved1: b.u64(349) + b.u64(365) + b.u64(405),
|
|
46
|
+
creatorFeeOn: b.u8(389),
|
|
47
|
+
creatorFeeEnabled: b.u8(390) !== 0,
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** 恒定乘积的兑换(与程序 CurveCalculator::swap_base_input 一致),返回给用户的输出(未扣转账手续费) */
|
|
52
|
+
export function cpmmSwapBaseInput(
|
|
53
|
+
amountIn: bigint,
|
|
54
|
+
reserveIn: bigint,
|
|
55
|
+
reserveOut: bigint,
|
|
56
|
+
tradeFeeRate: bigint,
|
|
57
|
+
creatorFeeRate: bigint,
|
|
58
|
+
creatorFeeOnInput: boolean,
|
|
59
|
+
): bigint {
|
|
60
|
+
let afterFee: bigint
|
|
61
|
+
if (creatorFeeOnInput) {
|
|
62
|
+
afterFee = amountIn - mulDivCeil(amountIn, tradeFeeRate + creatorFeeRate, FEE_DENOMINATOR)
|
|
63
|
+
} else {
|
|
64
|
+
afterFee = amountIn - mulDivCeil(amountIn, tradeFeeRate, FEE_DENOMINATOR)
|
|
65
|
+
}
|
|
66
|
+
if (afterFee < 0n) return 0n
|
|
67
|
+
const swapped = mulDivFloor(afterFee, reserveOut, reserveIn + afterFee)
|
|
68
|
+
return creatorFeeOnInput ? swapped : swapped - mulDivCeil(swapped, creatorFeeRate, FEE_DENOMINATOR)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export function cpmmPool(state: CpmmState): SwapPool {
|
|
72
|
+
const mints = (get: AccountGetter): [SwapMint, SwapMint] => [
|
|
73
|
+
swapMint(state.mint0, need(get, state.mint0, 'Token mint')),
|
|
74
|
+
swapMint(state.mint1, need(get, state.mint1, 'Token mint')),
|
|
75
|
+
]
|
|
76
|
+
return {
|
|
77
|
+
protocol: 'raydium-cpmm',
|
|
78
|
+
address: state.address,
|
|
79
|
+
mint0: state.mint0,
|
|
80
|
+
mint1: state.mint1,
|
|
81
|
+
mints,
|
|
82
|
+
accounts: () => [state.config, state.vault0, state.vault1, state.mint0, state.mint1],
|
|
83
|
+
quote(get, amountIn, zeroForOne, env: SwapEnv): HopQuote {
|
|
84
|
+
// status 第 2 位(Swap)为 1 表示禁止兑换
|
|
85
|
+
if (state.status & 4) throw new UnsupportedPool('Swap is disabled on this pool')
|
|
86
|
+
if (env.timestamp < state.openTime) throw new UnsupportedPool('Pool is not open yet')
|
|
87
|
+
const [m0, m1] = mints(get)
|
|
88
|
+
const config = need(get, state.config, 'AMM config').data
|
|
89
|
+
if (config.length < 124) throw new UnsupportedPool('Unexpected AMM config')
|
|
90
|
+
const c = new Bytes(config)
|
|
91
|
+
// AmmConfig:trade_fee_rate 12、creator_fee_rate 108
|
|
92
|
+
const tradeFeeRate = c.u64(12)
|
|
93
|
+
const creatorFeeRate = state.creatorFeeEnabled ? c.u64(108) : 0n
|
|
94
|
+
const v0 = parseTokenAccount(need(get, state.vault0, 'Pool vault').data).amount
|
|
95
|
+
const v1 = parseTokenAccount(need(get, state.vault1, 'Pool vault').data).amount
|
|
96
|
+
if (v0 < state.reserved0 || v1 < state.reserved1) throw new UnsupportedPool('Pool vault is below the owed fees')
|
|
97
|
+
const [reserveIn, reserveOut] = zeroForOne ? [v0 - state.reserved0, v1 - state.reserved1] : [v1 - state.reserved1, v0 - state.reserved0]
|
|
98
|
+
const [mintIn, mintOut] = zeroForOne ? [m0, m1] : [m1, m0]
|
|
99
|
+
// 创建者手续费:0 两边都从输入扣;1 只收 token0;2 只收 token1(收哪种代币,卖出它时从输入扣,买入它时从输出扣)
|
|
100
|
+
const creatorOnInput = state.creatorFeeOn === 0 || (state.creatorFeeOn === 1 && zeroForOne) || (state.creatorFeeOn === 2 && !zeroForOne)
|
|
101
|
+
const actualIn = amountIn - transferFee(mintIn, amountIn, env.epoch)
|
|
102
|
+
if (actualIn <= 0n) return { amountIn, amountOut: 0n, accounts: [] }
|
|
103
|
+
const out = cpmmSwapBaseInput(actualIn, reserveIn, reserveOut, tradeFeeRate, creatorFeeRate, creatorOnInput)
|
|
104
|
+
const received = out - transferFee(mintOut, out, env.epoch)
|
|
105
|
+
return { amountIn, amountOut: received > 0n ? received : 0n, accounts: [] }
|
|
106
|
+
},
|
|
107
|
+
instruction(get, owner, input, output, zeroForOne, quote, minOut): Instruction {
|
|
108
|
+
const [m0, m1] = mints(get)
|
|
109
|
+
const [mintIn, mintOut] = zeroForOne ? [m0, m1] : [m1, m0]
|
|
110
|
+
const [vaultIn, vaultOut] = zeroForOne ? [state.vault0, state.vault1] : [state.vault1, state.vault0]
|
|
111
|
+
return {
|
|
112
|
+
programId: RAYDIUM_CPMM_PROGRAM_ID,
|
|
113
|
+
keys: [
|
|
114
|
+
r(owner, true),
|
|
115
|
+
r(RAYDIUM_CPMM_AUTHORITY),
|
|
116
|
+
r(state.config),
|
|
117
|
+
w(state.address),
|
|
118
|
+
w(input),
|
|
119
|
+
w(output),
|
|
120
|
+
w(vaultIn),
|
|
121
|
+
w(vaultOut),
|
|
122
|
+
r(mintIn.program),
|
|
123
|
+
r(mintOut.program),
|
|
124
|
+
r(mintIn.mint),
|
|
125
|
+
r(mintOut.mint),
|
|
126
|
+
w(state.observation),
|
|
127
|
+
],
|
|
128
|
+
data: new Writer().bytes(anchorIx('swap_base_input')).u64(quote.amountIn).u64(minOut).build(),
|
|
129
|
+
}
|
|
130
|
+
},
|
|
131
|
+
}
|
|
132
|
+
}
|