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,596 +0,0 @@
1
- /**
2
- * BlockRazor Bundle Service 客户端
3
- *
4
- * 提供基于 BlockRazor 的 MEV 保护和捆绑交易服务
5
- *
6
- * 官方文档: https://blockrazor.gitbook.io/blockrazor/bsc/block-builder/send-bundle
7
- *
8
- * 特点:
9
- * - 支持 BSC 链的 Bundle 提交
10
- * - 激励机制:向 Builder EOA 转账 BNB 可提高优先级
11
- * - 支持 Bundle 合并提高打包率
12
- *
13
- * 使用示例:
14
- * ```typescript
15
- * import { BlockRazorClient } from 'four-flap-meme-sdk';
16
- *
17
- * const client = new BlockRazorClient({
18
- * apiKey: 'your-api-key',
19
- * chainId: 56
20
- * });
21
- *
22
- * const result = await client.sendBundle({
23
- * transactions: [tx1, tx2, tx3],
24
- * blockOffset: 10
25
- * });
26
- * ```
27
- */
28
- import { JsonRpcProvider, Transaction, ethers } from 'ethers';
29
- import { GAS_LIMITS } from '../constants/index.js';
30
- // ============================================================================
31
- // 常量
32
- // ============================================================================
33
- /**
34
- * BlockRazor Builder EOA 地址
35
- * 向此地址转账 BNB 可提高 Bundle 优先级
36
- * 来源: https://blockrazor.gitbook.io/blockrazor/bsc/block-builder/send-bundle
37
- */
38
- export const BLOCKRAZOR_BUILDER_EOA = '0x1266C6bE60392A8Ff346E8d5ECCd3E69dD9c5F20';
39
- /**
40
- * BlockRazor BSC RPC 端点
41
- * 来源: 测试文件 008_blockrazor_smoke_test.ts
42
- */
43
- const BLOCKRAZOR_RPC_ENDPOINTS = {
44
- BSC: 'https://rpc.blockrazor.builders',
45
- // 可以添加其他链的端点
46
- };
47
- /**
48
- * 最低 Gas Price 要求 (0.05 Gwei)
49
- */
50
- const MIN_GAS_PRICE_GWEI = 0.05;
51
- // ============================================================================
52
- // BlockRazor 客户端
53
- // ============================================================================
54
- /**
55
- * BlockRazor 客户端
56
- */
57
- export class BlockRazorClient {
58
- constructor(config) {
59
- // 区块号缓存
60
- this.blockNumberCache = null;
61
- this.chainId = config.chainId;
62
- this.apiKey = config.apiKey;
63
- // 普通 RPC(用于查询)
64
- const rpcUrl = config.customRpcUrl || 'https://bsc-dataseed.binance.org';
65
- this.provider = new JsonRpcProvider(rpcUrl, {
66
- chainId: this.chainId,
67
- name: 'bsc',
68
- });
69
- // Builder RPC URL(用于发送 Bundle)
70
- // ✅ 正确的端点: https://rpc.blockrazor.builders
71
- this.builderUrl = config.builderRpcUrl || BLOCKRAZOR_RPC_ENDPOINTS.BSC;
72
- }
73
- /**
74
- * 获取 Provider
75
- */
76
- getProvider() {
77
- return this.provider;
78
- }
79
- /**
80
- * 获取 Builder URL
81
- */
82
- getBuilderUrl() {
83
- return this.builderUrl;
84
- }
85
- /**
86
- * 获取当前区块号(带缓存)
87
- */
88
- async getBlockNumber(forceRefresh = false) {
89
- const now = Date.now();
90
- if (!forceRefresh && this.blockNumberCache) {
91
- const age = now - this.blockNumberCache.timestamp;
92
- if (age < BlockRazorClient.BLOCK_CACHE_TTL_MS) {
93
- return this.blockNumberCache.value;
94
- }
95
- }
96
- const blockNumber = await this.provider.getBlockNumber();
97
- this.blockNumberCache = { value: blockNumber, timestamp: now };
98
- return blockNumber;
99
- }
100
- /**
101
- * 获取 Gas 价格信息
102
- */
103
- async getFeeData() {
104
- return await this.provider.getFeeData();
105
- }
106
- /**
107
- * 构建激励交易(向 BlockRazor Builder EOA 转账 BNB)
108
- *
109
- * 根据文档:向 Builder EOA 转账更多 BNB 可提高 Bundle 优先级
110
- *
111
- * @param params 激励交易参数
112
- * @returns 已签名的交易
113
- */
114
- async buildIncentiveTransaction(params) {
115
- const { wallet, amount, nonce, gasPrice } = params;
116
- // 获取 nonce(使用 pending 确保包含待处理交易)
117
- const txNonce = nonce ?? await this.provider.getTransactionCount(wallet.address, 'pending');
118
- // 获取 gas price
119
- let txGasPrice = gasPrice;
120
- if (!txGasPrice) {
121
- const feeData = await this.getFeeData();
122
- txGasPrice = feeData.gasPrice || ethers.parseUnits(String(MIN_GAS_PRICE_GWEI), 'gwei');
123
- }
124
- // 构建交易
125
- const tx = {
126
- to: BLOCKRAZOR_BUILDER_EOA,
127
- value: ethers.parseEther(amount),
128
- nonce: txNonce,
129
- gasLimit: GAS_LIMITS.BRIBE,
130
- gasPrice: txGasPrice,
131
- chainId: this.chainId,
132
- type: 0,
133
- };
134
- return await wallet.signTransaction(tx);
135
- }
136
- /**
137
- * 发送捆绑交易(底层方法)
138
- *
139
- * ✅ 使用 fetch 直接发送请求,支持 Authorization 头
140
- *
141
- * @param params Bundle 参数
142
- * @returns Bundle Hash
143
- */
144
- async sendBundleRaw(params) {
145
- if (!params.txs || params.txs.length === 0) {
146
- throw new Error('Bundle transactions cannot be empty');
147
- }
148
- // 验证 Gas Price(最低 0.05 Gwei)
149
- for (const rawTx of params.txs) {
150
- try {
151
- const tx = Transaction.from(rawTx);
152
- const gasPrice = tx.gasPrice || 0n;
153
- const minGasPrice = ethers.parseUnits(String(MIN_GAS_PRICE_GWEI), 'gwei');
154
- if (gasPrice < minGasPrice) {
155
- }
156
- }
157
- catch {
158
- // 解析失败,跳过检查
159
- }
160
- }
161
- // 构建请求参数
162
- const bundleParams = {
163
- txs: params.txs,
164
- };
165
- if (params.maxBlockNumber !== undefined) {
166
- bundleParams.maxBlockNumber = params.maxBlockNumber;
167
- }
168
- if (params.minTimestamp !== undefined) {
169
- bundleParams.minTimestamp = params.minTimestamp;
170
- }
171
- if (params.maxTimestamp !== undefined) {
172
- bundleParams.maxTimestamp = params.maxTimestamp;
173
- }
174
- if (params.revertingTxHashes && params.revertingTxHashes.length > 0) {
175
- bundleParams.revertingTxHashes = params.revertingTxHashes;
176
- }
177
- if (params.noMerge !== undefined) {
178
- bundleParams.noMerge = params.noMerge;
179
- }
180
- try {
181
- // ✅ 使用 fetch 发送请求,支持 Authorization 头
182
- const requestBody = {
183
- jsonrpc: '2.0',
184
- id: '1',
185
- method: 'eth_sendBundle',
186
- params: [bundleParams]
187
- };
188
- const headers = {
189
- 'Content-Type': 'application/json',
190
- };
191
- // 如果有 API Key,添加 Authorization 头
192
- if (this.apiKey) {
193
- headers['Authorization'] = this.apiKey;
194
- }
195
- const response = await fetch(this.builderUrl, {
196
- method: 'POST',
197
- headers,
198
- body: JSON.stringify(requestBody),
199
- });
200
- if (!response.ok) {
201
- const text = await response.text();
202
- throw new Error(`HTTP ${response.status}: ${text}`);
203
- }
204
- const result = await response.json();
205
- // 检查 JSON-RPC 错误
206
- if (result.error) {
207
- throw new Error(`RPC Error: ${result.error.message || JSON.stringify(result.error)}`);
208
- }
209
- // 提取 bundle hash
210
- const bundleHash = result.result;
211
- if (typeof bundleHash === 'string') {
212
- return bundleHash;
213
- }
214
- if (bundleHash && typeof bundleHash === 'object') {
215
- if ('bundleHash' in bundleHash) {
216
- return String(bundleHash.bundleHash);
217
- }
218
- }
219
- return JSON.stringify(result.result || result);
220
- }
221
- catch (error) {
222
- const errorMsg = error.message || String(error);
223
- console.error(`❌ [BlockRazor] Bundle 发送失败: ${errorMsg}`);
224
- throw new Error(`BlockRazor send bundle failed: ${errorMsg}`);
225
- }
226
- }
227
- /**
228
- * 发送捆绑交易(高级方法)
229
- *
230
- * @param options 发送选项
231
- * @returns Bundle 结果
232
- */
233
- async sendBundle(options) {
234
- if (!options.transactions || options.transactions.length === 0) {
235
- throw new Error('Transactions array cannot be empty');
236
- }
237
- const blockOffset = options.blockOffset ?? 100;
238
- const maxBlockOffset = options.maxBlockOffset ?? 100;
239
- const autoRetry = options.autoRetry ?? false;
240
- const maxRetries = options.maxRetries ?? 3;
241
- let attempt = 0;
242
- let lastError = null;
243
- while (attempt <= (autoRetry ? maxRetries : 0)) {
244
- try {
245
- // 获取当前区块
246
- const currentBlock = await this.getBlockNumber(true);
247
- // 计算最大有效区块号
248
- const actualOffset = Math.min(blockOffset, maxBlockOffset);
249
- const maxBlockNumber = currentBlock + actualOffset;
250
- // 发送 Bundle
251
- const bundleHash = await this.sendBundleRaw({
252
- txs: options.transactions,
253
- maxBlockNumber,
254
- minTimestamp: options.minTimestamp,
255
- maxTimestamp: options.maxTimestamp,
256
- revertingTxHashes: options.revertingTxHashes,
257
- noMerge: options.noMerge,
258
- });
259
- // 提取交易哈希
260
- const txHashes = options.transactions.map(rawTx => {
261
- try {
262
- return Transaction.from(rawTx).hash || '';
263
- }
264
- catch {
265
- return '';
266
- }
267
- });
268
- return {
269
- bundleHash,
270
- txHashes,
271
- maxBlockNumber,
272
- txCount: options.transactions.length,
273
- };
274
- }
275
- catch (error) {
276
- lastError = error;
277
- if (autoRetry && attempt < maxRetries) {
278
- attempt++;
279
- await new Promise(resolve => setTimeout(resolve, 3000)); // 等待一个区块
280
- continue;
281
- }
282
- throw error;
283
- }
284
- }
285
- throw lastError || new Error('Bundle submission failed after all retries');
286
- }
287
- /**
288
- * 发送带激励的 Bundle(自动添加激励交易)
289
- *
290
- * @param options 发送选项
291
- * @param incentive 激励参数
292
- * @returns Bundle 结果
293
- */
294
- async sendBundleWithIncentive(options, incentive) {
295
- // 获取激励钱包的 nonce(使用 pending 确保包含待处理交易)
296
- const nonce = await this.provider.getTransactionCount(incentive.wallet.address, 'pending');
297
- // 构建激励交易(放在 Bundle 最后)
298
- const incentiveTx = await this.buildIncentiveTransaction({
299
- wallet: incentive.wallet,
300
- amount: incentive.amount,
301
- nonce: nonce,
302
- });
303
- // 将激励交易添加到 Bundle 末尾
304
- const allTransactions = [...options.transactions, incentiveTx];
305
- return await this.sendBundle({
306
- ...options,
307
- transactions: allTransactions,
308
- });
309
- }
310
- /**
311
- * 等待 Bundle 中的交易确认
312
- *
313
- * @param txHashes 交易哈希列表
314
- * @param confirmations 确认数(默认 1)
315
- * @param timeout 超时时间(毫秒,默认 120000)
316
- * @returns 交易结果列表
317
- */
318
- async waitForBundleConfirmation(txHashes, confirmations = 1, timeout = 120000) {
319
- const promises = txHashes.map(async (hash, index) => {
320
- try {
321
- const receipt = await this.provider.waitForTransaction(hash, confirmations, timeout);
322
- if (!receipt) {
323
- return {
324
- index,
325
- hash,
326
- success: false,
327
- error: 'Transaction not found',
328
- };
329
- }
330
- let gasCost;
331
- if (receipt.gasUsed && receipt.gasPrice) {
332
- const costWei = receipt.gasUsed * receipt.gasPrice;
333
- const costBnb = Number(costWei) / 1e18;
334
- gasCost = costBnb.toFixed(8);
335
- }
336
- return {
337
- index,
338
- hash,
339
- success: receipt.status === 1,
340
- blockNumber: receipt.blockNumber,
341
- gasUsed: receipt.gasUsed.toString(),
342
- effectiveGasPrice: receipt.gasPrice?.toString(),
343
- gasCost,
344
- };
345
- }
346
- catch (error) {
347
- return {
348
- index,
349
- hash,
350
- success: false,
351
- error: error.message,
352
- };
353
- }
354
- });
355
- return await Promise.all(promises);
356
- }
357
- /**
358
- * 签名交易批次
359
- *
360
- * @param wallet 钱包
361
- * @param transactions 交易列表
362
- * @param options 可选参数
363
- * @returns 已签名的交易数组
364
- */
365
- async signTransactions(wallet, transactions, options) {
366
- if (!transactions || transactions.length === 0) {
367
- throw new Error('Transactions array cannot be empty');
368
- }
369
- // 获取 nonce(使用 pending 确保包含待处理交易)
370
- let nonce = options?.startNonce;
371
- if (nonce === undefined) {
372
- nonce = await this.provider.getTransactionCount(wallet.address, 'pending');
373
- }
374
- // 获取 Gas Price(确保不低于最低要求)
375
- let gasPrice = options?.gasPrice;
376
- if (!gasPrice) {
377
- const feeData = await this.provider.getFeeData();
378
- const baseGasPrice = feeData.gasPrice || ethers.parseUnits(String(MIN_GAS_PRICE_GWEI), 'gwei');
379
- const multiplier = options?.gasPriceMultiplier || 50;
380
- gasPrice = (baseGasPrice * BigInt(100 + multiplier)) / 100n;
381
- // 确保不低于最低要求
382
- const minGasPrice = ethers.parseUnits(String(MIN_GAS_PRICE_GWEI), 'gwei');
383
- if (gasPrice < minGasPrice) {
384
- gasPrice = minGasPrice;
385
- }
386
- }
387
- // 并行签名所有交易
388
- const signedTxs = await Promise.all(transactions.map(async (tx, i) => {
389
- const fullTx = {
390
- ...tx,
391
- nonce: nonce + i,
392
- gasPrice,
393
- chainId: this.chainId,
394
- };
395
- return await wallet.signTransaction(fullTx);
396
- }));
397
- return signedTxs;
398
- }
399
- /**
400
- * 检查交易是否已包含在区块中
401
- */
402
- async isTransactionIncluded(txHash) {
403
- try {
404
- const receipt = await this.provider.getTransactionReceipt(txHash);
405
- return receipt !== null && receipt.blockNumber !== null;
406
- }
407
- catch {
408
- return false;
409
- }
410
- }
411
- // ============================================================================
412
- // 非捆绑广播方法(适用于 XLayer/Monad 等不支持 Bundle 的链)
413
- // ============================================================================
414
- /**
415
- * 并行广播交易(非捆绑)
416
- *
417
- * 所有交易同时广播,适合不同钱包的独立交易
418
- * ⚠️ 注意:同一钱包的多笔交易(连续 nonce)不建议并行广播,可能导致后续交易延迟确认
419
- *
420
- * @param signedTransactions 已签名的交易数组
421
- * @param options 可选配置
422
- * @returns 广播结果
423
- */
424
- async broadcastTransactionsParallel(signedTransactions, options) {
425
- if (!signedTransactions || signedTransactions.length === 0) {
426
- return { success: false, txHashes: [], errors: [{ index: 0, error: '没有交易数据' }] };
427
- }
428
- const provider = options?.provider || this.provider;
429
- const concurrencyLimit = options?.concurrencyLimit || 10;
430
- const txHashes = [];
431
- const errors = [];
432
- // 分批并行广播
433
- for (let i = 0; i < signedTransactions.length; i += concurrencyLimit) {
434
- const batch = signedTransactions.slice(i, i + concurrencyLimit);
435
- const batchPromises = batch.map(async (rawTx, batchIndex) => {
436
- const globalIndex = i + batchIndex;
437
- try {
438
- const txResponse = await provider.broadcastTransaction(rawTx);
439
- return { index: globalIndex, hash: txResponse.hash, error: null };
440
- }
441
- catch (err) {
442
- const errorMsg = err?.message || String(err);
443
- console.warn(`[broadcastParallel] 交易 ${globalIndex} 广播失败:`, errorMsg);
444
- return { index: globalIndex, hash: '', error: errorMsg };
445
- }
446
- });
447
- const results = await Promise.all(batchPromises);
448
- for (const result of results) {
449
- if (result.hash) {
450
- txHashes.push(result.hash);
451
- }
452
- if (result.error) {
453
- errors.push({ index: result.index, error: result.error });
454
- }
455
- }
456
- }
457
- return {
458
- success: errors.length === 0,
459
- txHashes,
460
- errors,
461
- };
462
- }
463
- /**
464
- * 顺序广播交易(非捆绑)
465
- *
466
- * 按顺序逐笔广播,可选等待确认后再广播下一笔
467
- * ✅ 适合同一钱包的多笔交易(连续 nonce),确保交易按顺序上链
468
- *
469
- * @param signedTransactions 已签名的交易数组
470
- * @param options 可选配置
471
- * @returns 广播结果
472
- */
473
- async broadcastTransactionsSequential(signedTransactions, options) {
474
- if (!signedTransactions || signedTransactions.length === 0) {
475
- return { success: false, txHashes: [], errors: [{ index: 0, error: '没有交易数据' }] };
476
- }
477
- const provider = options?.provider || this.provider;
478
- const waitConfirmation = options?.waitConfirmation ?? false;
479
- const confirmationTimeout = options?.confirmationTimeout ?? 60000;
480
- const broadcastDelay = options?.broadcastDelay ?? 100;
481
- const txHashes = [];
482
- const errors = [];
483
- for (let i = 0; i < signedTransactions.length; i++) {
484
- const rawTx = signedTransactions[i];
485
- if (!rawTx)
486
- continue;
487
- try {
488
- // 广播交易
489
- const txResponse = await provider.broadcastTransaction(rawTx);
490
- txHashes.push(txResponse.hash);
491
- console.log(`[broadcastSequential] 交易 ${i}/${signedTransactions.length} 广播成功: ${txResponse.hash.slice(0, 10)}...`);
492
- // 如果需要等待确认
493
- if (waitConfirmation) {
494
- try {
495
- const receipt = await provider.waitForTransaction(txResponse.hash, 1, confirmationTimeout);
496
- if (receipt && receipt.status === 1) {
497
- console.log(`[broadcastSequential] 交易 ${i} 确认成功,区块: ${receipt.blockNumber}`);
498
- }
499
- else if (receipt && receipt.status === 0) {
500
- console.warn(`[broadcastSequential] 交易 ${i} 执行失败(revert)`);
501
- errors.push({ index: i, error: 'Transaction reverted' });
502
- }
503
- }
504
- catch (waitErr) {
505
- console.warn(`[broadcastSequential] 交易 ${i} 等待确认超时:`, waitErr?.message);
506
- // 超时不算失败,交易可能还在 pending
507
- }
508
- }
509
- else {
510
- // 不等待确认,只加一个小延迟确保 RPC 处理完成
511
- if (broadcastDelay > 0 && i < signedTransactions.length - 1) {
512
- await new Promise(resolve => setTimeout(resolve, broadcastDelay));
513
- }
514
- }
515
- }
516
- catch (err) {
517
- const errorMsg = err?.message || String(err);
518
- console.warn(`[broadcastSequential] 交易 ${i} 广播失败:`, errorMsg);
519
- errors.push({ index: i, error: errorMsg });
520
- // 如果是 nonce 问题,后续交易也会失败,提前终止
521
- if (errorMsg.includes('nonce') || errorMsg.includes('replacement')) {
522
- console.error(`[broadcastSequential] Nonce 问题,终止后续广播`);
523
- break;
524
- }
525
- }
526
- }
527
- return {
528
- success: errors.length === 0,
529
- txHashes,
530
- errors,
531
- };
532
- }
533
- /**
534
- * 智能广播交易(自动选择并行或顺序)
535
- *
536
- * 根据交易的发送者地址自动决定广播策略:
537
- * - 如果所有交易来自不同钱包:并行广播
538
- * - 如果存在同一钱包的多笔交易:顺序广播
539
- *
540
- * @param signedTransactions 已签名的交易数组
541
- * @param options 可选配置
542
- * @returns 广播结果
543
- */
544
- async broadcastTransactionsSmart(signedTransactions, options) {
545
- // 检测是否有同一钱包的多笔交易
546
- const hasMultipleFromSameWallet = (() => {
547
- if (!Array.isArray(signedTransactions) || signedTransactions.length < 2)
548
- return false;
549
- const seen = new Set();
550
- for (const raw of signedTransactions) {
551
- if (!raw)
552
- continue;
553
- try {
554
- const tx = Transaction.from(raw);
555
- const from = (tx.from || '').toLowerCase();
556
- if (!from)
557
- continue;
558
- if (seen.has(from))
559
- return true;
560
- seen.add(from);
561
- }
562
- catch {
563
- // ignore parse errors
564
- }
565
- }
566
- return false;
567
- })();
568
- if (hasMultipleFromSameWallet) {
569
- console.log(`[broadcastSmart] 检测到同一钱包多笔交易,使用顺序广播`);
570
- const result = await this.broadcastTransactionsSequential(signedTransactions, options);
571
- return { ...result, mode: 'sequential' };
572
- }
573
- else {
574
- console.log(`[broadcastSmart] 所有交易来自不同钱包,使用并行广播`);
575
- const result = await this.broadcastTransactionsParallel(signedTransactions, { provider: options?.provider });
576
- return { ...result, mode: 'parallel' };
577
- }
578
- }
579
- /**
580
- * 获取客户端信息
581
- */
582
- getClientInfo() {
583
- return {
584
- chainId: this.chainId,
585
- builderEOA: BLOCKRAZOR_BUILDER_EOA,
586
- minGasPriceGwei: MIN_GAS_PRICE_GWEI,
587
- };
588
- }
589
- }
590
- BlockRazorClient.BLOCK_CACHE_TTL_MS = 1000; // 1秒缓存
591
- /**
592
- * 创建 BlockRazor 客户端的便捷函数
593
- */
594
- export function createBlockRazorClient(apiKey) {
595
- return new BlockRazorClient({ apiKey, chainId: 56 });
596
- }