four-flap-meme-sdk 2.0.0 → 2.1.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 (205) hide show
  1. package/dist/__tests__/subpath-exports.test.js +34 -0
  2. package/dist/chains/index.d.ts +13 -0
  3. package/dist/chains/index.js +13 -0
  4. package/dist/chains/xlayer/eip7702/index.d.ts +2 -0
  5. package/dist/flap/index.d.ts +10 -0
  6. package/dist/flap/index.js +8 -0
  7. package/dist/shared/constants/index.d.ts +2 -0
  8. package/dist/shared/index.d.ts +2 -0
  9. package/package.json +66 -1
  10. package/dist/chains/bsc/four/disperse.d.ts +0 -12
  11. package/dist/chains/bsc/four/disperse.js +0 -470
  12. package/dist/chains/bsc/four/pairwise.d.ts +0 -7
  13. package/dist/chains/bsc/four/pairwise.js +0 -308
  14. package/dist/chains/bsc/four/submit/blockrazor.d.ts +0 -18
  15. package/dist/chains/bsc/four/submit/blockrazor.js +0 -86
  16. package/dist/chains/bsc/four/submit/direct.d.ts +0 -66
  17. package/dist/chains/bsc/four/submit/direct.js +0 -452
  18. package/dist/chains/bsc/four/submit/helpers.d.ts +0 -18
  19. package/dist/chains/bsc/four/submit/helpers.js +0 -57
  20. package/dist/chains/bsc/four/submit/index.d.ts +0 -12
  21. package/dist/chains/bsc/four/submit/index.js +0 -11
  22. package/dist/chains/bsc/four/submit/merkle.d.ts +0 -18
  23. package/dist/chains/bsc/four/submit/merkle.js +0 -74
  24. package/dist/chains/bsc/four/submit/types.d.ts +0 -143
  25. package/dist/chains/bsc/four/swap/index.d.ts +0 -32
  26. package/dist/chains/bsc/four/swap/index.js +0 -829
  27. package/dist/chains/bsc/four/swap/types.d.ts +0 -70
  28. package/dist/chains/bsc/four/swap/types.js +0 -1
  29. package/dist/chains/bsc/four/sweep.d.ts +0 -13
  30. package/dist/chains/bsc/four/sweep.js +0 -788
  31. package/dist/chains/bsc/four/utils/index.d.ts +0 -20
  32. package/dist/chains/bsc/four/utils/index.js +0 -1558
  33. package/dist/chains/bsc/four/utils/types.d.ts +0 -1
  34. package/dist/chains/bsc/four/utils/types.js +0 -1
  35. package/dist/chains/bsc/pancake/bundle-buy-first/index.d.ts +0 -8
  36. package/dist/chains/bsc/pancake/bundle-buy-first/index.js +0 -907
  37. package/dist/chains/bsc/pancake/bundle-buy-first/types.d.ts +0 -73
  38. package/dist/chains/bsc/pancake/bundle-buy-first/types.js +0 -1
  39. package/dist/chains/bsc/pancake/bundle-swap/helpers.d.ts +0 -102
  40. package/dist/chains/bsc/pancake/bundle-swap/helpers.js +0 -572
  41. package/dist/chains/bsc/pancake/bundle-swap/index.d.ts +0 -50
  42. package/dist/chains/bsc/pancake/bundle-swap/index.js +0 -1066
  43. package/dist/chains/bsc/pancake/bundle-swap/types.d.ts +0 -202
  44. package/dist/chains/bsc/pancake/bundle-swap/types.js +0 -3
  45. package/dist/chains/xlayer/eip7702/bundle-swap/index.d.ts +0 -72
  46. package/dist/chains/xlayer/eip7702/bundle-swap/index.js +0 -921
  47. package/dist/chains/xlayer/eip7702/bundle-swap/types.d.ts +0 -65
  48. package/dist/chains/xlayer/eip7702/bundle-swap/types.js +0 -1
  49. package/dist/chains/xlayer/eip7702/multi-hop-transfer/index.d.ts +0 -128
  50. package/dist/chains/xlayer/eip7702/multi-hop-transfer/index.js +0 -857
  51. package/dist/chains/xlayer/eip7702/multi-hop-transfer/types.d.ts +0 -85
  52. package/dist/chains/xlayer/eip7702/multi-hop-transfer/types.js +0 -1
  53. package/dist/chains/xlayer/eip7702/volume/index.d.ts +0 -96
  54. package/dist/chains/xlayer/eip7702/volume/index.js +0 -793
  55. package/dist/chains/xlayer/eip7702/volume/types.d.ts +0 -124
  56. package/dist/chains/xlayer/eip7702/volume/types.js +0 -1
  57. package/dist/chains/xlayer/eoa/types-core.d.ts +0 -363
  58. package/dist/chains/xlayer/eoa/types-core.js +0 -53
  59. package/dist/chains/xlayer/eoa/types-create.d.ts +0 -413
  60. package/dist/chains/xlayer/eoa/types-create.js +0 -9
  61. package/dist/chains/xlayer/eoa/types-volume.d.ts +0 -209
  62. package/dist/chains/xlayer/eoa/types-volume.js +0 -13
  63. package/dist/dex/direct-router/index.d.ts +0 -70
  64. package/dist/dex/direct-router/index.js +0 -1410
  65. package/dist/dex/direct-router/types.d.ts +0 -81
  66. package/dist/dex/direct-router/types.js +0 -1
  67. package/dist/shared/abis/TaxToken.json +0 -969
  68. package/dist/shared/abis/TokenManager.json +0 -836
  69. package/dist/shared/abis/TokenManager2.json +0 -136
  70. package/dist/shared/abis/TokenManagerHelper3.json +0 -993
  71. package/dist/shared/abis 2/TaxToken.json +0 -105
  72. package/dist/shared/abis 2/TokenManager.json +0 -836
  73. package/dist/shared/abis 2/TokenManager2.json +0 -60
  74. package/dist/shared/abis 2/TokenManagerHelper3.json +0 -993
  75. package/dist/shared/abis 2/common.d.ts +0 -85
  76. package/dist/shared/abis 2/common.js +0 -254
  77. package/dist/shared/abis 2/index.d.ts +0 -8
  78. package/dist/shared/abis 2/index.js +0 -8
  79. package/dist/shared/clients 2/blockrazor.d.ts +0 -314
  80. package/dist/shared/clients 2/blockrazor.js +0 -596
  81. package/dist/shared/clients 2/club48.d.ts +0 -154
  82. package/dist/shared/clients 2/club48.js +0 -331
  83. package/dist/shared/clients 2/emitservice.d.ts +0 -47
  84. package/dist/shared/clients 2/emitservice.js +0 -44
  85. package/dist/shared/clients 2/four.d.ts +0 -132
  86. package/dist/shared/clients 2/four.js +0 -281
  87. package/dist/shared/clients 2/merkle.d.ts +0 -210
  88. package/dist/shared/clients 2/merkle.js +0 -400
  89. package/dist/shared/flap/__tests__/curve.test.d.ts +0 -1
  90. package/dist/shared/flap/__tests__/curve.test.js +0 -85
  91. package/dist/shared/flap/portal/index.d.ts +0 -12
  92. package/dist/shared/flap/portal/index.js +0 -11
  93. package/dist/shared/flap/portal/portal.d.ts +0 -47
  94. package/dist/shared/flap/portal/portal.js +0 -218
  95. package/dist/shared/flap/portal/types.d.ts +0 -227
  96. package/dist/shared/flap/portal/types.js +0 -80
  97. package/dist/shared/flap/portal/writer.d.ts +0 -121
  98. package/dist/shared/flap/portal/writer.js +0 -265
  99. package/dist/shared/flap/portal-bundle-merkle/core/index.d.ts +0 -18
  100. package/dist/shared/flap/portal-bundle-merkle/core/index.js +0 -938
  101. package/dist/shared/flap/portal-bundle-merkle/core/types.d.ts +0 -1
  102. package/dist/shared/flap/portal-bundle-merkle/core/types.js +0 -1
  103. package/dist/shared/flap/portal-bundle-merkle/swap/index.d.ts +0 -42
  104. package/dist/shared/flap/portal-bundle-merkle/swap/index.js +0 -1448
  105. package/dist/shared/flap/portal-bundle-merkle/swap/types.d.ts +0 -84
  106. package/dist/shared/flap/portal-bundle-merkle/swap/types.js +0 -1
  107. package/dist/shared/flap/portal-bundle-merkle/utils/index.d.ts +0 -17
  108. package/dist/shared/flap/portal-bundle-merkle/utils/index.js +0 -1024
  109. package/dist/shared/flap/portal-bundle-merkle/utils/types.d.ts +0 -16
  110. package/dist/shared/flap/portal-bundle-merkle/utils/types.js +0 -1
  111. package/dist/shared/flap/portal-bundle-merkle/utils-helpers.d.ts +0 -100
  112. package/dist/shared/flap/portal-bundle-merkle/utils-helpers.js +0 -133
  113. package/dist/shared/flap 2/__tests__/curve.test.d.ts +0 -1
  114. package/dist/shared/flap 2/__tests__/curve.test.js +0 -85
  115. package/dist/shared/flap 2/abi.d.ts +0 -4
  116. package/dist/shared/flap 2/abi.js +0 -4
  117. package/dist/shared/flap 2/constants.d.ts +0 -128
  118. package/dist/shared/flap 2/constants.js +0 -143
  119. package/dist/shared/flap 2/curve.d.ts +0 -33
  120. package/dist/shared/flap 2/curve.js +0 -84
  121. package/dist/shared/flap 2/errors.d.ts +0 -37
  122. package/dist/shared/flap 2/errors.js +0 -114
  123. package/dist/shared/flap 2/index.d.ts +0 -22
  124. package/dist/shared/flap 2/index.js +0 -33
  125. package/dist/shared/flap 2/ipfs.d.ts +0 -21
  126. package/dist/shared/flap 2/ipfs.js +0 -38
  127. package/dist/shared/flap 2/meta.d.ts +0 -30
  128. package/dist/shared/flap 2/meta.js +0 -195
  129. package/dist/shared/flap 2/permit.d.ts +0 -16
  130. package/dist/shared/flap 2/permit.js +0 -67
  131. package/dist/shared/flap 2/pinata.d.ts +0 -40
  132. package/dist/shared/flap 2/pinata.js +0 -106
  133. package/dist/shared/flap 2/portal-bundle-merkle/config.d.ts +0 -79
  134. package/dist/shared/flap 2/portal-bundle-merkle/config.js +0 -133
  135. package/dist/shared/flap 2/portal-bundle-merkle/core.d.ts +0 -18
  136. package/dist/shared/flap 2/portal-bundle-merkle/core.js +0 -938
  137. package/dist/shared/flap 2/portal-bundle-merkle/create-to-dex.d.ts +0 -125
  138. package/dist/shared/flap 2/portal-bundle-merkle/create-to-dex.js +0 -665
  139. package/dist/shared/flap 2/portal-bundle-merkle/curve-to-dex.d.ts +0 -88
  140. package/dist/shared/flap 2/portal-bundle-merkle/curve-to-dex.js +0 -446
  141. package/dist/shared/flap 2/portal-bundle-merkle/index.d.ts +0 -14
  142. package/dist/shared/flap 2/portal-bundle-merkle/index.js +0 -26
  143. package/dist/shared/flap 2/portal-bundle-merkle/pancake-proxy.d.ts +0 -28
  144. package/dist/shared/flap 2/portal-bundle-merkle/pancake-proxy.js +0 -701
  145. package/dist/shared/flap 2/portal-bundle-merkle/private.d.ts +0 -17
  146. package/dist/shared/flap 2/portal-bundle-merkle/private.js +0 -549
  147. package/dist/shared/flap 2/portal-bundle-merkle/swap-buy-first.d.ts +0 -65
  148. package/dist/shared/flap 2/portal-bundle-merkle/swap-buy-first.js +0 -831
  149. package/dist/shared/flap 2/portal-bundle-merkle/swap.d.ts +0 -201
  150. package/dist/shared/flap 2/portal-bundle-merkle/swap.js +0 -1359
  151. package/dist/shared/flap 2/portal-bundle-merkle/types.d.ts +0 -358
  152. package/dist/shared/flap 2/portal-bundle-merkle/types.js +0 -1
  153. package/dist/shared/flap 2/portal-bundle-merkle/utils.d.ts +0 -89
  154. package/dist/shared/flap 2/portal-bundle-merkle/utils.js +0 -963
  155. package/dist/shared/flap 2/portal-bundle.d.ts +0 -119
  156. package/dist/shared/flap 2/portal-bundle.js +0 -584
  157. package/dist/shared/flap 2/portal.d.ts +0 -392
  158. package/dist/shared/flap 2/portal.js +0 -559
  159. package/dist/shared/flap 2/vanity.d.ts +0 -48
  160. package/dist/shared/flap 2/vanity.js +0 -110
  161. package/dist/shared/flap 2/vault.d.ts +0 -240
  162. package/dist/shared/flap 2/vault.js +0 -366
  163. package/dist/shared/four 2/index.d.ts +0 -7
  164. package/dist/shared/four 2/index.js +0 -22
  165. package/dist/shared/four 2/tax-token.d.ts +0 -176
  166. package/dist/shared/four 2/tax-token.js +0 -302
  167. package/dist/shared/index 2.js +0 -10
  168. package/dist/shared/index.d 2.ts +0 -10
  169. package/dist/types/distribute.d.ts +0 -72
  170. package/dist/types/distribute.js +0 -1
  171. package/dist/types 2/errors.d.ts +0 -27
  172. package/dist/types 2/errors.js +0 -34
  173. package/dist/utils/__tests__/errors.test.d.ts +0 -1
  174. package/dist/utils/__tests__/errors.test.js +0 -76
  175. package/dist/utils/airdrop-sweep-types.d.ts +0 -1
  176. package/dist/utils/airdrop-sweep-types.js +0 -1
  177. package/dist/utils/erc20/index.d.ts +0 -242
  178. package/dist/utils/erc20/index.js +0 -645
  179. package/dist/utils/erc20/types.d.ts +0 -77
  180. package/dist/utils/erc20/types.js +0 -1
  181. package/dist/utils/erc20-types.d.ts +0 -1
  182. package/dist/utils/erc20-types.js +0 -1
  183. package/dist/utils/holders-maker/helpers.d.ts +0 -43
  184. package/dist/utils/holders-maker/helpers.js +0 -371
  185. package/dist/utils/holders-maker/index.d.ts +0 -26
  186. package/dist/utils/holders-maker/index.js +0 -218
  187. package/dist/utils/holders-maker/types.d.ts +0 -72
  188. package/dist/utils/holders-maker/types.js +0 -4
  189. package/dist/utils/holders-maker-types.d.ts +0 -1
  190. package/dist/utils/holders-maker-types.js +0 -1
  191. package/dist/utils/lp-inspect/index.d.ts +0 -44
  192. package/dist/utils/lp-inspect/index.js +0 -937
  193. package/dist/utils/lp-inspect/types.d.ts +0 -100
  194. package/dist/utils/lp-inspect/types.js +0 -1
  195. package/dist/utils/lp-inspect-types.d.ts +0 -1
  196. package/dist/utils/lp-inspect-types.js +0 -1
  197. package/dist/utils/private-sale-types.d.ts +0 -1
  198. package/dist/utils/private-sale-types.js +0 -1
  199. package/dist/utils/quote-helpers/index.d.ts +0 -107
  200. package/dist/utils/quote-helpers/index.js +0 -346
  201. package/dist/utils/quote-helpers/types.d.ts +0 -16
  202. package/dist/utils/quote-helpers/types.js +0 -1
  203. package/dist/utils/quote-helpers-types.d.ts +0 -1
  204. package/dist/utils/quote-helpers-types.js +0 -1
  205. /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;