@w3lib/evm-batch-call 0.5.0 → 0.7.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.
Files changed (160) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/README.md +240 -4
  3. package/contracts/TokenProbe.sol +103 -0
  4. package/dist/aggregate.d.ts.map +1 -1
  5. package/dist/aggregate.js +114 -3
  6. package/dist/aggregate.js.map +1 -1
  7. package/dist/approvals.d.ts +169 -0
  8. package/dist/approvals.d.ts.map +1 -0
  9. package/dist/approvals.js +310 -0
  10. package/dist/approvals.js.map +1 -0
  11. package/dist/chains.d.ts.map +1 -1
  12. package/dist/chains.js +4 -0
  13. package/dist/chains.js.map +1 -1
  14. package/dist/fees.d.ts +97 -0
  15. package/dist/fees.d.ts.map +1 -0
  16. package/dist/fees.js +115 -0
  17. package/dist/fees.js.map +1 -0
  18. package/dist/http.d.ts +10 -0
  19. package/dist/http.d.ts.map +1 -0
  20. package/dist/http.js +30 -0
  21. package/dist/http.js.map +1 -0
  22. package/dist/liquidity/common.d.ts +72 -0
  23. package/dist/liquidity/common.d.ts.map +1 -0
  24. package/dist/liquidity/common.js +271 -0
  25. package/dist/liquidity/common.js.map +1 -0
  26. package/dist/liquidity/concentrated.d.ts +19 -0
  27. package/dist/liquidity/concentrated.d.ts.map +1 -0
  28. package/dist/liquidity/concentrated.js +106 -0
  29. package/dist/liquidity/concentrated.js.map +1 -0
  30. package/dist/liquidity/index.d.ts +42 -0
  31. package/dist/liquidity/index.d.ts.map +1 -0
  32. package/dist/liquidity/index.js +143 -0
  33. package/dist/liquidity/index.js.map +1 -0
  34. package/dist/liquidity/types.d.ts +182 -0
  35. package/dist/liquidity/types.d.ts.map +1 -0
  36. package/dist/liquidity/types.js +2 -0
  37. package/dist/liquidity/types.js.map +1 -0
  38. package/dist/liquidity/v2.d.ts +5 -0
  39. package/dist/liquidity/v2.d.ts.map +1 -0
  40. package/dist/liquidity/v2.js +342 -0
  41. package/dist/liquidity/v2.js.map +1 -0
  42. package/dist/liquidity/v3.d.ts +6 -0
  43. package/dist/liquidity/v3.d.ts.map +1 -0
  44. package/dist/liquidity/v3.js +310 -0
  45. package/dist/liquidity/v3.js.map +1 -0
  46. package/dist/liquidity/v4.d.ts +5 -0
  47. package/dist/liquidity/v4.d.ts.map +1 -0
  48. package/dist/liquidity/v4.js +279 -0
  49. package/dist/liquidity/v4.js.map +1 -0
  50. package/dist/lp.d.ts +10 -2
  51. package/dist/lp.d.ts.map +1 -1
  52. package/dist/lp.js +31 -19
  53. package/dist/lp.js.map +1 -1
  54. package/dist/lpMath.d.ts +55 -0
  55. package/dist/lpMath.d.ts.map +1 -1
  56. package/dist/lpMath.js +209 -0
  57. package/dist/lpMath.js.map +1 -1
  58. package/dist/multicall.d.ts.map +1 -1
  59. package/dist/multicall.js +3 -0
  60. package/dist/multicall.js.map +1 -1
  61. package/dist/names.d.ts +55 -0
  62. package/dist/names.d.ts.map +1 -0
  63. package/dist/names.js +93 -0
  64. package/dist/names.js.map +1 -0
  65. package/dist/owner.d.ts +4 -26
  66. package/dist/owner.d.ts.map +1 -1
  67. package/dist/owner.js +7 -112
  68. package/dist/owner.js.map +1 -1
  69. package/dist/portfolio.d.ts +54 -0
  70. package/dist/portfolio.d.ts.map +1 -0
  71. package/dist/portfolio.js +49 -0
  72. package/dist/portfolio.js.map +1 -0
  73. package/dist/price.d.ts +95 -0
  74. package/dist/price.d.ts.map +1 -0
  75. package/dist/price.js +329 -0
  76. package/dist/price.js.map +1 -0
  77. package/dist/risk.d.ts +42 -0
  78. package/dist/risk.d.ts.map +1 -0
  79. package/dist/risk.js +134 -0
  80. package/dist/risk.js.map +1 -0
  81. package/dist/rpcNodes.d.ts.map +1 -1
  82. package/dist/rpcNodes.js +18 -0
  83. package/dist/rpcNodes.js.map +1 -1
  84. package/dist/subpaths/approvals.d.ts +26 -0
  85. package/dist/subpaths/approvals.d.ts.map +1 -0
  86. package/dist/subpaths/approvals.js +27 -0
  87. package/dist/subpaths/approvals.js.map +1 -0
  88. package/dist/subpaths/fees.d.ts +23 -0
  89. package/dist/subpaths/fees.d.ts.map +1 -0
  90. package/dist/subpaths/fees.js +25 -0
  91. package/dist/subpaths/fees.js.map +1 -0
  92. package/dist/subpaths/liquidity.d.ts +24 -0
  93. package/dist/subpaths/liquidity.d.ts.map +1 -0
  94. package/dist/subpaths/liquidity.js +21 -0
  95. package/dist/subpaths/liquidity.js.map +1 -0
  96. package/dist/subpaths/lp.d.ts +1 -1
  97. package/dist/subpaths/lp.d.ts.map +1 -1
  98. package/dist/subpaths/lp.js +1 -1
  99. package/dist/subpaths/lp.js.map +1 -1
  100. package/dist/subpaths/names.d.ts +35 -0
  101. package/dist/subpaths/names.d.ts.map +1 -0
  102. package/dist/subpaths/names.js +39 -0
  103. package/dist/subpaths/names.js.map +1 -0
  104. package/dist/subpaths/price.d.ts +38 -0
  105. package/dist/subpaths/price.d.ts.map +1 -0
  106. package/dist/subpaths/price.js +40 -0
  107. package/dist/subpaths/price.js.map +1 -0
  108. package/dist/subpaths/risk.d.ts +19 -0
  109. package/dist/subpaths/risk.d.ts.map +1 -0
  110. package/dist/subpaths/risk.js +20 -0
  111. package/dist/subpaths/risk.js.map +1 -0
  112. package/dist/subpaths/swap.d.ts +19 -0
  113. package/dist/subpaths/swap.d.ts.map +1 -0
  114. package/dist/subpaths/swap.js +20 -0
  115. package/dist/subpaths/swap.js.map +1 -0
  116. package/dist/swap.d.ts +128 -0
  117. package/dist/swap.d.ts.map +1 -0
  118. package/dist/swap.js +291 -0
  119. package/dist/swap.js.map +1 -0
  120. package/dist/tokenProbe.d.ts +3 -0
  121. package/dist/tokenProbe.d.ts.map +1 -0
  122. package/dist/tokenProbe.js +4 -0
  123. package/dist/tokenProbe.js.map +1 -0
  124. package/dist/write/tron.d.ts +27 -0
  125. package/dist/write/tron.d.ts.map +1 -1
  126. package/dist/write/tron.js +30 -0
  127. package/dist/write/tron.js.map +1 -1
  128. package/package.json +32 -1
  129. package/src/aggregate.ts +110 -3
  130. package/src/approvals.ts +462 -0
  131. package/src/chains.ts +4 -0
  132. package/src/fees.ts +201 -0
  133. package/src/http.ts +34 -0
  134. package/src/liquidity/common.ts +314 -0
  135. package/src/liquidity/concentrated.ts +121 -0
  136. package/src/liquidity/index.ts +171 -0
  137. package/src/liquidity/types.ts +194 -0
  138. package/src/liquidity/v2.ts +371 -0
  139. package/src/liquidity/v3.ts +382 -0
  140. package/src/liquidity/v4.ts +348 -0
  141. package/src/lp.ts +39 -19
  142. package/src/lpMath.ts +223 -0
  143. package/src/multicall.ts +3 -0
  144. package/src/names.ts +141 -0
  145. package/src/owner.ts +7 -138
  146. package/src/portfolio.ts +91 -0
  147. package/src/price.ts +415 -0
  148. package/src/risk.ts +166 -0
  149. package/src/rpcNodes.ts +18 -0
  150. package/src/subpaths/approvals.ts +48 -0
  151. package/src/subpaths/fees.ts +43 -0
  152. package/src/subpaths/liquidity.ts +52 -0
  153. package/src/subpaths/lp.ts +20 -1
  154. package/src/subpaths/names.ts +43 -0
  155. package/src/subpaths/price.ts +60 -0
  156. package/src/subpaths/risk.ts +23 -0
  157. package/src/subpaths/swap.ts +36 -0
  158. package/src/swap.ts +413 -0
  159. package/src/tokenProbe.ts +5 -0
  160. package/src/write/tron.ts +48 -0
@@ -0,0 +1,171 @@
1
+ import { Interface } from 'ethers'
2
+
3
+ import type { Provider } from '../provider.js'
4
+ import { batchCall, tronModule } from '../write/batch.js'
5
+ import { WriteRpc } from '../write/rpc.js'
6
+ import { resolveSigner, type SignerInput } from '../write/signer.js'
7
+ import { ZERO_ADDRESS, createCtx, evm, positionVersion, protocolById } from './common.js'
8
+ import type {
9
+ AddLiquidityParams,
10
+ CollectFeesParams,
11
+ LiquidityOptions,
12
+ LiquidityPlan,
13
+ LiquidityResult,
14
+ LiquiditySendOptions,
15
+ LiquidityTx,
16
+ LiquidityTxResult,
17
+ RemoveLiquidityParams,
18
+ } from './types.js'
19
+ import { v2Add, v2Remove } from './v2.js'
20
+ import { v3Add, v3Remove } from './v3.js'
21
+ import { v4Add, v4Remove } from './v4.js'
22
+
23
+ /**
24
+ * 添加流动性的计划(不签名、不发送):新建仓位,或往已有仓位追加。返回预计的数量和要按顺序发送的交易(授权在前)。
25
+ * 只做读取,也可以当作报价:输入一边的数量,看另一边要多少、能拿到多少流动性
26
+ *
27
+ * ```ts
28
+ * // 新建 V3 仓位:价格区间按 tokenB / tokenA,给一边的数量
29
+ * const plan = await buildAddLiquidity(multi, owner, { protocol: 'pancakeswap-v3', tokenA: WBNB, tokenB: USDT, fee: 500, priceLower: 550, priceUpper: 650, amountAFormatted: '1' })
30
+ * plan.amount1Formatted // 需要的 USDT
31
+ * plan.transactions // [approve…, add],可以交给钱包逐笔发送
32
+ * // 往已有仓位追加(position 可以直接用 getLpPositions 的结果)
33
+ * await buildAddLiquidity(multi, owner, { position, amount0Formatted: '0.5' })
34
+ * ```
35
+ */
36
+ export async function buildAddLiquidity(provider: Provider, owner: string, params: AddLiquidityParams, options: LiquidityOptions = {}): Promise<LiquidityPlan> {
37
+ const ctx = await createCtx(provider, owner, options)
38
+ if ('position' in params) {
39
+ const version = positionVersion(ctx, params.position)
40
+ return version === 'v2' ? v2Add(ctx, params) : version === 'v3' ? v3Add(ctx, params) : v4Add(ctx, params)
41
+ }
42
+ const protocol = protocolById(ctx, params.protocol)
43
+ const resolved = { ...params, protocol }
44
+ return protocol.version === 'v2' ? v2Add(ctx, resolved) : protocol.version === 'v3' ? v3Add(ctx, resolved) : v4Add(ctx, resolved)
45
+ }
46
+
47
+ /**
48
+ * 移除流动性的计划(不签名、不发送):按比例或指定数量移除,V3 / V4 同时领取全部未领取的手续费。
49
+ *
50
+ * ```ts
51
+ * await buildRemoveLiquidity(multi, owner, { position, percent: 50 })
52
+ * await buildRemoveLiquidity(multi, owner, { position, burn: true }) // 全部移除并销毁 NFT
53
+ * ```
54
+ */
55
+ export async function buildRemoveLiquidity(provider: Provider, owner: string, params: RemoveLiquidityParams, options: LiquidityOptions = {}): Promise<LiquidityPlan> {
56
+ const ctx = await createCtx(provider, owner, options)
57
+ const version = positionVersion(ctx, params.position)
58
+ return version === 'v2' ? v2Remove(ctx, params) : version === 'v3' ? v3Remove(ctx, params) : v4Remove(ctx, params)
59
+ }
60
+
61
+ /** 只领取 V3 / V4 仓位的手续费(不动流动性)的计划 */
62
+ export async function buildCollectFees(provider: Provider, owner: string, params: CollectFeesParams, options: LiquidityOptions = {}): Promise<LiquidityPlan> {
63
+ const ctx = await createCtx(provider, owner, options)
64
+ const version = positionVersion(ctx, params.position)
65
+ if (version === 'v2') {
66
+ throw new Error('V2 has no separate fees: they are part of the LP tokens, remove liquidity to get them')
67
+ }
68
+ return version === 'v3' ? v3Remove(ctx, { position: params.position }, true) : v4Remove(ctx, { position: params.position }, true)
69
+ }
70
+
71
+ /**
72
+ * 添加流动性:构建计划(同 buildAddLiquidity)后用 from 签名发送,授权不够时先发授权交易。
73
+ * from 与 /write 的 batchCall 相同:私钥、ethers Signer、浏览器钱包(Tron 上也可以是 tronWeb / adapter)
74
+ *
75
+ * ```ts
76
+ * const { status, tokenId, plan } = await addLiquidity(multi, privateKey, { protocol: 'uniswap-v3', tokenA: NATIVE_TOKEN, tokenB: USDC, fee: 500, fullRange: true, amountAFormatted: '0.1' })
77
+ * ```
78
+ */
79
+ export async function addLiquidity(provider: Provider, from: SignerInput, params: AddLiquidityParams, options: LiquiditySendOptions = {}): Promise<LiquidityResult> {
80
+ const plan = await buildAddLiquidity(provider, await signerAddress(provider, from), params, options)
81
+ if (options.checkBalance ?? true) {
82
+ await checkBalance(provider, plan)
83
+ }
84
+ return execute(provider, from, plan, options)
85
+ }
86
+
87
+ /** 移除流动性:构建计划(同 buildRemoveLiquidity)后用 from 签名发送 */
88
+ export async function removeLiquidity(provider: Provider, from: SignerInput, params: RemoveLiquidityParams, options: LiquiditySendOptions = {}): Promise<LiquidityResult> {
89
+ const plan = await buildRemoveLiquidity(provider, await signerAddress(provider, from), params, options)
90
+ return execute(provider, from, plan, options)
91
+ }
92
+
93
+ /** 领取 V3 / V4 仓位的手续费 */
94
+ export async function collectFees(provider: Provider, from: SignerInput, params: CollectFeesParams, options: LiquiditySendOptions = {}): Promise<LiquidityResult> {
95
+ const plan = await buildCollectFees(provider, await signerAddress(provider, from), params, options)
96
+ return execute(provider, from, plan, options)
97
+ }
98
+
99
+ /** 签名器的地址(Tron 上为 T 地址),不发交易 */
100
+ async function signerAddress(provider: Provider, from: SignerInput): Promise<string> {
101
+ const tron = await tronModule(provider)
102
+ return tron ? tron.tronSignerAddress(from) : (await resolveSigner(from)).address
103
+ }
104
+
105
+ /** 添加前检查余额:代币按预计数量,主币按附带的 value(不含手续费) */
106
+ async function checkBalance(provider: Provider, plan: LiquidityPlan): Promise<void> {
107
+ const needs: Array<[string, bigint]> = []
108
+ // V4 追加时先自动领取手续费、与存入相抵:只需要差额
109
+ const offset = (amount: string, fees: string) => {
110
+ const need = BigInt(amount) - (plan.version === 'v4' && plan.tokenId !== null ? BigInt(fees) : 0n)
111
+ return need > 0n ? need : 0n
112
+ }
113
+ if (plan.native !== 'token0') needs.push([plan.token0.address, offset(plan.amount0, plan.fees0)])
114
+ if (plan.native !== 'token1') needs.push([plan.token1.address, offset(plan.amount1, plan.fees1)])
115
+ if (BigInt(plan.value) > 0n) needs.push([provider.nativeTokens[0] ?? ZERO_ADDRESS, BigInt(plan.value)])
116
+ const list = needs.filter(([, amount]) => amount > 0n)
117
+ if (!list.length) {
118
+ return
119
+ }
120
+ const balances = await provider.balances(plan.owner, list.map(([token]) => token))
121
+ list.forEach(([token, amount], i) => {
122
+ const b = balances[i]
123
+ // 读不到余额的不拦(预估 gas 时也会失败)
124
+ if (b?.success && BigInt(b.balance) < amount) {
125
+ throw new Error(`Insufficient balance of ${token}: need ${amount}, have ${b.balance}`)
126
+ }
127
+ })
128
+ }
129
+
130
+ const transferTopic = new Interface(['event Transfer(address indexed from, address indexed to, uint256 indexed tokenId)']).getEvent('Transfer')?.topicHash as string
131
+
132
+ async function execute(provider: Provider, from: SignerInput, plan: LiquidityPlan, options: LiquiditySendOptions): Promise<LiquidityResult> {
133
+ const { transactions } = plan
134
+ const results = (
135
+ await batchCall(
136
+ provider,
137
+ transactions.map((tx) => ({ from, to: tx.to, data: tx.data, value: BigInt(tx.value) })),
138
+ {
139
+ ...options,
140
+ mode: 'tx',
141
+ // 授权失败时不发主交易
142
+ continueOnError: false,
143
+ onUpdate: options.onUpdate ? (r) => options.onUpdate?.({ ...r, kind: (transactions[r.index] as LiquidityTx).kind }) : undefined,
144
+ },
145
+ )
146
+ ).map((r, i): LiquidityTxResult => ({ ...r, kind: (transactions[i] as LiquidityTx).kind }))
147
+ const main = results[results.length - 1] as LiquidityTxResult
148
+ let tokenId: string | null = plan.tokenId
149
+ if (plan.action === 'add' && plan.tokenId === null && plan.version !== 'v2') {
150
+ tokenId = main.status === 'confirmed' && main.hash ? await mintedTokenId(provider, plan, main.hash) : null
151
+ }
152
+ return { plan, results, status: main.status, hash: main.hash, tokenId }
153
+ }
154
+
155
+ /** 新建仓位的 tokenId:主交易回执里仓位合约从零地址转出的 NFT(Tron 上不读,为 null) */
156
+ async function mintedTokenId(provider: Provider, plan: LiquidityPlan, hash: string): Promise<string | null> {
157
+ try {
158
+ if (await tronModule(provider)) {
159
+ return null
160
+ }
161
+ const receipt = await (await WriteRpc.from(provider)).receipt(hash)
162
+ const pm = evm((plan.transactions[plan.transactions.length - 1] as { to: string }).to)
163
+ const log = receipt?.logs.find(
164
+ (l) => l.topics.length === 4 && l.topics[0] === transferTopic && BigInt(l.topics[1] as string) === 0n && evm(l.address) === pm,
165
+ )
166
+ return log ? BigInt(log.topics[3] as string).toString() : null
167
+ } catch {
168
+ return null // 读回执失败不影响结果(交易已确认)
169
+ }
170
+ }
171
+
@@ -0,0 +1,194 @@
1
+ import type { BigNumberish } from 'ethers'
2
+
3
+ import type { LpPosition, LpProtocol, LpToken, LpVersion } from '../lp.js'
4
+ import type { SendOptions, TronSendOptions, WriteResult, WriteStatus } from '../write/send.js'
5
+
6
+ /**
7
+ * 已有的仓位:直接传 getLpPositions 查到的 LpPosition,或者只传能定位仓位的字段。
8
+ * - V2:pool(LP 代币地址)
9
+ * - V3 / V4:tokenId,加上 positionManager 或 protocol(协议 id / LpProtocol)
10
+ */
11
+ export interface PositionRef {
12
+ pool?: string
13
+ tokenId?: string | number | bigint
14
+ positionManager?: string
15
+ protocol?: string | LpProtocol
16
+ }
17
+
18
+ /** 往已有仓位追加流动性:两边数量给一边即可(另一边按当前价格算),也可以都给(按较少的一边) */
19
+ export interface IncreaseLiquidityParams {
20
+ position: PositionRef | LpPosition
21
+ /** token0 的数量:amount0(最小单位)和 amount0Formatted(按精度换算,如 '1.5')二选一 */
22
+ amount0?: BigNumberish
23
+ amount0Formatted?: string
24
+ amount1?: BigNumberish
25
+ amount1Formatted?: string
26
+ }
27
+
28
+ /**
29
+ * 新建仓位(V3 / V4:一个新的仓位 NFT;V2:往 tokenA / tokenB 的池子里加,池子不存在时创建)。
30
+ * 两个代币不分顺序,价格都是“1 个 tokenA 值多少个 tokenB”
31
+ */
32
+ export interface NewPositionParams {
33
+ /** 协议 id(如 'uniswap-v3')或自己的 LpProtocol */
34
+ protocol: string | LpProtocol
35
+ /** 代币地址;主币用 NATIVE_TOKEN 或零地址(V2 / V3 换成包装币、用主币支付;V4 是主币池子) */
36
+ tokenA: string
37
+ tokenB: string
38
+ /** V3 / V4:手续费档位(百万分之一:500 = 0.05%) */
39
+ fee?: number
40
+ /** V4:tick 间距,默认按手续费档位(100 → 1、500 → 10、3000 → 60、10000 → 200) */
41
+ tickSpacing?: number
42
+ /** V4:池子的 hooks 合约,默认零地址 */
43
+ hooks?: string
44
+ /** V3 / V4:价格区间(tokenB / tokenA,取最近的可用 tick);或直接给 tickLower / tickUpper;或 fullRange */
45
+ priceLower?: string | number
46
+ priceUpper?: string | number
47
+ /** 池子里的 tick(token1 / token0 方向),必须是 tickSpacing 的整数倍 */
48
+ tickLower?: number
49
+ tickUpper?: number
50
+ /** 全区间(最小到最大的可用 tick) */
51
+ fullRange?: boolean
52
+ /** tokenA / tokenB 的数量:amount(最小单位)和 formatted 二选一;两边给一边即可,V2 新池子两边都要给 */
53
+ amountA?: BigNumberish
54
+ amountAFormatted?: string
55
+ amountB?: BigNumberish
56
+ amountBFormatted?: string
57
+ /** 池子不存在(或还没初始化)时用这个价格创建(tokenB / tokenA)。不传时池子不存在会报错 */
58
+ initialPrice?: string | number
59
+ }
60
+
61
+ export type AddLiquidityParams = IncreaseLiquidityParams | NewPositionParams
62
+
63
+ export interface RemoveLiquidityParams {
64
+ position: PositionRef | LpPosition
65
+ /** 移除的比例(百分数,(0, 100]),默认 100 */
66
+ percent?: number
67
+ /** 或者直接给移除的流动性:V3 / V4 是 L,V2 是 LP 代币数量(最小单位) */
68
+ liquidity?: BigNumberish
69
+ /** V3 / V4:全部移除后销毁仓位 NFT,默认 false */
70
+ burn?: boolean
71
+ }
72
+
73
+ export interface CollectFeesParams {
74
+ /** V3 / V4 的仓位(V2 的手续费已经计入 LP 份额,没有单独领取) */
75
+ position: PositionRef | LpPosition
76
+ }
77
+
78
+ export interface LiquidityOptions {
79
+ /** 价格滑点(比例,0.005 = 0.5%),默认 0.005 */
80
+ slippage?: number
81
+ /** 交易的有效期(秒),默认 1200 */
82
+ deadline?: number
83
+ /** 收到 LP 代币 / 仓位 NFT / 移除的代币的地址,默认 owner */
84
+ recipient?: string
85
+ /**
86
+ * V2 / V3:包装币(WETH / WBNB …)那一边用主币支付 / 收取。
87
+ * 新建仓位时 tokenA / tokenB 传主币地址会自动开启;往已有仓位追加、移除、领取时默认 false(收到包装币)。V4 的主币池子不需要
88
+ */
89
+ native?: boolean
90
+ /** 授权额度:'exact'(默认,本次需要的数量)或 'max'(无限额度,之后不用再授权) */
91
+ approve?: 'exact' | 'max'
92
+ /** 内置表里没有的协议(自己的 LpProtocol),定位仓位时也会用到 */
93
+ protocols?: readonly LpProtocol[]
94
+ /** V4:传给 hooks 的 hookData,默认 '0x' */
95
+ hookData?: string
96
+ }
97
+
98
+ /** 一笔要发送的交易 */
99
+ export interface LiquidityTx {
100
+ /**
101
+ * - approve:代币授权给 Router / 仓位合约 / Permit2
102
+ * - permit2:Permit2 授权给 V4 的仓位合约
103
+ * - add / remove / collect:添加 / 移除流动性、领取手续费
104
+ */
105
+ kind: 'approve' | 'permit2' | 'add' | 'remove' | 'collect'
106
+ to: string
107
+ data: string
108
+ /** 附带的主币(最小单位) */
109
+ value: string
110
+ /** approve / permit2:授权的代币、被授权方、额度 */
111
+ token?: string
112
+ spender?: string
113
+ amount?: string
114
+ }
115
+
116
+ /**
117
+ * 添加 / 移除流动性的计划:预计的数量 + 要按顺序发送的交易(授权在前)。
118
+ * 只做读取、不签名,可以当作报价用(输入一边数量,看另一边要多少)
119
+ */
120
+ export interface LiquidityPlan {
121
+ action: 'add' | 'remove' | 'collect'
122
+ chainId: number
123
+ version: LpVersion
124
+ /** 协议 id / 显示名 */
125
+ protocol: string
126
+ protocolName: string
127
+ /** 池子地址(V4 为 poolId);V2 / V3 的池子还不存在时为 null */
128
+ pool: string | null
129
+ /** 这次会创建(初始化)池子 */
130
+ createPool: boolean
131
+ owner: string
132
+ recipient: string
133
+ token0: LpToken
134
+ token1: LpToken
135
+ /** 已有仓位的 tokenId;新建 V3 / V4 仓位、V2 为 null */
136
+ tokenId: string | null
137
+ /** V3 / V4:仓位的 tick 区间、池子当前的 tick 和价格(token1 / token0,按精度换算,只用于展示) */
138
+ tickLower: number | null
139
+ tickUpper: number | null
140
+ tick: number | null
141
+ price: number | null
142
+ priceLower: number | null
143
+ priceUpper: number | null
144
+ /** 添加 / 移除的流动性:V3 / V4 是 L;V2 是 LP 代币数量(添加时为预计) */
145
+ liquidity: string
146
+ /** 按当前价格预计存入 / 取出的数量(不含手续费) */
147
+ amount0: string
148
+ amount1: string
149
+ amount0Formatted: string | null
150
+ amount1Formatted: string | null
151
+ /** 添加:最多会用掉的数量(V4 按滑点上浮;V2 / V3 即传给合约的数量);移除:为 null */
152
+ amount0Max: string | null
153
+ amount1Max: string | null
154
+ /** 移除:至少会拿到的数量(价格在滑点范围外时交易失败);添加:为 null */
155
+ amount0Min: string | null
156
+ amount1Min: string | null
157
+ /**
158
+ * 一并领取的未领取手续费(V3 移除 / 领取;V4 修改流动性时自动领取)。V2 没有单独的手续费,为 '0'
159
+ */
160
+ fees0: string
161
+ fees1: string
162
+ fees0Formatted: string | null
163
+ fees1Formatted: string | null
164
+ /** 哪一边用主币支付 / 收取(V2 / V3 的包装币那一边开启 native 时;V4 主币池子的 token0);都不是时为 null */
165
+ native: 'token0' | 'token1' | null
166
+ /** 主交易附带的主币 */
167
+ value: string
168
+ /** 交易的截止时间(秒级时间戳) */
169
+ deadline: number
170
+ /** 按顺序发送;不需要授权时只有一笔 */
171
+ transactions: LiquidityTx[]
172
+ }
173
+
174
+ export interface LiquiditySendOptions extends LiquidityOptions, Omit<SendOptions, 'onUpdate'>, TronSendOptions {
175
+ /** 发送前检查余额够不够(添加时),默认 true */
176
+ checkBalance?: boolean
177
+ /** 每笔交易状态变化时回调(index 是在 plan.transactions 里的下标) */
178
+ onUpdate?: (result: LiquidityTxResult) => void
179
+ }
180
+
181
+ export interface LiquidityTxResult extends WriteResult {
182
+ kind: LiquidityTx['kind']
183
+ }
184
+
185
+ export interface LiquidityResult {
186
+ plan: LiquidityPlan
187
+ /** 与 plan.transactions 一一对应 */
188
+ results: LiquidityTxResult[]
189
+ /** 主交易(最后一笔)的状态和哈希 */
190
+ status: WriteStatus
191
+ hash: string | null
192
+ /** 新建的 V3 / V4 仓位的 tokenId(EVM 上主交易 confirmed 后从回执里读;其他情况为 null) */
193
+ tokenId: string | null
194
+ }