@w3lib/evm-batch-call 0.7.0 → 0.8.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 (159) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/README.md +206 -1
  3. package/dist/dividends.d.ts +135 -0
  4. package/dist/dividends.d.ts.map +1 -0
  5. package/dist/dividends.js +253 -0
  6. package/dist/dividends.js.map +1 -0
  7. package/dist/history.d.ts +154 -0
  8. package/dist/history.d.ts.map +1 -0
  9. package/dist/history.js +247 -0
  10. package/dist/history.js.map +1 -0
  11. package/dist/historySources.d.ts +32 -0
  12. package/dist/historySources.d.ts.map +1 -0
  13. package/dist/historySources.js +319 -0
  14. package/dist/historySources.js.map +1 -0
  15. package/dist/liquidity/v3.d.ts +2 -0
  16. package/dist/liquidity/v3.d.ts.map +1 -1
  17. package/dist/liquidity/v3.js +1 -1
  18. package/dist/liquidity/v3.js.map +1 -1
  19. package/dist/liquidity/v4.d.ts +21 -0
  20. package/dist/liquidity/v4.d.ts.map +1 -1
  21. package/dist/liquidity/v4.js +4 -3
  22. package/dist/liquidity/v4.js.map +1 -1
  23. package/dist/lp.d.ts +8 -0
  24. package/dist/lp.d.ts.map +1 -1
  25. package/dist/lp.js +17 -1
  26. package/dist/lp.js.map +1 -1
  27. package/dist/lpV4.d.ts +4 -0
  28. package/dist/lpV4.d.ts.map +1 -1
  29. package/dist/lpV4.js +27 -3
  30. package/dist/lpV4.js.map +1 -1
  31. package/dist/permit.d.ts +137 -0
  32. package/dist/permit.d.ts.map +1 -0
  33. package/dist/permit.js +355 -0
  34. package/dist/permit.js.map +1 -0
  35. package/dist/portfolio.d.ts +2 -0
  36. package/dist/portfolio.d.ts.map +1 -1
  37. package/dist/portfolio.js +9 -4
  38. package/dist/portfolio.js.map +1 -1
  39. package/dist/rewards/farms.d.ts +26 -0
  40. package/dist/rewards/farms.d.ts.map +1 -0
  41. package/dist/rewards/farms.js +210 -0
  42. package/dist/rewards/farms.js.map +1 -0
  43. package/dist/rewards/index.d.ts +42 -0
  44. package/dist/rewards/index.d.ts.map +1 -0
  45. package/dist/rewards/index.js +382 -0
  46. package/dist/rewards/index.js.map +1 -0
  47. package/dist/rewards/types.d.ts +170 -0
  48. package/dist/rewards/types.d.ts.map +1 -0
  49. package/dist/rewards/types.js +2 -0
  50. package/dist/rewards/types.js.map +1 -0
  51. package/dist/simulate.d.ts +186 -0
  52. package/dist/simulate.d.ts.map +1 -0
  53. package/dist/simulate.js +559 -0
  54. package/dist/simulate.js.map +1 -0
  55. package/dist/simulateDecode.d.ts +33 -0
  56. package/dist/simulateDecode.d.ts.map +1 -0
  57. package/dist/simulateDecode.js +321 -0
  58. package/dist/simulateDecode.js.map +1 -0
  59. package/dist/smartAccount/account.d.ts +31 -0
  60. package/dist/smartAccount/account.d.ts.map +1 -0
  61. package/dist/smartAccount/account.js +33 -0
  62. package/dist/smartAccount/account.js.map +1 -0
  63. package/dist/smartAccount/clients.d.ts +77 -0
  64. package/dist/smartAccount/clients.d.ts.map +1 -0
  65. package/dist/smartAccount/clients.js +122 -0
  66. package/dist/smartAccount/clients.js.map +1 -0
  67. package/dist/smartAccount/eip5792.d.ts +77 -0
  68. package/dist/smartAccount/eip5792.d.ts.map +1 -0
  69. package/dist/smartAccount/eip5792.js +152 -0
  70. package/dist/smartAccount/eip5792.js.map +1 -0
  71. package/dist/smartAccount/send.d.ts +40 -0
  72. package/dist/smartAccount/send.d.ts.map +1 -0
  73. package/dist/smartAccount/send.js +271 -0
  74. package/dist/smartAccount/send.js.map +1 -0
  75. package/dist/smartAccount/userOp.d.ts +91 -0
  76. package/dist/smartAccount/userOp.d.ts.map +1 -0
  77. package/dist/smartAccount/userOp.js +124 -0
  78. package/dist/smartAccount/userOp.js.map +1 -0
  79. package/dist/subpaths/dividends.d.ts +28 -0
  80. package/dist/subpaths/dividends.d.ts.map +1 -0
  81. package/dist/subpaths/dividends.js +29 -0
  82. package/dist/subpaths/dividends.js.map +1 -0
  83. package/dist/subpaths/history.d.ts +22 -0
  84. package/dist/subpaths/history.d.ts.map +1 -0
  85. package/dist/subpaths/history.js +23 -0
  86. package/dist/subpaths/history.js.map +1 -0
  87. package/dist/subpaths/permit.d.ts +14 -0
  88. package/dist/subpaths/permit.d.ts.map +1 -0
  89. package/dist/subpaths/permit.js +14 -0
  90. package/dist/subpaths/permit.js.map +1 -0
  91. package/dist/subpaths/price.js +2 -2
  92. package/dist/subpaths/price.js.map +1 -1
  93. package/dist/subpaths/rewards.d.ts +27 -0
  94. package/dist/subpaths/rewards.d.ts.map +1 -0
  95. package/dist/subpaths/rewards.js +25 -0
  96. package/dist/subpaths/rewards.js.map +1 -0
  97. package/dist/subpaths/simulate.d.ts +25 -0
  98. package/dist/subpaths/simulate.d.ts.map +1 -0
  99. package/dist/subpaths/simulate.js +28 -0
  100. package/dist/subpaths/simulate.js.map +1 -0
  101. package/dist/subpaths/smart-account.d.ts +24 -0
  102. package/dist/subpaths/smart-account.d.ts.map +1 -0
  103. package/dist/subpaths/smart-account.js +24 -0
  104. package/dist/subpaths/smart-account.js.map +1 -0
  105. package/dist/swap.d.ts +45 -5
  106. package/dist/swap.d.ts.map +1 -1
  107. package/dist/swap.js +108 -12
  108. package/dist/swap.js.map +1 -1
  109. package/dist/write/batch.d.ts +34 -2
  110. package/dist/write/batch.d.ts.map +1 -1
  111. package/dist/write/batch.js +22 -3
  112. package/dist/write/batch.js.map +1 -1
  113. package/dist/write/collect.d.ts +9 -0
  114. package/dist/write/collect.d.ts.map +1 -1
  115. package/dist/write/collect.js +41 -1
  116. package/dist/write/collect.js.map +1 -1
  117. package/dist/write/send.d.ts +4 -0
  118. package/dist/write/send.d.ts.map +1 -1
  119. package/dist/write/send.js.map +1 -1
  120. package/dist/write/signer.d.ts +5 -1
  121. package/dist/write/signer.d.ts.map +1 -1
  122. package/dist/write/signer.js.map +1 -1
  123. package/dist/write/transfer.d.ts +5 -3
  124. package/dist/write/transfer.d.ts.map +1 -1
  125. package/dist/write/transfer.js +12 -6
  126. package/dist/write/transfer.js.map +1 -1
  127. package/package.json +35 -1
  128. package/src/dividends.ts +360 -0
  129. package/src/history.ts +367 -0
  130. package/src/historySources.ts +360 -0
  131. package/src/liquidity/v3.ts +1 -1
  132. package/src/liquidity/v4.ts +4 -3
  133. package/src/lp.ts +18 -1
  134. package/src/lpV4.ts +32 -2
  135. package/src/permit.ts +457 -0
  136. package/src/portfolio.ts +11 -4
  137. package/src/rewards/farms.ts +229 -0
  138. package/src/rewards/index.ts +431 -0
  139. package/src/rewards/types.ts +179 -0
  140. package/src/simulate.ts +727 -0
  141. package/src/simulateDecode.ts +352 -0
  142. package/src/smartAccount/account.ts +63 -0
  143. package/src/smartAccount/clients.ts +180 -0
  144. package/src/smartAccount/eip5792.ts +187 -0
  145. package/src/smartAccount/send.ts +341 -0
  146. package/src/smartAccount/userOp.ts +180 -0
  147. package/src/subpaths/dividends.ts +47 -0
  148. package/src/subpaths/history.ts +41 -0
  149. package/src/subpaths/permit.ts +39 -0
  150. package/src/subpaths/price.ts +2 -2
  151. package/src/subpaths/rewards.ts +46 -0
  152. package/src/subpaths/simulate.ts +51 -0
  153. package/src/subpaths/smart-account.ts +40 -0
  154. package/src/swap.ts +139 -18
  155. package/src/write/batch.ts +44 -5
  156. package/src/write/collect.ts +60 -1
  157. package/src/write/send.ts +4 -0
  158. package/src/write/signer.ts +5 -1
  159. package/src/write/transfer.ts +17 -10
@@ -0,0 +1,23 @@
1
+ /**
2
+ * 交易历史(子路径 `@w3lib/evm-batch-call/history`):一个地址的转账 / 兑换 / 授权 / 流动性 / 铸造记录,带解码后的类型、资产变化和手续费。
3
+ * 数据来源可替换、可故障切换:Blockscout(免 Key,默认)、Etherscan v2(传 apiKey)、纯 RPC 日志、Tron 的 TronGrid。
4
+ * 不放在主入口,不用时打包不会带上这部分代码。
5
+ *
6
+ * ```ts
7
+ * import { getHistory } from '@w3lib/evm-batch-call/history'
8
+ *
9
+ * const page = await getHistory(user, { chainId: 1, limit: 20 })
10
+ * const more = await getHistory(user, { chainId: 1, cursor: page.nextCursor, types: ['swap'] })
11
+ * await getHistory(user, { chainId: 56, source: ['etherscan', 'rpc'], apiKey })
12
+ * ```
13
+ */
14
+ import { history } from '../history.js';
15
+ import { resolve } from '../shortcuts.js';
16
+ export { HistorySourceError, buildActivities, history, } from '../history.js';
17
+ export { BLOCKSCOUT_APIS, blockscoutSource, etherscanSource, explorerSource, rpcSource, trongridSource } from '../historySources.js';
18
+ /** 查一个地址的历史活动,节点参数与 getBalances 相同(只有 rpc 来源会用到节点) */
19
+ export function getHistory(address, options = {}) {
20
+ const { provider, own } = resolve(options, ['source', 'apiKey', 'limit', 'cursor', 'types', 'before', 'after', 'nft', 'maxPages', 'fetch']);
21
+ return history(provider, address, own);
22
+ }
23
+ //# sourceMappingURL=history.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"history.js","sourceRoot":"","sources":["../../src/subpaths/history.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,EAAE,OAAO,EAA2C,MAAM,eAAe,CAAA;AAChF,OAAO,EAAE,OAAO,EAAgC,MAAM,iBAAiB,CAAA;AAEvE,OAAO,EACL,kBAAkB,EAClB,eAAe,EACf,OAAO,GAYR,MAAM,eAAe,CAAA;AACtB,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,eAAe,EAAE,cAAc,EAAE,SAAS,EAAE,cAAc,EAAqD,MAAM,sBAAsB,CAAA;AAIvL,sDAAsD;AACtD,MAAM,UAAU,UAAU,CAAC,OAAe,EAAE,UAA6B,EAAE;IACzE,MAAM,EAAE,QAAQ,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC,CAAA;IAC3I,OAAO,OAAO,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,CAAC,CAAA;AACxC,CAAC"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * 免 gas 授权(子路径 `@w3lib/evm-batch-call/permit`):EIP-2612 permit、DAI 风格 permit、Permit2(PermitSingle / PermitBatch / permitTransferFrom)。
3
+ * 构建 EIP-712 数据 → 用 ethers Signer 签名 → 本地验证 → 生成上链的 calldata。不放在主入口,不用时打包不会带上。
4
+ *
5
+ * ```ts
6
+ * import { buildPermit, signPermit, permitCalldata } from '@w3lib/evm-batch-call/permit'
7
+ *
8
+ * const permit = await buildPermit(provider, { token: USDC, owner, spender: router, value: 100_000_000n }) // 精确额度,30 分钟有效
9
+ * const signed = await signPermit(signer, permit) // signer:Wallet / 浏览器钱包的 JsonRpcSigner
10
+ * const data = permitCalldata(signed) // token.permit(...) 的 calldata,谁都可以提交
11
+ * ```
12
+ */
13
+ export { DEFAULT_PERMIT_DEADLINE, MAX_PERMIT_DEADLINE, MAX_UINT160, PERMIT2_ADDRESS, assertPermitSafe, buildPermit, buildPermit2Batch, buildPermit2Single, buildPermit2Transfer, detectPermit, permit2Calldata, permitCalldata, permitTransferFromCalldata, signPermit, verifyPermitSignature, type BuildPermitParams, type Permit, type Permit2AllowanceParams, type Permit2BatchParams, type Permit2TransferParams, type PermitKind, type PermitOptions, type PermitSupport, type SignedPermit, type TypedData, } from '../permit.js';
14
+ //# sourceMappingURL=permit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"permit.d.ts","sourceRoot":"","sources":["../../src/subpaths/permit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EACL,uBAAuB,EACvB,mBAAmB,EACnB,WAAW,EACX,eAAe,EACf,gBAAgB,EAChB,WAAW,EACX,iBAAiB,EACjB,kBAAkB,EAClB,oBAAoB,EACpB,YAAY,EACZ,eAAe,EACf,cAAc,EACd,0BAA0B,EAC1B,UAAU,EACV,qBAAqB,EACrB,KAAK,iBAAiB,EACtB,KAAK,MAAM,EACX,KAAK,sBAAsB,EAC3B,KAAK,kBAAkB,EACvB,KAAK,qBAAqB,EAC1B,KAAK,UAAU,EACf,KAAK,aAAa,EAClB,KAAK,aAAa,EAClB,KAAK,YAAY,EACjB,KAAK,SAAS,GACf,MAAM,cAAc,CAAA"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * 免 gas 授权(子路径 `@w3lib/evm-batch-call/permit`):EIP-2612 permit、DAI 风格 permit、Permit2(PermitSingle / PermitBatch / permitTransferFrom)。
3
+ * 构建 EIP-712 数据 → 用 ethers Signer 签名 → 本地验证 → 生成上链的 calldata。不放在主入口,不用时打包不会带上。
4
+ *
5
+ * ```ts
6
+ * import { buildPermit, signPermit, permitCalldata } from '@w3lib/evm-batch-call/permit'
7
+ *
8
+ * const permit = await buildPermit(provider, { token: USDC, owner, spender: router, value: 100_000_000n }) // 精确额度,30 分钟有效
9
+ * const signed = await signPermit(signer, permit) // signer:Wallet / 浏览器钱包的 JsonRpcSigner
10
+ * const data = permitCalldata(signed) // token.permit(...) 的 calldata,谁都可以提交
11
+ * ```
12
+ */
13
+ export { DEFAULT_PERMIT_DEADLINE, MAX_PERMIT_DEADLINE, MAX_UINT160, PERMIT2_ADDRESS, assertPermitSafe, buildPermit, buildPermit2Batch, buildPermit2Single, buildPermit2Transfer, detectPermit, permit2Calldata, permitCalldata, permitTransferFromCalldata, signPermit, verifyPermitSignature, } from '../permit.js';
14
+ //# sourceMappingURL=permit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"permit.js","sourceRoot":"","sources":["../../src/subpaths/permit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EACL,uBAAuB,EACvB,mBAAmB,EACnB,WAAW,EACX,eAAe,EACf,gBAAgB,EAChB,WAAW,EACX,iBAAiB,EACjB,kBAAkB,EAClB,oBAAoB,EACpB,YAAY,EACZ,eAAe,EACf,cAAc,EACd,0BAA0B,EAC1B,UAAU,EACV,qBAAqB,GAWtB,MAAM,cAAc,CAAA"}
@@ -34,7 +34,7 @@ export function getTokenPrices(tokens, options = {}) {
34
34
  * ```
35
35
  */
36
36
  export function getPortfolio(owner, options) {
37
- const { provider, own } = resolve(options, ['tokens', 'sources', 'lp', 'minUsd', 'onPriceError', 'fetch']);
38
- return portfolio(provider, owner, own);
37
+ const { provider, overrides, own } = resolve(options, ['tokens', 'sources', 'lp', 'minUsd', 'onPriceError', 'fetch']);
38
+ return portfolio(provider, owner, { ...own, ...(overrides.signal ? { signal: overrides.signal } : {}) });
39
39
  }
40
40
  //# sourceMappingURL=price.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"price.js","sourceRoot":"","sources":["../../src/subpaths/price.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAE,SAAS,EAAyC,MAAM,iBAAiB,CAAA;AAClF,OAAO,EAAE,WAAW,EAA4C,MAAM,aAAa,CAAA;AACnF,OAAO,EAAE,OAAO,EAAgC,MAAM,iBAAiB,CAAA;AAEvE,OAAO,EAAE,SAAS,EAA8D,MAAM,iBAAiB,CAAA;AACvG,OAAO,EACL,gBAAgB,EAChB,WAAW,EACX,aAAa,EACb,eAAe,EACf,aAAa,EACb,UAAU,EACV,WAAW,GAOZ,MAAM,aAAa,CAAA;AAIpB;;;;;;;GAOG;AACH,MAAM,UAAU,cAAc,CAAC,MAAyB,EAAE,UAAiC,EAAE;IAC3F,MAAM,EAAE,QAAQ,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,SAAS,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC,CAAA;IAC3E,OAAO,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,CAAC,CAAA;AAC3C,CAAC;AAID;;;;;;GAMG;AACH,MAAM,UAAU,YAAY,CAAC,KAAa,EAAE,OAA4B;IACtE,MAAM,EAAE,QAAQ,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE,cAAc,EAAE,OAAO,CAAC,CAAC,CAAA;IAC1G,OAAO,SAAS,CAAC,QAAQ,EAAE,KAAK,EAAE,GAAuB,CAAC,CAAA;AAC5D,CAAC"}
1
+ {"version":3,"file":"price.js","sourceRoot":"","sources":["../../src/subpaths/price.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAE,SAAS,EAAyC,MAAM,iBAAiB,CAAA;AAClF,OAAO,EAAE,WAAW,EAA4C,MAAM,aAAa,CAAA;AACnF,OAAO,EAAE,OAAO,EAAgC,MAAM,iBAAiB,CAAA;AAEvE,OAAO,EAAE,SAAS,EAA8D,MAAM,iBAAiB,CAAA;AACvG,OAAO,EACL,gBAAgB,EAChB,WAAW,EACX,aAAa,EACb,eAAe,EACf,aAAa,EACb,UAAU,EACV,WAAW,GAOZ,MAAM,aAAa,CAAA;AAIpB;;;;;;;GAOG;AACH,MAAM,UAAU,cAAc,CAAC,MAAyB,EAAE,UAAiC,EAAE;IAC3F,MAAM,EAAE,QAAQ,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,SAAS,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC,CAAA;IAC3E,OAAO,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,CAAC,CAAA;AAC3C,CAAC;AAID;;;;;;GAMG;AACH,MAAM,UAAU,YAAY,CAAC,KAAa,EAAE,OAA4B;IACtE,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE,cAAc,EAAE,OAAO,CAAC,CAAC,CAAA;IACrH,OAAO,SAAS,CAAC,QAAQ,EAAE,KAAK,EAAE,EAAE,GAAI,GAAwB,EAAE,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAA;AAChI,CAAC"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * 一键领取手续费和挖矿奖励(子路径 `@w3lib/evm-batch-call/rewards`):V3 / V4 仓位(含 Tron 的 SunSwap V3)未领取的手续费、
3
+ * PancakeSwap V3 MasterChef 的 CAKE(和质押仓位的手续费)、Aerodrome / Velodrome Slipstream gauge 的奖励。
4
+ * 不放在主入口,不用时打包不会带上这部分代码。
5
+ *
6
+ * - getClaimable:只读,列出每个仓位能领什么(数量 + 美元价值)
7
+ * - buildClaimAll:合并成尽量少的交易(V3 multicall、V4 一次 modifyLiquidities、MasterChef multicall),先模拟、剔除会失败的项
8
+ * - claimAll:构建后签名发送;`mode: '7702' | '4337' | '5792'` 时合成一笔原子交易
9
+ *
10
+ * ```ts
11
+ * import { claimAll, getClaimable } from '@w3lib/evm-batch-call/rewards'
12
+ *
13
+ * const c = await getClaimable(user, { chainId: 56, prices: true }) // c.items、c.totals、c.usd
14
+ * const { status, claimed } = await claimAll(multi, privateKey, { minUsd: 1 })
15
+ * ```
16
+ */
17
+ import { type ShortcutProviderOptions } from '../shortcuts.js';
18
+ import type { Claimable, ClaimableOptions } from '../rewards/types.js';
19
+ export { FARM_PROTOCOLS, buildClaimAll, claimAll, claimable } from '../rewards/index.js';
20
+ export type { ClaimAllOptions, ClaimAllSendOptions, ClaimAmount, ClaimItem, ClaimKind, ClaimPlan, ClaimResult, ClaimSkipped, ClaimTx, ClaimTxResult, Claimable, ClaimableOptions, FarmProtocol, } from '../rewards/types.js';
21
+ export type { LpProtocol } from '../lp.js';
22
+ export type { SignerInput, WriteResult, WriteStatus } from '../subpaths/write.js';
23
+ export interface GetClaimableOptions extends ClaimableOptions, ShortcutProviderOptions {
24
+ }
25
+ /** 查一个地址能领取的手续费和挖矿奖励,节点参数与 getBalances 相同 */
26
+ export declare function getClaimable(owner: string, options?: GetClaimableOptions): Promise<Claimable>;
27
+ //# sourceMappingURL=rewards.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rewards.d.ts","sourceRoot":"","sources":["../../src/subpaths/rewards.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EAAW,KAAK,uBAAuB,EAAE,MAAM,iBAAiB,CAAA;AAEvE,OAAO,KAAK,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAA;AAEtE,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AACxF,YAAY,EACV,eAAe,EACf,mBAAmB,EACnB,WAAW,EACX,SAAS,EACT,SAAS,EACT,SAAS,EACT,WAAW,EACX,YAAY,EACZ,OAAO,EACP,aAAa,EACb,SAAS,EACT,gBAAgB,EAChB,YAAY,GACb,MAAM,qBAAqB,CAAA;AAC5B,YAAY,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AAC1C,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAA;AAEjF,MAAM,WAAW,mBAAoB,SAAQ,gBAAgB,EAAE,uBAAuB;CAAG;AAEzF,6CAA6C;AAC7C,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,GAAE,mBAAwB,GAAG,OAAO,CAAC,SAAS,CAAC,CAGjG"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * 一键领取手续费和挖矿奖励(子路径 `@w3lib/evm-batch-call/rewards`):V3 / V4 仓位(含 Tron 的 SunSwap V3)未领取的手续费、
3
+ * PancakeSwap V3 MasterChef 的 CAKE(和质押仓位的手续费)、Aerodrome / Velodrome Slipstream gauge 的奖励。
4
+ * 不放在主入口,不用时打包不会带上这部分代码。
5
+ *
6
+ * - getClaimable:只读,列出每个仓位能领什么(数量 + 美元价值)
7
+ * - buildClaimAll:合并成尽量少的交易(V3 multicall、V4 一次 modifyLiquidities、MasterChef multicall),先模拟、剔除会失败的项
8
+ * - claimAll:构建后签名发送;`mode: '7702' | '4337' | '5792'` 时合成一笔原子交易
9
+ *
10
+ * ```ts
11
+ * import { claimAll, getClaimable } from '@w3lib/evm-batch-call/rewards'
12
+ *
13
+ * const c = await getClaimable(user, { chainId: 56, prices: true }) // c.items、c.totals、c.usd
14
+ * const { status, claimed } = await claimAll(multi, privateKey, { minUsd: 1 })
15
+ * ```
16
+ */
17
+ import { resolve } from '../shortcuts.js';
18
+ import { claimable } from '../rewards/index.js';
19
+ export { FARM_PROTOCOLS, buildClaimAll, claimAll, claimable } from '../rewards/index.js';
20
+ /** 查一个地址能领取的手续费和挖矿奖励,节点参数与 getBalances 相同 */
21
+ export function getClaimable(owner, options = {}) {
22
+ const { provider, overrides, own } = resolve(options, ['protocols', 'fees', 'rewards', 'v4', 'farms', 'gauges', 'maxPositions', 'prices', 'onPriceError', 'fetch']);
23
+ return claimable(provider, owner, { ...overrides, ...own });
24
+ }
25
+ //# sourceMappingURL=rewards.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rewards.js","sourceRoot":"","sources":["../../src/subpaths/rewards.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EAAE,OAAO,EAAgC,MAAM,iBAAiB,CAAA;AACvE,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAG/C,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAqBxF,6CAA6C;AAC7C,MAAM,UAAU,YAAY,CAAC,KAAa,EAAE,UAA+B,EAAE;IAC3E,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,QAAQ,EAAE,cAAc,EAAE,OAAO,CAAC,CAAC,CAAA;IACnK,OAAO,SAAS,CAAC,QAAQ,EAAE,KAAK,EAAE,EAAE,GAAG,SAAS,EAAE,GAAG,GAAG,EAAE,CAAC,CAAA;AAC7D,CAAC"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * 交易模拟(子路径 `@w3lib/evm-batch-call/simulate`):发送前先看一笔(或一串依赖的)交易会发生什么——成不成功、gas、
3
+ * 哪些资产进出(含美元价值)、给了什么授权、calldata 解码、风险提示。可以直接传 `buildSwap` / `buildRevokes` / 流动性构建的交易。
4
+ * 不放在主入口,不用时打包不会带上这部分代码。EVM 用 `eth_simulateV1`(不支持时退回 `eth_call`),Tron 用 `triggerconstantcontract`。
5
+ *
6
+ * ```ts
7
+ * import { getSimulation, getBatchSimulation } from '@w3lib/evm-batch-call/simulate'
8
+ *
9
+ * const sim = await getSimulation({ to: router, data, value }, { chainId: 1, from: user, usd: true })
10
+ * if (sim.warnings.some((w) => w.severity === 'danger')) alert(sim.warnings[0].message)
11
+ * const flow = await getBatchSimulation(plan.transactions, { chainId: 1, from: user }) // approve + swap,状态延续
12
+ * ```
13
+ */
14
+ import { type BatchSimulationResult, type SimulateOptions, type SimulateTx, type SimulationResult } from '../simulate.js';
15
+ import { type ShortcutProviderOptions } from '../shortcuts.js';
16
+ export { assertSimulation, decodeCalldata, decodeRevert, simulate, simulateBatch, type ApprovalChange, type BalanceChange, type BatchSimulationResult, type DecodedCall, type DecodedType, type SimulatedTransfer, type SimulateOptions, type SimulateTx, type SimulationResult, type SimulationWarning, type StateOverrides, type WarningSeverity, } from '../simulate.js';
17
+ export interface GetSimulationOptions extends SimulateOptions, ShortcutProviderOptions {
18
+ }
19
+ /** 模拟一笔交易,节点参数与 getBalances 相同 */
20
+ export declare function getSimulation(tx: SimulateTx, options?: GetSimulationOptions): Promise<SimulationResult>;
21
+ /** 按顺序模拟一串依赖前一笔的交易(也可以直接传 buildSwap 等的结果),节点参数与 getBalances 相同 */
22
+ export declare function getBatchSimulation(txs: readonly SimulateTx[] | {
23
+ transactions: readonly SimulateTx[];
24
+ }, options?: GetSimulationOptions): Promise<BatchSimulationResult>;
25
+ //# sourceMappingURL=simulate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"simulate.d.ts","sourceRoot":"","sources":["../../src/subpaths/simulate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,EAA2B,KAAK,qBAAqB,EAAE,KAAK,eAAe,EAAE,KAAK,UAAU,EAAE,KAAK,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AAClJ,OAAO,EAAW,KAAK,uBAAuB,EAAE,MAAM,iBAAiB,CAAA;AAEvE,OAAO,EACL,gBAAgB,EAChB,cAAc,EACd,YAAY,EACZ,QAAQ,EACR,aAAa,EACb,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,qBAAqB,EAC1B,KAAK,WAAW,EAChB,KAAK,WAAW,EAChB,KAAK,iBAAiB,EACtB,KAAK,eAAe,EACpB,KAAK,UAAU,EACf,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,EACtB,KAAK,cAAc,EACnB,KAAK,eAAe,GACrB,MAAM,gBAAgB,CAAA;AAIvB,MAAM,WAAW,oBAAqB,SAAQ,eAAe,EAAE,uBAAuB;CAAG;AAEzF,kCAAkC;AAClC,wBAAgB,aAAa,CAAC,EAAE,EAAE,UAAU,EAAE,OAAO,GAAE,oBAAyB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAG3G;AAED,kEAAkE;AAClE,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,SAAS,UAAU,EAAE,GAAG;IAAE,YAAY,EAAE,SAAS,UAAU,EAAE,CAAA;CAAE,EAAE,OAAO,GAAE,oBAAyB,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAG3K"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * 交易模拟(子路径 `@w3lib/evm-batch-call/simulate`):发送前先看一笔(或一串依赖的)交易会发生什么——成不成功、gas、
3
+ * 哪些资产进出(含美元价值)、给了什么授权、calldata 解码、风险提示。可以直接传 `buildSwap` / `buildRevokes` / 流动性构建的交易。
4
+ * 不放在主入口,不用时打包不会带上这部分代码。EVM 用 `eth_simulateV1`(不支持时退回 `eth_call`),Tron 用 `triggerconstantcontract`。
5
+ *
6
+ * ```ts
7
+ * import { getSimulation, getBatchSimulation } from '@w3lib/evm-batch-call/simulate'
8
+ *
9
+ * const sim = await getSimulation({ to: router, data, value }, { chainId: 1, from: user, usd: true })
10
+ * if (sim.warnings.some((w) => w.severity === 'danger')) alert(sim.warnings[0].message)
11
+ * const flow = await getBatchSimulation(plan.transactions, { chainId: 1, from: user }) // approve + swap,状态延续
12
+ * ```
13
+ */
14
+ import { simulate, simulateBatch } from '../simulate.js';
15
+ import { resolve } from '../shortcuts.js';
16
+ export { assertSimulation, decodeCalldata, decodeRevert, simulate, simulateBatch, } from '../simulate.js';
17
+ const OWN = ['from', 'watch', 'stateOverrides', 'gas', 'fee', 'usd', 'risk', 'forceCall'];
18
+ /** 模拟一笔交易,节点参数与 getBalances 相同 */
19
+ export function getSimulation(tx, options = {}) {
20
+ const { provider, overrides, own } = resolve(options, OWN);
21
+ return simulate(provider, tx, { ...own, ...(overrides.blockTag === undefined ? {} : { blockTag: overrides.blockTag }) });
22
+ }
23
+ /** 按顺序模拟一串依赖前一笔的交易(也可以直接传 buildSwap 等的结果),节点参数与 getBalances 相同 */
24
+ export function getBatchSimulation(txs, options = {}) {
25
+ const { provider, overrides, own } = resolve(options, OWN);
26
+ return simulateBatch(provider, txs, { ...own, ...(overrides.blockTag === undefined ? {} : { blockTag: overrides.blockTag }) });
27
+ }
28
+ //# sourceMappingURL=simulate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"simulate.js","sourceRoot":"","sources":["../../src/subpaths/simulate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,EAAE,QAAQ,EAAE,aAAa,EAA4F,MAAM,gBAAgB,CAAA;AAClJ,OAAO,EAAE,OAAO,EAAgC,MAAM,iBAAiB,CAAA;AAEvE,OAAO,EACL,gBAAgB,EAChB,cAAc,EACd,YAAY,EACZ,QAAQ,EACR,aAAa,GAad,MAAM,gBAAgB,CAAA;AAEvB,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,OAAO,EAAE,gBAAgB,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,CAAU,CAAA;AAIlG,kCAAkC;AAClC,MAAM,UAAU,aAAa,CAAC,EAAc,EAAE,UAAgC,EAAE;IAC9E,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,CAAA;IAC1D,OAAO,QAAQ,CAAC,QAAQ,EAAE,EAAE,EAAE,EAAE,GAAG,GAAG,EAAE,GAAG,CAAC,SAAS,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,SAAS,CAAC,QAAQ,EAAE,CAAC,EAAE,CAAC,CAAA;AAC1H,CAAC;AAED,kEAAkE;AAClE,MAAM,UAAU,kBAAkB,CAAC,GAAoE,EAAE,UAAgC,EAAE;IACzI,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,CAAA;IAC1D,OAAO,aAAa,CAAC,QAAQ,EAAE,GAAG,EAAE,EAAE,GAAG,GAAG,EAAE,GAAG,CAAC,SAAS,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,SAAS,CAAC,QAAQ,EAAE,CAAC,EAAE,CAAC,CAAA;AAChI,CAAC"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * 智能账户批量执行(子路径 `@w3lib/evm-batch-call/smart-account`):ERC-4337(EntryPoint v0.7 / v0.8)UserOperation 的构建 / 哈希 / 签名、
3
+ * bundler 与 ERC-7677 paymaster 客户端、自己打包(handleOps)、EIP-5792(wallet_sendCalls)。
4
+ * 通常通过 `/write` 的 `mode: '4337' | '5792'`、`mode: '7702' + sponsor` 使用,这里是底层积木。
5
+ *
6
+ * ```ts
7
+ * import { BundlerClient } from '@w3lib/evm-batch-call/smart-account'
8
+ * const bundler = new BundlerClient('https://public.pimlico.io/v2/8453/rpc')
9
+ * await bundler.supportedEntryPoints()
10
+ * ```
11
+ */
12
+ export { BundlerClient, PaymasterClient, type GasEstimate, type PaymasterContext, type PaymasterFields, type PaymasterHook, type RpcClientOptions, type UserOperationReceipt } from '../smartAccount/clients.js';
13
+ export { DUMMY_SIGNATURE, EIP7702_MARKER, ENTRY_POINT_V07, ENTRY_POINT_V08, entryPointAddress, getUserOpHash, packUserOp, userOpToRpc, userOpTypedData, type EntryPointVersion, type PackedUserOperation, type UserOperation, } from '../smartAccount/userOp.js';
14
+ import type { Provider } from '../provider.js';
15
+ import type { SmartAccountOptions } from '../smartAccount/send.js';
16
+ export { SIMPLE_ACCOUNT_FACTORY_V07, SIMPLE_ACCOUNT_FACTORY_V08, encodeExecuteBatch, type SmartAccountKind } from '../smartAccount/account.js';
17
+ export { getCallsStatus, getWalletCapabilities, sendCalls, waitForCalls, type CallsStatus, type Eip1193Like, type SendCallsRequest, type WalletCapabilities } from '../smartAccount/eip5792.js';
18
+ export type { SmartAccountOptions };
19
+ /** owner 对应的 SimpleAccount 地址(部署前就能算出,向它转入资产后再用 `mode: '4337'` 发送) */
20
+ export declare function getSimpleAccount(provider: Provider, owner: string, options?: Pick<SmartAccountOptions, 'entryPoint' | 'salt' | 'factory'>): Promise<{
21
+ address: string;
22
+ deployed: boolean;
23
+ }>;
24
+ //# sourceMappingURL=smart-account.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"smart-account.d.ts","sourceRoot":"","sources":["../../src/subpaths/smart-account.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,KAAK,WAAW,EAAE,KAAK,gBAAgB,EAAE,KAAK,eAAe,EAAE,KAAK,aAAa,EAAE,KAAK,gBAAgB,EAAE,KAAK,oBAAoB,EAAE,MAAM,4BAA4B,CAAA;AAChN,OAAO,EACL,eAAe,EACf,cAAc,EACd,eAAe,EACf,eAAe,EACf,iBAAiB,EACjB,aAAa,EACb,UAAU,EACV,WAAW,EACX,eAAe,EACf,KAAK,iBAAiB,EACtB,KAAK,mBAAmB,EACxB,KAAK,aAAa,GACnB,MAAM,2BAA2B,CAAA;AAClC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAG9C,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAA;AAClE,OAAO,EAAE,0BAA0B,EAAE,0BAA0B,EAAE,kBAAkB,EAAE,KAAK,gBAAgB,EAAE,MAAM,4BAA4B,CAAA;AAC9I,OAAO,EAAE,cAAc,EAAE,qBAAqB,EAAE,SAAS,EAAE,YAAY,EAAE,KAAK,WAAW,EAAE,KAAK,WAAW,EAAE,KAAK,gBAAgB,EAAE,KAAK,kBAAkB,EAAE,MAAM,4BAA4B,CAAA;AAC/L,YAAY,EAAE,mBAAmB,EAAE,CAAA;AAEnC,sEAAsE;AACtE,wBAAsB,gBAAgB,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,GAAE,IAAI,CAAC,mBAAmB,EAAE,YAAY,GAAG,MAAM,GAAG,SAAS,CAAM,GAAG,OAAO,CAAC;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAA;CAAE,CAAC,CAIrM"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * 智能账户批量执行(子路径 `@w3lib/evm-batch-call/smart-account`):ERC-4337(EntryPoint v0.7 / v0.8)UserOperation 的构建 / 哈希 / 签名、
3
+ * bundler 与 ERC-7677 paymaster 客户端、自己打包(handleOps)、EIP-5792(wallet_sendCalls)。
4
+ * 通常通过 `/write` 的 `mode: '4337' | '5792'`、`mode: '7702' + sponsor` 使用,这里是底层积木。
5
+ *
6
+ * ```ts
7
+ * import { BundlerClient } from '@w3lib/evm-batch-call/smart-account'
8
+ * const bundler = new BundlerClient('https://public.pimlico.io/v2/8453/rpc')
9
+ * await bundler.supportedEntryPoints()
10
+ * ```
11
+ */
12
+ export { BundlerClient, PaymasterClient } from '../smartAccount/clients.js';
13
+ export { DUMMY_SIGNATURE, EIP7702_MARKER, ENTRY_POINT_V07, ENTRY_POINT_V08, entryPointAddress, getUserOpHash, packUserOp, userOpToRpc, userOpTypedData, } from '../smartAccount/userOp.js';
14
+ import { WriteRpc } from '../write/rpc.js';
15
+ import { resolveSimpleAccount } from '../smartAccount/account.js';
16
+ export { SIMPLE_ACCOUNT_FACTORY_V07, SIMPLE_ACCOUNT_FACTORY_V08, encodeExecuteBatch } from '../smartAccount/account.js';
17
+ export { getCallsStatus, getWalletCapabilities, sendCalls, waitForCalls } from '../smartAccount/eip5792.js';
18
+ /** owner 对应的 SimpleAccount 地址(部署前就能算出,向它转入资产后再用 `mode: '4337'` 发送) */
19
+ export async function getSimpleAccount(provider, owner, options = {}) {
20
+ const rpc = await WriteRpc.from(provider);
21
+ const { address, deployed } = await resolveSimpleAccount(rpc, owner, options.entryPoint ?? '0.7', options.salt, options.factory);
22
+ return { address, deployed };
23
+ }
24
+ //# sourceMappingURL=smart-account.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"smart-account.js","sourceRoot":"","sources":["../../src/subpaths/smart-account.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAE,aAAa,EAAE,eAAe,EAAuI,MAAM,4BAA4B,CAAA;AAChN,OAAO,EACL,eAAe,EACf,cAAc,EACd,eAAe,EACf,eAAe,EACf,iBAAiB,EACjB,aAAa,EACb,UAAU,EACV,WAAW,EACX,eAAe,GAIhB,MAAM,2BAA2B,CAAA;AAElC,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAA;AAC1C,OAAO,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAA;AAEjE,OAAO,EAAE,0BAA0B,EAAE,0BAA0B,EAAE,kBAAkB,EAAyB,MAAM,4BAA4B,CAAA;AAC9I,OAAO,EAAE,cAAc,EAAE,qBAAqB,EAAE,SAAS,EAAE,YAAY,EAAsF,MAAM,4BAA4B,CAAA;AAG/L,sEAAsE;AACtE,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,QAAkB,EAAE,KAAa,EAAE,UAAwE,EAAE;IAClJ,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;IACzC,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,MAAM,oBAAoB,CAAC,GAAG,EAAE,KAAK,EAAE,OAAO,CAAC,UAAU,IAAI,KAAK,EAAE,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,CAAA;IAChI,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAA;AAC9B,CAAC"}
package/dist/swap.d.ts CHANGED
@@ -8,6 +8,7 @@ import type { LiquidityTxResult } from './liquidity/types.js';
8
8
  import { type LpProtocol, type LpToken } from './lp.js';
9
9
  import type { BlockTag } from './aggregate.js';
10
10
  import type { Provider } from './provider.js';
11
+ import type { SignedPermit } from './permit.js';
11
12
  import type { BatchCallOptions } from './write/batch.js';
12
13
  import type { SignerInput } from './write/signer.js';
13
14
  /** V3 协议的报价合约(QuoterV2)和兑换合约(SwapRouter02 接口),按 协议 id → chainId。2026-10 在链上核对过(Router 的 WETH9 / deployer,并用 eth_call 实际执行过兑换) */
@@ -30,8 +31,20 @@ export interface SwapOptions {
30
31
  deadline?: number;
31
32
  /** 收到代币的地址,默认 owner */
32
33
  recipient?: string;
33
- /** 授权额度:'exact'(默认,本次卖出的数量)或 'max' */
34
- approve?: 'exact' | 'max';
34
+ /**
35
+ * 授权方式:
36
+ * - 'exact'(默认):授权本次卖出的数量;'max':无限额度
37
+ * - 'permit':用 EIP-2612 签名代替授权交易(要代币支持,见 /permit 的 detectPermit)。V3 路线(SwapRouter02 / SmartRouter)把 selfPermit 放进同一笔 multicall,
38
+ * 一次签名、一笔交易;V2 路线的 Router 没有 selfPermit,只有 `atomic` 批量(7702 / 4337 / 5792)发送时才用 permit,否则仍然是普通授权
39
+ * - 'permit2':内置的 V2 / V3 路由都不使用 Permit2(它们直接 transferFrom),所以会退回普通的 'exact' 授权;结果的 plan.approval 里有说明
40
+ * - 'auto':能用 permit 就用,否则普通授权
41
+ * 退回普通授权时 plan.approval.method 为 'approve',reason 写明原因
42
+ */
43
+ approve?: 'exact' | 'max' | 'permit' | 'permit2' | 'auto';
44
+ /** 交易会在一笔原子批量里发送(`swap` 的 mode 为 7702 / 4337 / 5792 时自动为 true):V2 路线才能把 permit 和兑换放进同一笔 */
45
+ atomic?: boolean;
46
+ /** 已签名的 permit(`swap` 内部使用):V3 路线嵌入 multicall 的 selfPermit,V2 路线放在兑换前;不再生成授权交易 */
47
+ signedPermit?: SignedPermit;
35
48
  /**
36
49
  * 代币的转账税(比例,0.05 = 5%),默认 0。V2 报价(getAmountsOut)不含转账税,带税的代币
37
50
  * 实际收到的比报价少,最少收到按 (1 − slippage) × (1 − tax) 算,否则会因 INSUFFICIENT_OUTPUT_AMOUNT 回滚。
@@ -59,8 +72,8 @@ export interface SwapRoute {
59
72
  amountOut: string;
60
73
  }
61
74
  export interface SwapTx {
62
- /** approve:卖出的代币授权给 Router;swap:兑换 */
63
- kind: 'approve' | 'swap';
75
+ /** approve:卖出的代币授权给 Router;permit:提交 EIP-2612 签名(V2 路线批量发送时);swap:兑换 */
76
+ kind: 'approve' | 'permit' | 'swap';
64
77
  to: string;
65
78
  data: string;
66
79
  /** 附带的主币(最小单位):卖出主币时为卖出的数量 */
@@ -88,6 +101,23 @@ export interface SwapPlan {
88
101
  routes: SwapRoute[];
89
102
  /** 按顺序发送的交易(授权在前) */
90
103
  transactions: SwapTx[];
104
+ /** 请求了 permit / permit2 / auto 时:实际采用的授权方式和原因 */
105
+ approval?: SwapApproval;
106
+ }
107
+ export interface SwapApproval {
108
+ requested: 'permit' | 'permit2' | 'auto';
109
+ /** 'permit':用签名;'approve':退回普通授权交易(reason 说明);'none':不需要授权(卖出主币 / 额度已够) */
110
+ method: 'permit' | 'approve' | 'none';
111
+ /** permit 的提交方式:selfPermit(V3 的 multicall 内)/ batch(和兑换放在同一笔原子批量) */
112
+ via?: 'selfPermit' | 'batch';
113
+ reason?: string;
114
+ /** 要签的 permit(owner 授权 spender 精确的卖出数量,签名有效期与兑换的 deadline 相同) */
115
+ permit?: {
116
+ token: string;
117
+ spender: string;
118
+ value: string;
119
+ deadline: number;
120
+ };
91
121
  }
92
122
  /** 这条链上能兑换的协议:V2 要有 Router,V3 要有报价和兑换合约(V3_SWAP_CONTRACTS) */
93
123
  export declare function swapProtocols(chainId: number): LpProtocol[];
@@ -106,13 +136,20 @@ export type SwapTxResult = Omit<LiquidityTxResult, 'kind'> & {
106
136
  };
107
137
  export interface SwapResult {
108
138
  plan: SwapPlan;
109
- /** 每笔交易的结果(授权、兑换) */
139
+ /** 每笔交易的结果(授权 / permit、兑换) */
110
140
  results: SwapTxResult[];
111
141
  /** 兑换那一笔的状态和哈希 */
112
142
  status: LiquidityTxResult['status'];
113
143
  hash: string | null;
144
+ /** 请求 permit / permit2 / auto 时:实际采用的授权方式(同 plan.approval,退回普通授权时有原因) */
145
+ approval?: SwapApproval;
114
146
  }
115
147
  export interface SwapSendOptions extends SwapOptions, Omit<BatchCallOptions, 'mode' | 'continueOnError' | 'onUpdate'> {
148
+ /**
149
+ * 发送方式:'tx'(默认,授权和兑换分别发,授权确认后重新报价);
150
+ * '7702' / '4337' / '5792':授权(或 permit)和兑换放进同一笔原子批量,见 BatchCallOptions.mode
151
+ */
152
+ mode?: 'tx' | '7702' | '4337' | '5792';
116
153
  onUpdate?: (result: SwapTxResult) => void;
117
154
  }
118
155
  /**
@@ -122,6 +159,9 @@ export interface SwapSendOptions extends SwapOptions, Omit<BatchCallOptions, 'mo
122
159
  * ```ts
123
160
  * const r = await swap(provider, key, { tokenIn: USDT, tokenOut: NATIVE_TOKEN, amountInFormatted: '100' }, { slippage: 0.01 })
124
161
  * r.status // 'confirmed'
162
+ *
163
+ * // 用 EIP-2612 签名代替授权交易(V3 路线一笔交易完成;不支持时退回普通授权,r.approval.reason 说明原因)
164
+ * await swap(provider, signer, params, { approve: 'auto' })
125
165
  * ```
126
166
  */
127
167
  export declare function swap(provider: Provider, from: SignerInput, params: SwapParams, options?: SwapSendOptions): Promise<SwapResult>;
@@ -1 +1 @@
1
- {"version":3,"file":"swap.d.ts","sourceRoot":"","sources":["../src/swap.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"swap.d.ts","sourceRoot":"","sources":["../src/swap.ts"],"names":[],"mappings":"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"}
package/dist/swap.js CHANGED
@@ -3,7 +3,7 @@
3
3
  * 批量报价(V2 用 Router 的 getAmountsOut,V3 用 QuoterV2,按 gas 分成几次并发的 eth_call),选输出最多的;按滑点算最少收到的数量,
4
4
  * 构建授权 + 兑换的交易(V2 走 Router 的 swapExact…SupportingFeeOnTransferTokens,V3 走 SwapRouter02 / PancakeSwap SmartRouter 的 multicall)
5
5
  */
6
- import { Interface } from 'ethers';
6
+ import { Interface, getAddress } from 'ethers';
7
7
  import { approvals, createCtx, evm, fmt, isNative, minus, out, parseAmount, same, tokenInfo } from './liquidity/common.js';
8
8
  import { LP_PROTOCOLS, LP_QUOTE_TOKENS } from './lp.js';
9
9
  /** V3 协议的报价合约(QuoterV2)和兑换合约(SwapRouter02 接口),按 协议 id → chainId。2026-10 在链上核对过(Router 的 WETH9 / deployer,并用 eth_call 实际执行过兑换) */
@@ -33,6 +33,7 @@ const v2RouterInterface = new Interface([
33
33
  'function swapExactETHForTokensSupportingFeeOnTransferTokens(uint256 amountOutMin, address[] path, address to, uint256 deadline) payable',
34
34
  'function swapExactTokensForETHSupportingFeeOnTransferTokens(uint256 amountIn, uint256 amountOutMin, address[] path, address to, uint256 deadline)',
35
35
  ]);
36
+ const permitInterface = new Interface(['function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)']);
36
37
  const v3FactoryInterface = new Interface(['function getPool(address tokenA, address tokenB, uint24 fee) view returns (address)']);
37
38
  const v3PoolInterface = new Interface(['function liquidity() view returns (uint128)']);
38
39
  /** QuoterV2 很费 gas(池子很薄时一次可达上千万):每次 eth_call 只放几个报价,多个 eth_call 并发,避免超过节点的 gas 上限后被悄悄截掉 */
@@ -47,6 +48,7 @@ const swapRouterInterface = new Interface([
47
48
  'function exactInputSingle((address tokenIn, address tokenOut, uint24 fee, address recipient, uint256 amountIn, uint256 amountOutMinimum, uint160 sqrtPriceLimitX96) params) payable returns (uint256 amountOut)',
48
49
  'function exactInput((bytes path, address recipient, uint256 amountIn, uint256 amountOutMinimum) params) payable returns (uint256 amountOut)',
49
50
  'function unwrapWETH9(uint256 amountMinimum, address recipient) payable',
51
+ 'function selfPermitIfNecessary(address token, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) payable',
50
52
  'function multicall(uint256 deadline, bytes[] data) payable returns (bytes[] results)',
51
53
  ]);
52
54
  /** 这条链上能兑换的协议:V2 要有 Router,V3 要有报价和兑换合约(V3_SWAP_CONTRACTS) */
@@ -163,7 +165,7 @@ function amountOf(c, result) {
163
165
  */
164
166
  export async function buildSwap(provider, owner, params, options = {}) {
165
167
  const { slippage, deadline, recipient, approve } = options;
166
- const ctx = await createCtx(provider, owner, { slippage, deadline, recipient, approve });
168
+ const ctx = await createCtx(provider, owner, { slippage, deadline, recipient, approve: approve === 'max' ? 'max' : 'exact' });
167
169
  const wrapped = LP_QUOTE_TOKENS[ctx.chainId]?.[0];
168
170
  const nativeIn = isNative(ctx, params.tokenIn);
169
171
  const nativeOut = isNative(ctx, params.tokenOut);
@@ -200,7 +202,16 @@ export async function buildSwap(provider, owner, params, options = {}) {
200
202
  // approvals 只会返回 kind 为 'approve' 的交易
201
203
  // Router 在 Tron 上是 T 地址:授权的 ABI 参数要用 0x 格式
202
204
  const transactions = (nativeIn ? [] : await approvals(ctx, [{ token: tokenIn, spender: evm(best.router), amount: amountIn }]));
203
- transactions.push(swapTx(ctx, best, amountIn, amountOutMin, nativeIn, nativeOut));
205
+ let approval;
206
+ const requested = options.approve;
207
+ if (requested === 'permit' || requested === 'permit2' || requested === 'auto') {
208
+ approval = await decideApproval(ctx, requested, best, tokenIn, amountIn, nativeIn, transactions.some((t) => t.kind === 'approve'), options);
209
+ }
210
+ let permitCall;
211
+ if (options.signedPermit && approval?.method === 'permit') {
212
+ permitCall = applySignedPermit(options.signedPermit, approval, ctx, transactions);
213
+ }
214
+ transactions.push(swapTx(ctx, best, amountIn, amountOutMin, nativeIn, nativeOut, permitCall));
204
215
  const route = (c) => ({
205
216
  protocol: c.protocol.id,
206
217
  protocolName: c.protocol.name,
@@ -224,9 +235,50 @@ export async function buildSwap(provider, owner, params, options = {}) {
224
235
  route: route(best),
225
236
  routes: routes.map(route),
226
237
  transactions,
238
+ ...(approval ? { approval } : {}),
227
239
  };
228
240
  }
229
- function swapTx(ctx, c, amountIn, amountOutMin, nativeIn, nativeOut) {
241
+ /** permit / permit2 / auto:判断这条路线和这个代币能不能用签名代替授权交易,不能的退回普通授权并写明原因 */
242
+ async function decideApproval(ctx, requested, best, tokenIn, amountIn, nativeIn, needsApprove, options) {
243
+ if (nativeIn || !needsApprove)
244
+ return { requested, method: 'none' };
245
+ const fallback = (reason) => ({ requested, method: 'approve', reason });
246
+ if (requested === 'permit2') {
247
+ return fallback('The built-in V2 / V3 routers pull tokens with transferFrom and do not consume Permit2 signatures; used a normal exact approve');
248
+ }
249
+ if (ctx.tron)
250
+ return fallback('permit is not available on Tron; used a normal approve');
251
+ const { detectPermit } = await import('./permit.js');
252
+ const support = await detectPermit(ctx.provider, tokenIn);
253
+ if (!support.kind)
254
+ return fallback(`${support.reason}; used a normal approve`);
255
+ if (support.kind === 'dai')
256
+ return fallback('A DAI-style permit can only grant an unlimited allowance; used a normal exact approve');
257
+ const via = best.version === 'v3' ? 'selfPermit' : 'batch';
258
+ if (via === 'batch' && !options.atomic) {
259
+ return fallback("V2 routers have no selfPermit, so a separate permit() transaction saves nothing; use mode '7702' / '4337' / '5792' to send the permit and the swap atomically. Used a normal approve");
260
+ }
261
+ return { requested, method: 'permit', via, permit: { token: tokenIn, spender: evm(best.router), value: amountIn.toString(), deadline: ctx.deadline } };
262
+ }
263
+ /** 已签名的 permit 放进交易:V3 返回 selfPermit 的 calldata(嵌进 multicall),V2 往 transactions 里加一笔 permit 交易 */
264
+ function applySignedPermit(signed, approval, ctx, transactions) {
265
+ const want = approval.permit;
266
+ const p = signed.permit;
267
+ if (p.kind !== 'eip2612' || getAddress(p.tokens[0]) !== getAddress(want.token) || getAddress(p.spender) !== getAddress(want.spender) || p.owner !== ctx.owner || BigInt(p.amounts[0]) !== BigInt(want.value)) {
268
+ throw new Error('The signed permit does not match the swap (token / spender / owner / amount)');
269
+ }
270
+ // 授权交易换成 permit
271
+ const at = transactions.findIndex((t) => t.kind === 'approve');
272
+ transactions.splice(at, transactions.length);
273
+ if (approval.via === 'selfPermit') {
274
+ return swapRouterInterface.encodeFunctionData('selfPermitIfNecessary', [want.token, want.value, p.deadline, signed.v, signed.r, signed.s]);
275
+ }
276
+ const m = p.typedData.message;
277
+ const data = permitInterface.encodeFunctionData('permit', [m.owner, m.spender, m.value, m.deadline, signed.v, signed.r, signed.s]);
278
+ transactions.push({ kind: 'permit', to: out(ctx, want.token), data, value: '0', token: out(ctx, want.token), spender: out(ctx, want.spender), amount: want.value });
279
+ return undefined;
280
+ }
281
+ function swapTx(ctx, c, amountIn, amountOutMin, nativeIn, nativeOut, selfPermit) {
230
282
  const value = nativeIn ? amountIn.toString() : '0';
231
283
  if (c.version === 'v2') {
232
284
  const data = nativeIn
@@ -243,7 +295,7 @@ function swapTx(ctx, c, amountIn, amountOutMin, nativeIn, nativeOut) {
243
295
  { tokenIn: c.path[0], tokenOut: c.path[1], fee: c.fees[0], recipient, amountIn, amountOutMinimum: amountOutMin, sqrtPriceLimitX96: 0n },
244
296
  ])
245
297
  : swapRouterInterface.encodeFunctionData('exactInput', [{ path: encodePath(c.path, c.fees), recipient, amountIn, amountOutMinimum: amountOutMin }]);
246
- const calls = nativeOut ? [swap, swapRouterInterface.encodeFunctionData('unwrapWETH9', [amountOutMin, ctx.recipient])] : [swap];
298
+ const calls = [...(selfPermit ? [selfPermit] : []), swap, ...(nativeOut ? [swapRouterInterface.encodeFunctionData('unwrapWETH9', [amountOutMin, ctx.recipient])] : [])];
247
299
  return { kind: 'swap', to: out(ctx, c.router), data: swapRouterInterface.encodeFunctionData('multicall', [ctx.deadline, calls]), value };
248
300
  }
249
301
  /**
@@ -253,22 +305,63 @@ function swapTx(ctx, c, amountIn, amountOutMin, nativeIn, nativeOut) {
253
305
  * ```ts
254
306
  * const r = await swap(provider, key, { tokenIn: USDT, tokenOut: NATIVE_TOKEN, amountInFormatted: '100' }, { slippage: 0.01 })
255
307
  * r.status // 'confirmed'
308
+ *
309
+ * // 用 EIP-2612 签名代替授权交易(V3 路线一笔交易完成;不支持时退回普通授权,r.approval.reason 说明原因)
310
+ * await swap(provider, signer, params, { approve: 'auto' })
256
311
  * ```
257
312
  */
258
313
  export async function swap(provider, from, params, options = {}) {
259
314
  const [{ batchCall, tronModule }, { resolveSigner }, { emptyOutcome, toWriteResult }] = await Promise.all([import('./write/batch.js'), import('./write/signer.js'), import('./write/send.js')]);
260
315
  const tron = await tronModule(provider);
261
- const owner = tron ? await tron.tronSignerAddress(from) : (await resolveSigner(from)).address;
262
- let plan = await buildSwap(provider, owner, params, options);
263
- const send = async (txs) => (await batchCall(provider, txs.map((tx) => ({ from, to: tx.to, data: tx.data, value: BigInt(tx.value) })), {
316
+ const resolved = tron ? null : await resolveSigner(from);
317
+ const owner = tron ? await tron.tronSignerAddress(from) : resolved.address;
318
+ const mode = options.mode ?? 'tx';
319
+ const atomic = mode !== 'tx';
320
+ // 4337 的 SimpleAccount:资产在账户地址里,兑换的 owner 是账户(合约账户不能签 EIP-2612,不用 permit)
321
+ let holder = owner;
322
+ let smartHolder = false;
323
+ if (mode === '4337' && (options.smartAccount?.account ?? 'simple') === 'simple') {
324
+ const [{ resolveSimpleAccount }, { WriteRpc }] = await Promise.all([import('./smartAccount/account.js'), import('./write/rpc.js')]);
325
+ const sa = options.smartAccount;
326
+ holder = (await resolveSimpleAccount(await WriteRpc.from(provider), owner, sa?.entryPoint ?? '0.7', sa?.salt, sa?.factory)).address;
327
+ smartHolder = true;
328
+ }
329
+ const wantsPermit = options.approve === 'permit' || options.approve === 'permit2' || options.approve === 'auto';
330
+ let plan = await buildSwap(provider, holder, params, { ...options, atomic, ...(smartHolder && wantsPermit ? { approve: 'exact' } : {}) });
331
+ if (smartHolder && wantsPermit && plan.transactions.length > 1) {
332
+ plan.approval = { requested: options.approve, method: 'approve', reason: 'The 4337 smart account is a contract and cannot sign EIP-2612 permits; used a normal approve' };
333
+ }
334
+ if (plan.approval?.method === 'permit' && resolved) {
335
+ // 签 permit:精确的卖出数量、有效期与兑换的 deadline 相同;用户拒绝签名就整体中止(不悄悄改成发授权交易)
336
+ const { buildPermit, signPermit } = await import('./permit.js');
337
+ const want = plan.approval.permit;
338
+ const permit = await buildPermit(provider, { token: want.token, owner: holder, spender: want.spender, value: want.value }, { deadlineAt: want.deadline });
339
+ const signed = await signPermit(resolved.signer, permit, { chainId: await provider.getChainId() });
340
+ try {
341
+ plan = await buildSwap(provider, holder, params, { ...options, atomic, signedPermit: signed });
342
+ }
343
+ catch (err) {
344
+ // 签名后重新报价,最优路线变了(路由 / 版本 / 数量不同),签名对不上:改用普通授权,不让已经签过的请求白白中止
345
+ if (!/signed permit does not match/.test(err instanceof Error ? err.message : String(err)))
346
+ throw err;
347
+ plan = await buildSwap(provider, holder, params, { ...options, atomic, approve: 'exact' });
348
+ if (plan.approval)
349
+ plan.approval = { ...plan.approval, requested: options.approve, method: 'approve', reason: 'The best route changed after the permit was signed; used a normal approve' };
350
+ }
351
+ }
352
+ const send = async (txs, asMode = 'tx') => (await batchCall(provider, txs.map((tx) => ({ from, to: tx.to, data: tx.data, value: BigInt(tx.value) })), {
264
353
  ...options,
265
- mode: 'tx',
354
+ mode: asMode === 'atomic' ? mode : 'tx',
266
355
  continueOnError: false,
267
356
  onUpdate: options.onUpdate ? (r) => options.onUpdate?.({ ...r, kind: txs[r.index].kind }) : undefined,
268
357
  })).map((r, i) => ({ ...r, kind: txs[i].kind }));
269
358
  const txs = plan.transactions;
270
359
  let results;
271
- if (txs.length === 1) {
360
+ if (atomic) {
361
+ // 授权 / permit 和兑换在同一笔原子批量里:要么都成功,要么都不生效
362
+ results = await send(txs, 'atomic');
363
+ }
364
+ else if (txs.length === 1) {
272
365
  results = await send(txs);
273
366
  }
274
367
  else {
@@ -276,8 +369,11 @@ export async function swap(provider, from, params, options = {}) {
276
369
  // 不会因为授权等得久而过期或按旧价成交
277
370
  const approved = await send(txs.slice(0, -1));
278
371
  const last = txs[txs.length - 1];
372
+ const approval = plan.approval;
279
373
  if (approved.every((r) => r.status === 'confirmed')) {
280
- plan = await buildSwap(provider, owner, params, options);
374
+ plan = await buildSwap(provider, holder, params, { ...options, approve: options.approve === 'max' ? 'max' : 'exact' });
375
+ if (approval)
376
+ plan.approval = approval; // 重新报价时额度已够:保留最初的选择和原因
281
377
  const fresh = plan.transactions[plan.transactions.length - 1];
282
378
  results = [...approved, ...(await send([fresh])).map((r) => ({ ...r, index: txs.length - 1 }))];
283
379
  }
@@ -286,6 +382,6 @@ export async function swap(provider, from, params, options = {}) {
286
382
  }
287
383
  }
288
384
  const main = results[results.length - 1];
289
- return { plan, results, status: main.status, hash: main.hash };
385
+ return { plan, results, status: main.status, hash: main.hash, ...(plan.approval ? { approval: plan.approval } : {}) };
290
386
  }
291
387
  //# sourceMappingURL=swap.js.map