four-flap-meme-sdk 2.0.0 → 2.2.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 (220) hide show
  1. package/dist/__tests__/subpath-exports.test.js +64 -0
  2. package/dist/chains/bsc/iro.d.ts +5 -0
  3. package/dist/chains/bsc/iro.js +4 -0
  4. package/dist/chains/eni/flat-aliases.d.ts +10 -0
  5. package/dist/chains/eni/flat-aliases.js +8 -0
  6. package/dist/chains/eni/index.d.ts +1 -0
  7. package/dist/chains/eni/index.js +1 -0
  8. package/dist/chains/index.d.ts +13 -0
  9. package/dist/chains/index.js +13 -0
  10. package/dist/chains/xlayer/eip7702/flat-aliases.d.ts +13 -0
  11. package/dist/chains/xlayer/eip7702/flat-aliases.js +10 -0
  12. package/dist/chains/xlayer/eip7702/index.d.ts +1 -0
  13. package/dist/chains/xlayer/eip7702/index.js +1 -0
  14. package/dist/chains/xlayer/index.d.ts +3 -2
  15. package/dist/chains/xlayer/index.js +4 -7
  16. package/dist/flap/index.d.ts +10 -0
  17. package/dist/flap/index.js +8 -0
  18. package/dist/merkle/index.d.ts +12 -0
  19. package/dist/merkle/index.js +11 -0
  20. package/dist/shared/constants/index.d.ts +2 -0
  21. package/dist/shared/index.d.ts +2 -0
  22. package/dist/vanity/index.d.ts +5 -0
  23. package/dist/vanity/index.js +5 -0
  24. package/package.json +93 -2
  25. package/dist/chains/bsc/four/disperse.d.ts +0 -12
  26. package/dist/chains/bsc/four/disperse.js +0 -470
  27. package/dist/chains/bsc/four/pairwise.d.ts +0 -7
  28. package/dist/chains/bsc/four/pairwise.js +0 -308
  29. package/dist/chains/bsc/four/submit/blockrazor.d.ts +0 -18
  30. package/dist/chains/bsc/four/submit/blockrazor.js +0 -86
  31. package/dist/chains/bsc/four/submit/direct.d.ts +0 -66
  32. package/dist/chains/bsc/four/submit/direct.js +0 -452
  33. package/dist/chains/bsc/four/submit/helpers.d.ts +0 -18
  34. package/dist/chains/bsc/four/submit/helpers.js +0 -57
  35. package/dist/chains/bsc/four/submit/index.d.ts +0 -12
  36. package/dist/chains/bsc/four/submit/index.js +0 -11
  37. package/dist/chains/bsc/four/submit/merkle.d.ts +0 -18
  38. package/dist/chains/bsc/four/submit/merkle.js +0 -74
  39. package/dist/chains/bsc/four/submit/types.d.ts +0 -143
  40. package/dist/chains/bsc/four/swap/index.d.ts +0 -32
  41. package/dist/chains/bsc/four/swap/index.js +0 -829
  42. package/dist/chains/bsc/four/swap/types.d.ts +0 -70
  43. package/dist/chains/bsc/four/swap/types.js +0 -1
  44. package/dist/chains/bsc/four/sweep.d.ts +0 -13
  45. package/dist/chains/bsc/four/sweep.js +0 -788
  46. package/dist/chains/bsc/four/utils/index.d.ts +0 -20
  47. package/dist/chains/bsc/four/utils/index.js +0 -1558
  48. package/dist/chains/bsc/four/utils/types.d.ts +0 -1
  49. package/dist/chains/bsc/four/utils/types.js +0 -1
  50. package/dist/chains/bsc/pancake/bundle-buy-first/index.d.ts +0 -8
  51. package/dist/chains/bsc/pancake/bundle-buy-first/index.js +0 -907
  52. package/dist/chains/bsc/pancake/bundle-buy-first/types.d.ts +0 -73
  53. package/dist/chains/bsc/pancake/bundle-buy-first/types.js +0 -1
  54. package/dist/chains/bsc/pancake/bundle-swap/helpers.d.ts +0 -102
  55. package/dist/chains/bsc/pancake/bundle-swap/helpers.js +0 -572
  56. package/dist/chains/bsc/pancake/bundle-swap/index.d.ts +0 -50
  57. package/dist/chains/bsc/pancake/bundle-swap/index.js +0 -1066
  58. package/dist/chains/bsc/pancake/bundle-swap/types.d.ts +0 -202
  59. package/dist/chains/bsc/pancake/bundle-swap/types.js +0 -3
  60. package/dist/chains/xlayer/eip7702/bundle-swap/index.d.ts +0 -72
  61. package/dist/chains/xlayer/eip7702/bundle-swap/index.js +0 -921
  62. package/dist/chains/xlayer/eip7702/bundle-swap/types.d.ts +0 -65
  63. package/dist/chains/xlayer/eip7702/bundle-swap/types.js +0 -1
  64. package/dist/chains/xlayer/eip7702/multi-hop-transfer/index.d.ts +0 -128
  65. package/dist/chains/xlayer/eip7702/multi-hop-transfer/index.js +0 -857
  66. package/dist/chains/xlayer/eip7702/multi-hop-transfer/types.d.ts +0 -85
  67. package/dist/chains/xlayer/eip7702/multi-hop-transfer/types.js +0 -1
  68. package/dist/chains/xlayer/eip7702/volume/index.d.ts +0 -96
  69. package/dist/chains/xlayer/eip7702/volume/index.js +0 -793
  70. package/dist/chains/xlayer/eip7702/volume/types.d.ts +0 -124
  71. package/dist/chains/xlayer/eip7702/volume/types.js +0 -1
  72. package/dist/chains/xlayer/eoa/types-core.d.ts +0 -363
  73. package/dist/chains/xlayer/eoa/types-core.js +0 -53
  74. package/dist/chains/xlayer/eoa/types-create.d.ts +0 -413
  75. package/dist/chains/xlayer/eoa/types-create.js +0 -9
  76. package/dist/chains/xlayer/eoa/types-volume.d.ts +0 -209
  77. package/dist/chains/xlayer/eoa/types-volume.js +0 -13
  78. package/dist/dex/direct-router/index.d.ts +0 -70
  79. package/dist/dex/direct-router/index.js +0 -1410
  80. package/dist/dex/direct-router/types.d.ts +0 -81
  81. package/dist/dex/direct-router/types.js +0 -1
  82. package/dist/shared/abis/TaxToken.json +0 -969
  83. package/dist/shared/abis/TokenManager.json +0 -836
  84. package/dist/shared/abis/TokenManager2.json +0 -136
  85. package/dist/shared/abis/TokenManagerHelper3.json +0 -993
  86. package/dist/shared/abis 2/TaxToken.json +0 -105
  87. package/dist/shared/abis 2/TokenManager.json +0 -836
  88. package/dist/shared/abis 2/TokenManager2.json +0 -60
  89. package/dist/shared/abis 2/TokenManagerHelper3.json +0 -993
  90. package/dist/shared/abis 2/common.d.ts +0 -85
  91. package/dist/shared/abis 2/common.js +0 -254
  92. package/dist/shared/abis 2/index.d.ts +0 -8
  93. package/dist/shared/abis 2/index.js +0 -8
  94. package/dist/shared/clients 2/blockrazor.d.ts +0 -314
  95. package/dist/shared/clients 2/blockrazor.js +0 -596
  96. package/dist/shared/clients 2/club48.d.ts +0 -154
  97. package/dist/shared/clients 2/club48.js +0 -331
  98. package/dist/shared/clients 2/emitservice.d.ts +0 -47
  99. package/dist/shared/clients 2/emitservice.js +0 -44
  100. package/dist/shared/clients 2/four.d.ts +0 -132
  101. package/dist/shared/clients 2/four.js +0 -281
  102. package/dist/shared/clients 2/merkle.d.ts +0 -210
  103. package/dist/shared/clients 2/merkle.js +0 -400
  104. package/dist/shared/flap/__tests__/curve.test.d.ts +0 -1
  105. package/dist/shared/flap/__tests__/curve.test.js +0 -85
  106. package/dist/shared/flap/portal/index.d.ts +0 -12
  107. package/dist/shared/flap/portal/index.js +0 -11
  108. package/dist/shared/flap/portal/portal.d.ts +0 -47
  109. package/dist/shared/flap/portal/portal.js +0 -218
  110. package/dist/shared/flap/portal/types.d.ts +0 -227
  111. package/dist/shared/flap/portal/types.js +0 -80
  112. package/dist/shared/flap/portal/writer.d.ts +0 -121
  113. package/dist/shared/flap/portal/writer.js +0 -265
  114. package/dist/shared/flap/portal-bundle-merkle/core/index.d.ts +0 -18
  115. package/dist/shared/flap/portal-bundle-merkle/core/index.js +0 -938
  116. package/dist/shared/flap/portal-bundle-merkle/core/types.d.ts +0 -1
  117. package/dist/shared/flap/portal-bundle-merkle/core/types.js +0 -1
  118. package/dist/shared/flap/portal-bundle-merkle/swap/index.d.ts +0 -42
  119. package/dist/shared/flap/portal-bundle-merkle/swap/index.js +0 -1448
  120. package/dist/shared/flap/portal-bundle-merkle/swap/types.d.ts +0 -84
  121. package/dist/shared/flap/portal-bundle-merkle/swap/types.js +0 -1
  122. package/dist/shared/flap/portal-bundle-merkle/utils/index.d.ts +0 -17
  123. package/dist/shared/flap/portal-bundle-merkle/utils/index.js +0 -1024
  124. package/dist/shared/flap/portal-bundle-merkle/utils/types.d.ts +0 -16
  125. package/dist/shared/flap/portal-bundle-merkle/utils/types.js +0 -1
  126. package/dist/shared/flap/portal-bundle-merkle/utils-helpers.d.ts +0 -100
  127. package/dist/shared/flap/portal-bundle-merkle/utils-helpers.js +0 -133
  128. package/dist/shared/flap 2/__tests__/curve.test.d.ts +0 -1
  129. package/dist/shared/flap 2/__tests__/curve.test.js +0 -85
  130. package/dist/shared/flap 2/abi.d.ts +0 -4
  131. package/dist/shared/flap 2/abi.js +0 -4
  132. package/dist/shared/flap 2/constants.d.ts +0 -128
  133. package/dist/shared/flap 2/constants.js +0 -143
  134. package/dist/shared/flap 2/curve.d.ts +0 -33
  135. package/dist/shared/flap 2/curve.js +0 -84
  136. package/dist/shared/flap 2/errors.d.ts +0 -37
  137. package/dist/shared/flap 2/errors.js +0 -114
  138. package/dist/shared/flap 2/index.d.ts +0 -22
  139. package/dist/shared/flap 2/index.js +0 -33
  140. package/dist/shared/flap 2/ipfs.d.ts +0 -21
  141. package/dist/shared/flap 2/ipfs.js +0 -38
  142. package/dist/shared/flap 2/meta.d.ts +0 -30
  143. package/dist/shared/flap 2/meta.js +0 -195
  144. package/dist/shared/flap 2/permit.d.ts +0 -16
  145. package/dist/shared/flap 2/permit.js +0 -67
  146. package/dist/shared/flap 2/pinata.d.ts +0 -40
  147. package/dist/shared/flap 2/pinata.js +0 -106
  148. package/dist/shared/flap 2/portal-bundle-merkle/config.d.ts +0 -79
  149. package/dist/shared/flap 2/portal-bundle-merkle/config.js +0 -133
  150. package/dist/shared/flap 2/portal-bundle-merkle/core.d.ts +0 -18
  151. package/dist/shared/flap 2/portal-bundle-merkle/core.js +0 -938
  152. package/dist/shared/flap 2/portal-bundle-merkle/create-to-dex.d.ts +0 -125
  153. package/dist/shared/flap 2/portal-bundle-merkle/create-to-dex.js +0 -665
  154. package/dist/shared/flap 2/portal-bundle-merkle/curve-to-dex.d.ts +0 -88
  155. package/dist/shared/flap 2/portal-bundle-merkle/curve-to-dex.js +0 -446
  156. package/dist/shared/flap 2/portal-bundle-merkle/index.d.ts +0 -14
  157. package/dist/shared/flap 2/portal-bundle-merkle/index.js +0 -26
  158. package/dist/shared/flap 2/portal-bundle-merkle/pancake-proxy.d.ts +0 -28
  159. package/dist/shared/flap 2/portal-bundle-merkle/pancake-proxy.js +0 -701
  160. package/dist/shared/flap 2/portal-bundle-merkle/private.d.ts +0 -17
  161. package/dist/shared/flap 2/portal-bundle-merkle/private.js +0 -549
  162. package/dist/shared/flap 2/portal-bundle-merkle/swap-buy-first.d.ts +0 -65
  163. package/dist/shared/flap 2/portal-bundle-merkle/swap-buy-first.js +0 -831
  164. package/dist/shared/flap 2/portal-bundle-merkle/swap.d.ts +0 -201
  165. package/dist/shared/flap 2/portal-bundle-merkle/swap.js +0 -1359
  166. package/dist/shared/flap 2/portal-bundle-merkle/types.d.ts +0 -358
  167. package/dist/shared/flap 2/portal-bundle-merkle/types.js +0 -1
  168. package/dist/shared/flap 2/portal-bundle-merkle/utils.d.ts +0 -89
  169. package/dist/shared/flap 2/portal-bundle-merkle/utils.js +0 -963
  170. package/dist/shared/flap 2/portal-bundle.d.ts +0 -119
  171. package/dist/shared/flap 2/portal-bundle.js +0 -584
  172. package/dist/shared/flap 2/portal.d.ts +0 -392
  173. package/dist/shared/flap 2/portal.js +0 -559
  174. package/dist/shared/flap 2/vanity.d.ts +0 -48
  175. package/dist/shared/flap 2/vanity.js +0 -110
  176. package/dist/shared/flap 2/vault.d.ts +0 -240
  177. package/dist/shared/flap 2/vault.js +0 -366
  178. package/dist/shared/four 2/index.d.ts +0 -7
  179. package/dist/shared/four 2/index.js +0 -22
  180. package/dist/shared/four 2/tax-token.d.ts +0 -176
  181. package/dist/shared/four 2/tax-token.js +0 -302
  182. package/dist/shared/index 2.js +0 -10
  183. package/dist/shared/index.d 2.ts +0 -10
  184. package/dist/types/distribute.d.ts +0 -72
  185. package/dist/types/distribute.js +0 -1
  186. package/dist/types 2/errors.d.ts +0 -27
  187. package/dist/types 2/errors.js +0 -34
  188. package/dist/utils/__tests__/errors.test.d.ts +0 -1
  189. package/dist/utils/__tests__/errors.test.js +0 -76
  190. package/dist/utils/airdrop-sweep-types.d.ts +0 -1
  191. package/dist/utils/airdrop-sweep-types.js +0 -1
  192. package/dist/utils/erc20/index.d.ts +0 -242
  193. package/dist/utils/erc20/index.js +0 -645
  194. package/dist/utils/erc20/types.d.ts +0 -77
  195. package/dist/utils/erc20/types.js +0 -1
  196. package/dist/utils/erc20-types.d.ts +0 -1
  197. package/dist/utils/erc20-types.js +0 -1
  198. package/dist/utils/holders-maker/helpers.d.ts +0 -43
  199. package/dist/utils/holders-maker/helpers.js +0 -371
  200. package/dist/utils/holders-maker/index.d.ts +0 -26
  201. package/dist/utils/holders-maker/index.js +0 -218
  202. package/dist/utils/holders-maker/types.d.ts +0 -72
  203. package/dist/utils/holders-maker/types.js +0 -4
  204. package/dist/utils/holders-maker-types.d.ts +0 -1
  205. package/dist/utils/holders-maker-types.js +0 -1
  206. package/dist/utils/lp-inspect/index.d.ts +0 -44
  207. package/dist/utils/lp-inspect/index.js +0 -937
  208. package/dist/utils/lp-inspect/types.d.ts +0 -100
  209. package/dist/utils/lp-inspect/types.js +0 -1
  210. package/dist/utils/lp-inspect-types.d.ts +0 -1
  211. package/dist/utils/lp-inspect-types.js +0 -1
  212. package/dist/utils/private-sale-types.d.ts +0 -1
  213. package/dist/utils/private-sale-types.js +0 -1
  214. package/dist/utils/quote-helpers/index.d.ts +0 -107
  215. package/dist/utils/quote-helpers/index.js +0 -346
  216. package/dist/utils/quote-helpers/types.d.ts +0 -16
  217. package/dist/utils/quote-helpers/types.js +0 -1
  218. package/dist/utils/quote-helpers-types.d.ts +0 -1
  219. package/dist/utils/quote-helpers-types.js +0 -1
  220. /package/dist/{chains/bsc/four/submit/types.js → __tests__/subpath-exports.test.d.ts} +0 -0
@@ -1,857 +0,0 @@
1
- /**
2
- * EIP-7702 转账功能
3
- *
4
- * 支持三种模式:
5
- * 1. 分散 (disperse): 一对多分发资金
6
- * 2. 归集 (sweep): 多对一收集资金
7
- * 3. 多对多 (pairwise): sender[i] → receiver[i] 一一对应转账
8
- *
9
- * 所有模式都支持:
10
- * - 原生 OKB 转账
11
- * - ERC20 代币转账
12
- * - 可选的多跳混淆
13
- *
14
- * 只生成签名,由调用方决定如何提交
15
- */
16
- import { ethers, Contract } from 'ethers';
17
- import { getCachedProvider, createWallet, signAuthorizationsWithNonces, batchGetNonces, buildEIP7702TransactionSync, generateRandomWallets, getProfitRecipient, } from '../utils.js';
18
- import { UNIFIED_DELEGATE_ADDRESS, UNIFIED_DELEGATE_ABI, ERC20_ABI, XLAYER_CHAIN_ID, } from '../constants.js';
19
- import { calculateTransferFee } from '../../../../shared/constants/index.js';
20
- // ========================================
21
- // 通用类型定义
22
- // ========================================
23
- // ========================================
24
- // 分散 (Disperse) - 一对多
25
- // ========================================
26
- /**
27
- * 分散资金 - 一对多分发
28
- *
29
- * 支持:原生 OKB / ERC20 代币 + 可选多跳
30
- *
31
- * 流程(无多跳):主钱包 → 多个接收者
32
- * 流程(有多跳):主钱包 → hop1 → hop2 → ... → 分发给接收者
33
- *
34
- * @example
35
- * // 原生 OKB 直接分发
36
- * const result = await disperse({
37
- * mainPrivateKey: '0x...',
38
- * recipients: ['0xAAA', '0xBBB', '0xCCC'],
39
- * amounts: ['0.1', '0.2', '0.3'],
40
- * });
41
- *
42
- * @example
43
- * // 原生 OKB 多跳分发
44
- * const result = await disperse({
45
- * mainPrivateKey: '0x...',
46
- * recipients: ['0xAAA', '0xBBB'],
47
- * amounts: ['0.5', '0.5'],
48
- * hopCount: 2,
49
- * });
50
- *
51
- * @example
52
- * // ERC20 代币分发
53
- * const result = await disperse({
54
- * mainPrivateKey: '0x...',
55
- * recipients: ['0xAAA', '0xBBB'],
56
- * amounts: ['100', '200'],
57
- * tokenAddress: '0xTOKEN...',
58
- * tokenDecimals: 18,
59
- * hopCount: 2,
60
- * });
61
- */
62
- export async function disperse(params) {
63
- const { mainPrivateKey, payerPrivateKey, recipients, amounts, tokenAddress, tokenDecimals = 18, hopCount = 0, userType, config, } = params;
64
- if (recipients.length !== amounts.length) {
65
- throw new Error('recipients 和 amounts 长度必须相同');
66
- }
67
- const provider = getCachedProvider(config?.rpcUrl);
68
- const delegateAddress = (config?.delegateAddress && config.delegateAddress.trim()) || UNIFIED_DELEGATE_ADDRESS;
69
- const delegateInterface = new ethers.Interface(UNIFIED_DELEGATE_ABI);
70
- // ✅ mainWallet: 资金来源(Token/OKB 从这里转出)
71
- const mainWallet = createWallet(mainPrivateKey, provider);
72
- const isNative = !tokenAddress;
73
- const profitRecipient = getProfitRecipient(config);
74
- // ✅ 支持单独的 Payer 钱包(用于支付 gas)
75
- const hasSeparatePayer = payerPrivateKey && payerPrivateKey !== mainPrivateKey;
76
- const payerWallet = hasSeparatePayer ? createWallet(payerPrivateKey, provider) : null;
77
- const txSender = payerWallet ?? mainWallet; // 交易发起者
78
- console.log(`[disperse] 资金钱包: ${mainWallet.address}`);
79
- console.log(`[disperse] Gas Payer: ${txSender.address}${hasSeparatePayer ? ' (独立 Payer)' : ''}`);
80
- // ✅ 为每个接收者生成独立的中间钱包链
81
- // 每个接收者有自己的 hopCount 个中间钱包
82
- const allHopWalletInfos = [];
83
- const allHopWallets = [];
84
- for (let i = 0; i < recipients.length; i++) {
85
- if (hopCount > 0) {
86
- const hopInfos = generateRandomWallets(hopCount);
87
- allHopWalletInfos.push(hopInfos);
88
- allHopWallets.push(hopInfos.map(info => createWallet(info.privateKey, provider)));
89
- }
90
- else {
91
- allHopWalletInfos.push([]);
92
- allHopWallets.push([]);
93
- }
94
- }
95
- // 解析金额
96
- const amountsWei = amounts.map(amt => isNative ? ethers.parseEther(amt) : ethers.parseUnits(amt, tokenDecimals));
97
- const totalAmount = amountsWei.reduce((sum, amt) => sum + amt, 0n);
98
- // ✅ 按地址数量收取固定费用(原生 OKB)
99
- const profitAmountOkb = calculateTransferFee(XLAYER_CHAIN_ID, recipients.length);
100
- console.log(`[disperse] 按地址收费: ${recipients.length} 个地址 × ${ethers.formatEther(calculateTransferFee(XLAYER_CHAIN_ID, 1))} = ${ethers.formatEther(profitAmountOkb)} OKB`);
101
- // ========================================
102
- // 并行获取数据
103
- // ========================================
104
- const addressesToGetNonces = payerWallet
105
- ? [payerWallet.address, mainWallet.address]
106
- : [mainWallet.address];
107
- const [allNoncesResult, feeData] = await Promise.all([
108
- batchGetNonces(addressesToGetNonces, provider),
109
- provider.getFeeData(),
110
- ]);
111
- const payerNonce = payerWallet ? allNoncesResult[0] : allNoncesResult[0];
112
- const mainNonce = payerWallet ? allNoncesResult[1] : allNoncesResult[0];
113
- // ========================================
114
- // 同步签署授权(已有 nonce)
115
- // ========================================
116
- // ✅ 如果有 Payer,需要为 Payer 和 mainWallet 都生成授权
117
- const allWallets = payerWallet ? [payerWallet, mainWallet] : [mainWallet];
118
- const allNonces = payerWallet ? [payerNonce, mainNonce] : [mainNonce];
119
- for (const hopWallets of allHopWallets) {
120
- for (const hopWallet of hopWallets) {
121
- allWallets.push(hopWallet);
122
- allNonces.push(0);
123
- }
124
- }
125
- const authorizations = signAuthorizationsWithNonces(allWallets, allNonces, delegateAddress, 0 // txSender(Payer 或 mainWallet)是交易发起者
126
- );
127
- // ========================================
128
- // 同步构建调用
129
- // ========================================
130
- const calls = [];
131
- for (let i = 0; i < recipients.length; i++) {
132
- const recipient = recipients[i];
133
- const amtWei = amountsWei[i];
134
- const hopWallets = allHopWallets[i];
135
- if (hopCount === 0 || hopWallets.length === 0) {
136
- // ========================================
137
- // 直接分发:主钱包 → 接收者
138
- // ========================================
139
- if (isNative) {
140
- // ✅ Payer 模式:使用 transferAmount(从 mainWallet 余额转出)
141
- // ✅ 非 Payer 模式:使用 transferTo(从 msg.value 转出)
142
- if (payerWallet) {
143
- calls.push({
144
- target: mainWallet.address,
145
- allowFailure: false,
146
- value: 0n,
147
- callData: delegateInterface.encodeFunctionData('transferAmount', [recipient, amtWei]),
148
- });
149
- }
150
- else {
151
- calls.push({
152
- target: mainWallet.address,
153
- allowFailure: false,
154
- value: amtWei,
155
- callData: delegateInterface.encodeFunctionData('transferTo', [recipient]),
156
- });
157
- }
158
- }
159
- else {
160
- calls.push({
161
- target: mainWallet.address,
162
- allowFailure: false,
163
- value: 0n,
164
- callData: delegateInterface.encodeFunctionData('executeTransfer', [
165
- tokenAddress,
166
- recipient,
167
- amtWei,
168
- ]),
169
- });
170
- }
171
- }
172
- else {
173
- // ========================================
174
- // 多跳分发:主钱包 → hop1 → hop2 → ... → 接收者
175
- // ========================================
176
- const firstHop = hopWallets[0];
177
- const lastHop = hopWallets[hopWallets.length - 1];
178
- if (isNative) {
179
- // 主钱包 → 第一个中间钱包
180
- // ✅ Payer 模式:使用 transferAmount(从 mainWallet 余额转出)
181
- if (payerWallet) {
182
- calls.push({
183
- target: mainWallet.address,
184
- allowFailure: false,
185
- value: 0n,
186
- callData: delegateInterface.encodeFunctionData('transferAmount', [firstHop.address, amtWei]),
187
- });
188
- }
189
- else {
190
- calls.push({
191
- target: mainWallet.address,
192
- allowFailure: false,
193
- value: amtWei,
194
- callData: delegateInterface.encodeFunctionData('transferTo', [firstHop.address]),
195
- });
196
- }
197
- // 中间钱包之间转账(使用全部余额)
198
- for (let j = 0; j < hopWallets.length - 1; j++) {
199
- calls.push({
200
- target: hopWallets[j].address,
201
- allowFailure: false,
202
- value: 0n,
203
- callData: delegateInterface.encodeFunctionData('transferTo', [hopWallets[j + 1].address]),
204
- });
205
- }
206
- // 最后一个中间钱包 → 接收者(使用全部余额)
207
- calls.push({
208
- target: lastHop.address,
209
- allowFailure: false,
210
- value: 0n,
211
- callData: delegateInterface.encodeFunctionData('transferTo', [recipient]),
212
- });
213
- }
214
- else {
215
- // ERC20 多跳
216
- // 主钱包 → 第一个中间钱包
217
- calls.push({
218
- target: mainWallet.address,
219
- allowFailure: false,
220
- value: 0n,
221
- callData: delegateInterface.encodeFunctionData('executeTransfer', [
222
- tokenAddress,
223
- firstHop.address,
224
- amtWei,
225
- ]),
226
- });
227
- // 中间钱包之间转账
228
- for (let j = 0; j < hopWallets.length - 1; j++) {
229
- calls.push({
230
- target: hopWallets[j].address,
231
- allowFailure: false,
232
- value: 0n,
233
- callData: delegateInterface.encodeFunctionData('executeTransferAll', [
234
- tokenAddress,
235
- hopWallets[j + 1].address,
236
- ]),
237
- });
238
- }
239
- // 最后一个中间钱包 → 接收者
240
- calls.push({
241
- target: lastHop.address,
242
- allowFailure: false,
243
- value: 0n,
244
- callData: delegateInterface.encodeFunctionData('executeTransferAll', [
245
- tokenAddress,
246
- recipient,
247
- ]),
248
- });
249
- }
250
- }
251
- }
252
- // ========================================
253
- // 添加利润转账调用(固定费用,OKB)
254
- // ========================================
255
- if (profitAmountOkb > 0n) {
256
- calls.push({
257
- target: mainWallet.address,
258
- allowFailure: false,
259
- value: 0n,
260
- callData: delegateInterface.encodeFunctionData('transferAmount', [profitRecipient, profitAmountOkb]),
261
- });
262
- console.log(`[disperse] 已添加利润转账调用: ${ethers.formatEther(profitAmountOkb)} OKB → ${profitRecipient}`);
263
- }
264
- // ========================================
265
- // 构建交易
266
- // ========================================
267
- // ✅ Payer 模式下 value 为 0(资金从 mainWallet 转出,不是 Payer)
268
- // 无 Payer 时,原生币分发需要传递 value(资金从 txSender 转出)
269
- const totalValue = (isNative && !payerWallet) ? totalAmount : 0n;
270
- const signedTransaction = buildEIP7702TransactionSync(txSender, // ✅ 使用 txSender(Payer 或 mainWallet)发起交易
271
- authorizations, calls, totalValue, payerNonce, // ✅ 使用 txSender 的 nonce
272
- feeData, config);
273
- // ✅ 返回所有中间钱包(扁平化)
274
- const flatHopWallets = allHopWalletInfos.flat();
275
- return {
276
- signedTransaction,
277
- hopWallets: flatHopWallets.length > 0 ? flatHopWallets : undefined,
278
- metadata: {
279
- senderAddress: mainWallet.address, // 资金来源
280
- payerAddress: txSender.address, // Gas 支付者
281
- recipientCount: recipients.length,
282
- totalAmount: isNative ? ethers.formatEther(totalAmount) : ethers.formatUnits(totalAmount, tokenDecimals),
283
- profitAmount: ethers.formatEther(profitAmountOkb), // ✅ 以 OKB 计
284
- isNative,
285
- tokenAddress: tokenAddress ?? null,
286
- hopCount,
287
- userType,
288
- },
289
- };
290
- }
291
- // ========================================
292
- // 归集 (Sweep) - 多对一
293
- // ========================================
294
- /**
295
- * 归集资金 - 多对一收集
296
- *
297
- * 支持:原生 OKB / ERC20 代币 + 可选多跳
298
- *
299
- * 流程(无多跳):多个源钱包 → 目标地址
300
- * 流程(有多跳):多个源钱包 → hop1 → hop2 → ... → 目标地址
301
- *
302
- * @example
303
- * // 原生 OKB 直接归集
304
- * const result = await sweep({
305
- * targetAddress: '0xTARGET',
306
- * sourcePrivateKeys: ['0x...', '0x...'],
307
- * });
308
- *
309
- * @example
310
- * // 原生 OKB 多跳归集
311
- * const result = await sweep({
312
- * targetAddress: '0xTARGET',
313
- * sourcePrivateKeys: ['0x...', '0x...'],
314
- * hopCount: 2,
315
- * });
316
- *
317
- * @example
318
- * // ERC20 代币归集
319
- * const result = await sweep({
320
- * targetAddress: '0xTARGET',
321
- * sourcePrivateKeys: ['0x...', '0x...'],
322
- * tokenAddress: '0xTOKEN...',
323
- * tokenDecimals: 18,
324
- * hopCount: 2,
325
- * });
326
- */
327
- export async function sweep(params) {
328
- const { targetAddress, sourcePrivateKeys, payerPrivateKey, tokenAddress, tokenDecimals = 18, hopCount = 0, reserveGas = true, percent = 100, userType, config, } = params;
329
- const provider = getCachedProvider(config?.rpcUrl);
330
- const delegateAddress = (config?.delegateAddress && config.delegateAddress.trim()) || UNIFIED_DELEGATE_ADDRESS;
331
- const delegateInterface = new ethers.Interface(UNIFIED_DELEGATE_ABI);
332
- const sourceWallets = sourcePrivateKeys.map(pk => createWallet(pk, provider));
333
- const isNative = !tokenAddress;
334
- const profitRecipient = getProfitRecipient(config);
335
- // ✅ 为每个源钱包生成独立的中间钱包链
336
- const allHopWalletInfos = [];
337
- const allHopWallets = [];
338
- for (let i = 0; i < sourceWallets.length; i++) {
339
- if (hopCount > 0) {
340
- const hopInfos = generateRandomWallets(hopCount);
341
- allHopWalletInfos.push(hopInfos);
342
- allHopWallets.push(hopInfos.map(info => createWallet(info.privateKey, provider)));
343
- }
344
- else {
345
- allHopWalletInfos.push([]);
346
- allHopWallets.push([]);
347
- }
348
- }
349
- // ✅ 支持单独的 Payer 钱包(用于支付 gas)
350
- const hasSeparatePayer = payerPrivateKey && !sourcePrivateKeys.includes(payerPrivateKey);
351
- const payerWallet = hasSeparatePayer ? createWallet(payerPrivateKey, provider) : null;
352
- const mainWallet = payerWallet ?? sourceWallets[0];
353
- // ========================================
354
- // 并行获取数据
355
- // ========================================
356
- const sourceAddresses = sourceWallets.map(w => w.address);
357
- const addressesToGetNonces = payerWallet
358
- ? [payerWallet.address, ...sourceAddresses]
359
- : sourceAddresses;
360
- const parallelPromises = [
361
- batchGetNonces(addressesToGetNonces, provider),
362
- provider.getFeeData(),
363
- ];
364
- if (isNative) {
365
- parallelPromises.push(Promise.all(sourceWallets.map(w => provider.getBalance(w.address))));
366
- }
367
- else {
368
- const tokenContract = new Contract(tokenAddress, ERC20_ABI, provider);
369
- parallelPromises.push(Promise.all(sourceWallets.map(w => tokenContract.balanceOf(w.address))));
370
- }
371
- const results = await Promise.all(parallelPromises);
372
- const allNoncesResult = results[0];
373
- const payerNonce = payerWallet ? allNoncesResult[0] : allNoncesResult[0];
374
- const nonces = payerWallet ? allNoncesResult.slice(1) : allNoncesResult;
375
- const feeData = results[1];
376
- const balances = results[2].map(b => typeof b === 'bigint' ? b : BigInt(b.toString()));
377
- // 计算转账金额
378
- // ✅ 修复:当 percent=100 时,不预留 gas,归集全部余额
379
- const isFullSweep = percent >= 100;
380
- const gasReserve = (reserveGas && isNative && !isFullSweep) ? ethers.parseEther('0.001') : 0n;
381
- const percentBigInt = BigInt(Math.min(100, Math.max(1, percent)));
382
- const transferAmounts = balances.map(b => {
383
- if (isFullSweep) {
384
- // 100% 归集:使用全部余额
385
- return b;
386
- }
387
- const afterReserve = b > gasReserve ? b - gasReserve : 0n;
388
- return (afterReserve * percentBigInt) / 100n;
389
- });
390
- const totalAmount = transferAmounts.reduce((sum, amt) => sum + amt, 0n);
391
- // ✅ 按地址数量收取固定费用(原生 OKB)
392
- const profitAmountOkb = calculateTransferFee(XLAYER_CHAIN_ID, sourceWallets.length);
393
- console.log(`[sweep] 按地址收费: ${sourceWallets.length} 个地址 × ${ethers.formatEther(calculateTransferFee(XLAYER_CHAIN_ID, 1))} = ${ethers.formatEther(profitAmountOkb)} OKB`);
394
- // ✅ 找出归集金额最大的钱包(用于支付 OKB 利润)
395
- let maxSweepIndex = -1;
396
- let maxSweepAmount = 0n;
397
- for (let i = 0; i < transferAmounts.length; i++) {
398
- if (transferAmounts[i] > maxSweepAmount) {
399
- maxSweepAmount = transferAmounts[i];
400
- maxSweepIndex = i;
401
- }
402
- }
403
- // ========================================
404
- // 构建调用
405
- // ========================================
406
- const calls = [];
407
- for (let i = 0; i < sourceWallets.length; i++) {
408
- const sourceWallet = sourceWallets[i];
409
- const amount = transferAmounts[i];
410
- const hopWallets = allHopWallets[i];
411
- if (amount <= 0n)
412
- continue;
413
- // ✅ 使用 Payer 时所有源钱包都用自己的余额(value: 0n)
414
- const callValue = (payerWallet || i > 0) ? 0n : amount;
415
- if (hopCount === 0 || hopWallets.length === 0) {
416
- // ========================================
417
- // 直接归集:源钱包 → 目标地址
418
- // ========================================
419
- // ✅ 最大归集钱包负责转 OKB 固定费用
420
- if (profitAmountOkb > 0n && i === maxSweepIndex) {
421
- calls.push({
422
- target: sourceWallet.address,
423
- allowFailure: false,
424
- value: 0n,
425
- callData: delegateInterface.encodeFunctionData('transferAmount', [profitRecipient, profitAmountOkb]),
426
- });
427
- console.log(`[sweep] 钱包 ${i} 转利润: ${ethers.formatEther(profitAmountOkb)} OKB → ${profitRecipient}`);
428
- }
429
- if (isNative) {
430
- // ✅ 原生 OKB 归集
431
- calls.push({
432
- target: sourceWallet.address,
433
- allowFailure: false,
434
- value: callValue,
435
- callData: delegateInterface.encodeFunctionData('transferAmount', [targetAddress, amount]),
436
- });
437
- }
438
- else {
439
- // ✅ ERC20 归集
440
- calls.push({
441
- target: sourceWallet.address,
442
- allowFailure: false,
443
- value: 0n,
444
- callData: delegateInterface.encodeFunctionData('executeTransfer', [
445
- tokenAddress,
446
- targetAddress,
447
- amount,
448
- ]),
449
- });
450
- }
451
- }
452
- else {
453
- // ========================================
454
- // 多跳归集:源钱包 → hop1 → hop2 → ... → 目标地址
455
- // ========================================
456
- const firstHop = hopWallets[0];
457
- const lastHop = hopWallets[hopWallets.length - 1];
458
- // ✅ 最大归集钱包负责转 OKB 固定费用(在归集前)
459
- if (profitAmountOkb > 0n && i === maxSweepIndex) {
460
- calls.push({
461
- target: sourceWallet.address,
462
- allowFailure: false,
463
- value: 0n,
464
- callData: delegateInterface.encodeFunctionData('transferAmount', [profitRecipient, profitAmountOkb]),
465
- });
466
- console.log(`[sweep] 钱包 ${i} 转利润(多跳): ${ethers.formatEther(profitAmountOkb)} OKB → ${profitRecipient}`);
467
- }
468
- if (isNative) {
469
- // 源钱包 → 第一个中间钱包
470
- // ✅ 修复:使用 transferAmount 替代 transferTo,支持百分比归集
471
- calls.push({
472
- target: sourceWallet.address,
473
- allowFailure: false,
474
- value: callValue,
475
- callData: delegateInterface.encodeFunctionData('transferAmount', [firstHop.address, amount]),
476
- });
477
- // 中间钱包之间转账
478
- for (let j = 0; j < hopWallets.length - 1; j++) {
479
- calls.push({
480
- target: hopWallets[j].address,
481
- allowFailure: false,
482
- value: 0n,
483
- callData: delegateInterface.encodeFunctionData('transferTo', [hopWallets[j + 1].address]),
484
- });
485
- }
486
- // 最后一个中间钱包 → 目标地址
487
- calls.push({
488
- target: lastHop.address,
489
- allowFailure: false,
490
- value: 0n,
491
- callData: delegateInterface.encodeFunctionData('transferTo', [targetAddress]),
492
- });
493
- }
494
- else {
495
- // ERC20 多跳
496
- // 源钱包 → 第一个中间钱包(ERC20 代币)
497
- calls.push({
498
- target: sourceWallet.address,
499
- allowFailure: false,
500
- value: 0n,
501
- callData: delegateInterface.encodeFunctionData('executeTransfer', [
502
- tokenAddress,
503
- firstHop.address,
504
- amount,
505
- ]),
506
- });
507
- // 中间钱包之间转账
508
- for (let j = 0; j < hopWallets.length - 1; j++) {
509
- calls.push({
510
- target: hopWallets[j].address,
511
- allowFailure: false,
512
- value: 0n,
513
- callData: delegateInterface.encodeFunctionData('executeTransferAll', [
514
- tokenAddress,
515
- hopWallets[j + 1].address,
516
- ]),
517
- });
518
- }
519
- // 最后一个中间钱包 → 目标地址
520
- calls.push({
521
- target: lastHop.address,
522
- allowFailure: false,
523
- value: 0n,
524
- callData: delegateInterface.encodeFunctionData('executeTransferAll', [
525
- tokenAddress,
526
- targetAddress,
527
- ]),
528
- });
529
- }
530
- }
531
- }
532
- // ========================================
533
- // 同步签署授权(已有 nonce)
534
- // ========================================
535
- // ✅ 收集所有需要授权的钱包
536
- const allWallets = payerWallet ? [payerWallet] : [];
537
- const allNonces = payerWallet ? [payerNonce] : [];
538
- // 添加源钱包
539
- for (let i = 0; i < sourceWallets.length; i++) {
540
- allWallets.push(sourceWallets[i]);
541
- allNonces.push(nonces[i]);
542
- }
543
- // 添加所有中间钱包
544
- for (const hopWallets of allHopWallets) {
545
- for (const hopWallet of hopWallets) {
546
- allWallets.push(hopWallet);
547
- allNonces.push(0);
548
- }
549
- }
550
- const authorizations = signAuthorizationsWithNonces(allWallets, allNonces, delegateAddress, 0 // mainWallet 是交易发起者
551
- );
552
- // ========================================
553
- // 同步构建交易
554
- // ========================================
555
- // ✅ Payer 模式下 value 为 0(资金来自源钱包)
556
- const totalValue = (isNative && !payerWallet) ? transferAmounts[0] : 0n;
557
- const signedTransaction = buildEIP7702TransactionSync(mainWallet, authorizations, calls, totalValue, payerWallet ? payerNonce : nonces[0], feeData, config);
558
- // ✅ 返回所有中间钱包(扁平化)
559
- const flatHopWallets = allHopWalletInfos.flat();
560
- return {
561
- signedTransaction,
562
- hopWallets: flatHopWallets.length > 0 ? flatHopWallets : undefined,
563
- metadata: {
564
- targetAddress,
565
- sourceCount: sourceWallets.length,
566
- totalAmount: isNative ? ethers.formatEther(totalAmount) : ethers.formatUnits(totalAmount, tokenDecimals),
567
- profitAmount: ethers.formatEther(profitAmountOkb), // ✅ 以 OKB 计
568
- isNative,
569
- tokenAddress: tokenAddress ?? null,
570
- hopCount,
571
- percent,
572
- userType,
573
- },
574
- };
575
- }
576
- // ========================================
577
- // 多对多 (Pairwise) - sender[i] → receiver[i]
578
- // ========================================
579
- /**
580
- * 多对多转账 - sender[i] → receiver[i] 一一对应
581
- *
582
- * 支持:原生 OKB / ERC20 代币 + 可选多跳
583
- *
584
- * 每对都有独立的多跳链:sender → hop1 → hop2 → ... → receiver
585
- *
586
- * @example
587
- * // 原生 OKB 多对多(直接转账)
588
- * const result = await pairwiseTransfer({
589
- * senderPrivateKeys: ['0xA...', '0xB...', '0xC...'],
590
- * receiverAddresses: ['0x111', '0x222', '0x333'],
591
- * amount: '0.1',
592
- * });
593
- *
594
- * @example
595
- * // 原生 OKB 多对多(带多跳)
596
- * const result = await pairwiseTransfer({
597
- * senderPrivateKeys: ['0xA...', '0xB...'],
598
- * receiverAddresses: ['0x111', '0x222'],
599
- * amounts: ['0.1', '0.2'],
600
- * hopCount: 2, // A → hop1 → hop2 → 111, B → hop3 → hop4 → 222
601
- * });
602
- *
603
- * @example
604
- * // ERC20 多对多(带多跳)
605
- * const result = await pairwiseTransfer({
606
- * senderPrivateKeys: ['0xA...', '0xB...'],
607
- * receiverAddresses: ['0x111', '0x222'],
608
- * amount: '100',
609
- * tokenAddress: '0xTOKEN...',
610
- * tokenDecimals: 18,
611
- * hopCount: 2,
612
- * });
613
- */
614
- export async function pairwiseTransfer(params) {
615
- const { senderPrivateKeys, receiverAddresses, payerPrivateKey, amount, amounts, tokenAddress, tokenDecimals = 18, hopCount = 0, userType, config, } = params;
616
- // 验证参数
617
- if (senderPrivateKeys.length !== receiverAddresses.length) {
618
- throw new Error(`senderPrivateKeys 长度 (${senderPrivateKeys.length}) 必须与 receiverAddresses 长度 (${receiverAddresses.length}) 相同`);
619
- }
620
- const pairCount = senderPrivateKeys.length;
621
- if (pairCount === 0) {
622
- throw new Error('至少需要一对发送者/接收者');
623
- }
624
- // 解析金额
625
- const normalizedAmounts = (() => {
626
- if (amounts && amounts.length > 0) {
627
- if (amounts.length !== pairCount) {
628
- throw new Error(`amounts 长度 (${amounts.length}) 必须与对数 (${pairCount}) 相同`);
629
- }
630
- return amounts;
631
- }
632
- if (amount !== undefined && amount.trim().length > 0) {
633
- return new Array(pairCount).fill(amount);
634
- }
635
- throw new Error('必须提供 amount 或 amounts');
636
- })();
637
- const provider = getCachedProvider(config?.rpcUrl);
638
- const delegateAddress = (config?.delegateAddress && config.delegateAddress.trim()) || UNIFIED_DELEGATE_ADDRESS;
639
- const delegateInterface = new ethers.Interface(UNIFIED_DELEGATE_ABI);
640
- const isNative = !tokenAddress;
641
- const profitRecipient = getProfitRecipient(config);
642
- // 创建钱包
643
- const senderWallets = senderPrivateKeys.map(pk => createWallet(pk, provider));
644
- // ✅ 支持单独的 Payer 钱包(用于支付 gas)
645
- const hasSeparatePayer = payerPrivateKey && !senderPrivateKeys.includes(payerPrivateKey);
646
- const payerWallet = hasSeparatePayer ? createWallet(payerPrivateKey, provider) : null;
647
- const mainWallet = payerWallet ?? senderWallets[0];
648
- // 为每对生成独立的中间钱包链
649
- const allHopWalletInfos = [];
650
- const allHopWallets = [];
651
- for (let i = 0; i < pairCount; i++) {
652
- if (hopCount > 0) {
653
- const hopInfos = generateRandomWallets(hopCount);
654
- allHopWalletInfos.push(hopInfos);
655
- allHopWallets.push(hopInfos.map(info => createWallet(info.privateKey, provider)));
656
- }
657
- else {
658
- allHopWalletInfos.push([]);
659
- allHopWallets.push([]);
660
- }
661
- }
662
- // 解析金额为 Wei
663
- const amountsWei = normalizedAmounts.map(amt => isNative ? ethers.parseEther(amt) : ethers.parseUnits(amt, tokenDecimals));
664
- const totalAmount = amountsWei.reduce((sum, amt) => sum + amt, 0n);
665
- // ✅ 按地址数量收取固定费用(原生 OKB)
666
- const profitAmountOkb = calculateTransferFee(XLAYER_CHAIN_ID, pairCount);
667
- console.log(`[pairwiseTransfer] 按地址收费: ${pairCount} 个地址 × ${ethers.formatEther(calculateTransferFee(XLAYER_CHAIN_ID, 1))} = ${ethers.formatEther(profitAmountOkb)} OKB`);
668
- // ✅ 使用第一个发送者支付 OKB 利润
669
- const maxTransferIndex = 0;
670
- // ========================================
671
- // 并行获取数据
672
- // ========================================
673
- const senderAddresses = senderWallets.map(w => w.address);
674
- const addressesToGetNonces = payerWallet
675
- ? [payerWallet.address, ...senderAddresses]
676
- : senderAddresses;
677
- const [allNoncesResult, feeData] = await Promise.all([
678
- batchGetNonces(addressesToGetNonces, provider),
679
- provider.getFeeData(),
680
- ]);
681
- // 如果有单独的 Payer,第一个是 Payer 的 nonce,其余是发送者的
682
- const payerNonce = payerWallet ? allNoncesResult[0] : allNoncesResult[0];
683
- const nonces = payerWallet ? allNoncesResult.slice(1) : allNoncesResult;
684
- // ========================================
685
- // 构建调用
686
- // ========================================
687
- const calls = [];
688
- for (let i = 0; i < pairCount; i++) {
689
- const senderWallet = senderWallets[i];
690
- const receiver = receiverAddresses[i];
691
- const amtWei = amountsWei[i];
692
- const hopWallets = allHopWallets[i];
693
- // ✅ 如果有单独的 Payer,发送者使用自己的余额(value: 0n, 由 transferTo 使用 address(this).balance)
694
- // ✅ 如果没有 Payer 且是第一个发送者(发起交易),需要传递 value
695
- const shouldPassValue = !payerWallet && i === 0;
696
- if (hopCount === 0 || hopWallets.length === 0) {
697
- // ========================================
698
- // 直接转账:sender → receiver
699
- // ========================================
700
- // ✅ 第一个发送者负责转 OKB 固定费用
701
- if (profitAmountOkb > 0n && i === maxTransferIndex) {
702
- calls.push({
703
- target: senderWallet.address,
704
- allowFailure: false,
705
- value: 0n,
706
- callData: delegateInterface.encodeFunctionData('transferAmount', [profitRecipient, profitAmountOkb]),
707
- });
708
- console.log(`[pairwiseTransfer] 发送者 ${i} 转利润: ${ethers.formatEther(profitAmountOkb)} OKB → ${profitRecipient}`);
709
- }
710
- if (isNative) {
711
- // ✅ 使用 transferAmount 转移指定金额(而不是 transferTo 全额)
712
- calls.push({
713
- target: senderWallet.address,
714
- allowFailure: false,
715
- value: shouldPassValue ? amtWei : 0n,
716
- callData: delegateInterface.encodeFunctionData('transferAmount', [receiver, amtWei]),
717
- });
718
- }
719
- else {
720
- // ERC20 代币转账
721
- calls.push({
722
- target: senderWallet.address,
723
- allowFailure: false,
724
- value: 0n,
725
- callData: delegateInterface.encodeFunctionData('executeTransfer', [
726
- tokenAddress,
727
- receiver,
728
- amtWei,
729
- ]),
730
- });
731
- }
732
- }
733
- else {
734
- // ========================================
735
- // 多跳转账:sender → hop1 → hop2 → ... → receiver
736
- // ========================================
737
- const firstHop = hopWallets[0];
738
- const lastHop = hopWallets[hopWallets.length - 1];
739
- // ✅ 第一个发送者负责转 OKB 固定费用(在转账前)
740
- if (profitAmountOkb > 0n && i === maxTransferIndex) {
741
- calls.push({
742
- target: senderWallet.address,
743
- allowFailure: false,
744
- value: 0n,
745
- callData: delegateInterface.encodeFunctionData('transferAmount', [profitRecipient, profitAmountOkb]),
746
- });
747
- console.log(`[pairwiseTransfer] 发送者 ${i} 转利润(多跳): ${ethers.formatEther(profitAmountOkb)} OKB → ${profitRecipient}`);
748
- }
749
- if (isNative) {
750
- // 原生 OKB 多跳
751
- // ✅ sender → 第一个中间钱包(使用 transferAmount 转移指定金额)
752
- calls.push({
753
- target: senderWallet.address,
754
- allowFailure: false,
755
- value: shouldPassValue ? amtWei : 0n,
756
- callData: delegateInterface.encodeFunctionData('transferAmount', [firstHop.address, amtWei]),
757
- });
758
- // 中间钱包之间转账(使用 transferTo,因为中间钱包只有这笔钱)
759
- for (let j = 0; j < hopWallets.length - 1; j++) {
760
- calls.push({
761
- target: hopWallets[j].address,
762
- allowFailure: false,
763
- value: 0n,
764
- callData: delegateInterface.encodeFunctionData('transferTo', [hopWallets[j + 1].address]),
765
- });
766
- }
767
- // 最后一个中间钱包 → receiver(使用 transferTo 转移全部)
768
- calls.push({
769
- target: lastHop.address,
770
- allowFailure: false,
771
- value: 0n,
772
- callData: delegateInterface.encodeFunctionData('transferTo', [receiver]),
773
- });
774
- }
775
- else {
776
- // ERC20 多跳
777
- // sender → 第一个中间钱包(ERC20 代币)
778
- calls.push({
779
- target: senderWallet.address,
780
- allowFailure: false,
781
- value: 0n,
782
- callData: delegateInterface.encodeFunctionData('executeTransfer', [
783
- tokenAddress,
784
- firstHop.address,
785
- amtWei,
786
- ]),
787
- });
788
- // 中间钱包之间转账
789
- for (let j = 0; j < hopWallets.length - 1; j++) {
790
- calls.push({
791
- target: hopWallets[j].address,
792
- allowFailure: false,
793
- value: 0n,
794
- callData: delegateInterface.encodeFunctionData('executeTransferAll', [
795
- tokenAddress,
796
- hopWallets[j + 1].address,
797
- ]),
798
- });
799
- }
800
- // 最后一个中间钱包 → receiver
801
- calls.push({
802
- target: lastHop.address,
803
- allowFailure: false,
804
- value: 0n,
805
- callData: delegateInterface.encodeFunctionData('executeTransferAll', [
806
- tokenAddress,
807
- receiver,
808
- ]),
809
- });
810
- }
811
- }
812
- }
813
- // ========================================
814
- // 同步签署授权(已有 nonce)
815
- // ========================================
816
- // ✅ 如果有单独的 Payer,需要为 Payer 也生成授权
817
- const allWallets = payerWallet
818
- ? [payerWallet, ...senderWallets]
819
- : [...senderWallets];
820
- const allNonces = payerWallet
821
- ? [payerNonce, ...nonces]
822
- : [...nonces];
823
- for (const hopWallets of allHopWallets) {
824
- for (const hopWallet of hopWallets) {
825
- allWallets.push(hopWallet);
826
- allNonces.push(0);
827
- }
828
- }
829
- const authorizations = signAuthorizationsWithNonces(allWallets, allNonces, delegateAddress, 0 // mainWallet(可能是 Payer 或第一个发送者钱包)是交易发起者
830
- );
831
- // ========================================
832
- // 同步构建交易
833
- // ========================================
834
- // ✅ Payer 模式下 value 为 0(资金来自发送者钱包)
835
- const totalValue = (isNative && !payerWallet) ? totalAmount : 0n;
836
- const signedTransaction = buildEIP7702TransactionSync(mainWallet, authorizations, calls, totalValue, payerWallet ? payerNonce : nonces[0], feeData, config);
837
- return {
838
- signedTransaction,
839
- hopWallets: hopCount > 0 ? allHopWalletInfos : undefined,
840
- metadata: {
841
- pairCount,
842
- totalAmount: isNative ? ethers.formatEther(totalAmount) : ethers.formatUnits(totalAmount, tokenDecimals),
843
- profitAmount: ethers.formatEther(profitAmountOkb), // ✅ 以 OKB 计
844
- isNative,
845
- tokenAddress: tokenAddress ?? null,
846
- hopCount,
847
- userType,
848
- },
849
- };
850
- }
851
- // ========================================
852
- // 保留旧函数名的别名(向后兼容)
853
- // ========================================
854
- /** @deprecated 使用 disperse 替代 */
855
- export const disperseWithHops = disperse;
856
- /** @deprecated 使用 sweep 替代 */
857
- export const sweepWithHops = sweep;