four-flap-meme-sdk 1.3.77 → 1.3.79
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.
- package/dist/clients/blockrazor.d.ts +237 -0
- package/dist/clients/blockrazor.js +435 -0
- package/dist/contracts/tm-bundle-merkle/index.d.ts +1 -1
- package/dist/contracts/tm-bundle-merkle/index.js +5 -1
- package/dist/contracts/tm-bundle-merkle/pancake-proxy.js +1 -1
- package/dist/contracts/tm-bundle-merkle/submit.d.ts +95 -1
- package/dist/contracts/tm-bundle-merkle/submit.js +130 -1
- package/dist/flap/portal-bundle-merkle/pancake-proxy.js +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/pancake/bundle-buy-first.js +1 -1
- package/dist/pancake/bundle-swap.js +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,237 @@
|
|
|
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, Wallet, TransactionLike, ethers } from 'ethers';
|
|
29
|
+
/**
|
|
30
|
+
* BlockRazor Builder EOA 地址
|
|
31
|
+
* 向此地址转账 BNB 可提高 Bundle 优先级
|
|
32
|
+
* 来源: https://blockrazor.gitbook.io/blockrazor/bsc/block-builder/send-bundle
|
|
33
|
+
*/
|
|
34
|
+
export declare const BLOCKRAZOR_BUILDER_EOA = "0x1266C6bE60392A8Ff346E8d5ECCd3E69dD9c5F20";
|
|
35
|
+
/**
|
|
36
|
+
* BlockRazor 客户端配置
|
|
37
|
+
*/
|
|
38
|
+
export interface BlockRazorConfig {
|
|
39
|
+
/** API Key(可选,根据 Tier 等级需要) */
|
|
40
|
+
apiKey?: string;
|
|
41
|
+
/** 链 ID: 56=BSC */
|
|
42
|
+
chainId: 56;
|
|
43
|
+
/** 自定义 RPC URL(可选) */
|
|
44
|
+
customRpcUrl?: string;
|
|
45
|
+
/** 自定义 Builder RPC URL(可选,用于发送 Bundle) */
|
|
46
|
+
builderRpcUrl?: string;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* BlockRazor Bundle 参数(原始格式)
|
|
50
|
+
* 参考: https://blockrazor.gitbook.io/blockrazor/bsc/block-builder/send-bundle
|
|
51
|
+
*/
|
|
52
|
+
export interface BlockRazorBundleParams {
|
|
53
|
+
/** 已签名的交易数组(原始交易字符串) */
|
|
54
|
+
txs: string[];
|
|
55
|
+
/** 最大有效区块号(默认: 当前区块 + 100) */
|
|
56
|
+
maxBlockNumber?: number;
|
|
57
|
+
/** 最小有效时间戳(秒) */
|
|
58
|
+
minTimestamp?: number;
|
|
59
|
+
/** 最大有效时间戳(秒) */
|
|
60
|
+
maxTimestamp?: number;
|
|
61
|
+
/** 允许 revert 的交易哈希列表 */
|
|
62
|
+
revertingTxHashes?: string[];
|
|
63
|
+
/** 是否禁止 Bundle 合并(默认 false,允许合并可提高打包率) */
|
|
64
|
+
noMerge?: boolean;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* 发送 Bundle 的选项(高级接口)
|
|
68
|
+
*/
|
|
69
|
+
export interface SendBundleOptions {
|
|
70
|
+
/** 已签名的交易数组 */
|
|
71
|
+
transactions: string[];
|
|
72
|
+
/** 区块偏移量(默认 10,即当前区块 + 10) */
|
|
73
|
+
blockOffset?: number;
|
|
74
|
+
/** 最大区块偏移量(默认 100) */
|
|
75
|
+
maxBlockOffset?: number;
|
|
76
|
+
/** 最小时间戳 */
|
|
77
|
+
minTimestamp?: number;
|
|
78
|
+
/** 最大时间戳 */
|
|
79
|
+
maxTimestamp?: number;
|
|
80
|
+
/** 允许 revert 的交易哈希列表 */
|
|
81
|
+
revertingTxHashes?: string[];
|
|
82
|
+
/** 是否禁止 Bundle 合并 */
|
|
83
|
+
noMerge?: boolean;
|
|
84
|
+
/** 是否启用自动重试(默认 false) */
|
|
85
|
+
autoRetry?: boolean;
|
|
86
|
+
/** 最大重试次数(默认 3) */
|
|
87
|
+
maxRetries?: number;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Bundle 发送结果
|
|
91
|
+
*/
|
|
92
|
+
export interface BundleResult {
|
|
93
|
+
/** Bundle Hash */
|
|
94
|
+
bundleHash: string;
|
|
95
|
+
/** 交易哈希列表 */
|
|
96
|
+
txHashes: string[];
|
|
97
|
+
/** 最大有效区块号 */
|
|
98
|
+
maxBlockNumber: number;
|
|
99
|
+
/** 交易数量 */
|
|
100
|
+
txCount: number;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* 交易确认结果
|
|
104
|
+
*/
|
|
105
|
+
export interface TransactionResult {
|
|
106
|
+
/** 交易索引 */
|
|
107
|
+
index: number;
|
|
108
|
+
/** 交易哈希 */
|
|
109
|
+
hash: string;
|
|
110
|
+
/** 是否成功 */
|
|
111
|
+
success: boolean;
|
|
112
|
+
/** 区块号 */
|
|
113
|
+
blockNumber?: number;
|
|
114
|
+
/** Gas 使用量 */
|
|
115
|
+
gasUsed?: string;
|
|
116
|
+
/** 有效 Gas Price */
|
|
117
|
+
effectiveGasPrice?: string;
|
|
118
|
+
/** Gas 费用(BNB) */
|
|
119
|
+
gasCost?: string;
|
|
120
|
+
/** 错误信息 */
|
|
121
|
+
error?: string;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* 激励交易参数
|
|
125
|
+
*/
|
|
126
|
+
export interface IncentiveTransactionParams {
|
|
127
|
+
/** 发送者钱包 */
|
|
128
|
+
wallet: Wallet;
|
|
129
|
+
/** 激励金额(BNB) */
|
|
130
|
+
amount: string;
|
|
131
|
+
/** Nonce(可选,自动获取) */
|
|
132
|
+
nonce?: number;
|
|
133
|
+
/** Gas Price(可选,自动获取) */
|
|
134
|
+
gasPrice?: bigint;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* BlockRazor 客户端
|
|
138
|
+
*/
|
|
139
|
+
export declare class BlockRazorClient {
|
|
140
|
+
private provider;
|
|
141
|
+
private chainId;
|
|
142
|
+
private apiKey?;
|
|
143
|
+
private builderUrl;
|
|
144
|
+
private blockNumberCache;
|
|
145
|
+
private static BLOCK_CACHE_TTL_MS;
|
|
146
|
+
constructor(config: BlockRazorConfig);
|
|
147
|
+
/**
|
|
148
|
+
* 获取 Provider
|
|
149
|
+
*/
|
|
150
|
+
getProvider(): JsonRpcProvider;
|
|
151
|
+
/**
|
|
152
|
+
* 获取 Builder URL
|
|
153
|
+
*/
|
|
154
|
+
getBuilderUrl(): string;
|
|
155
|
+
/**
|
|
156
|
+
* 获取当前区块号(带缓存)
|
|
157
|
+
*/
|
|
158
|
+
getBlockNumber(forceRefresh?: boolean): Promise<number>;
|
|
159
|
+
/**
|
|
160
|
+
* 获取 Gas 价格信息
|
|
161
|
+
*/
|
|
162
|
+
getFeeData(): Promise<ethers.FeeData>;
|
|
163
|
+
/**
|
|
164
|
+
* 构建激励交易(向 BlockRazor Builder EOA 转账 BNB)
|
|
165
|
+
*
|
|
166
|
+
* 根据文档:向 Builder EOA 转账更多 BNB 可提高 Bundle 优先级
|
|
167
|
+
*
|
|
168
|
+
* @param params 激励交易参数
|
|
169
|
+
* @returns 已签名的交易
|
|
170
|
+
*/
|
|
171
|
+
buildIncentiveTransaction(params: IncentiveTransactionParams): Promise<string>;
|
|
172
|
+
/**
|
|
173
|
+
* 发送捆绑交易(底层方法)
|
|
174
|
+
*
|
|
175
|
+
* ✅ 使用 fetch 直接发送请求,支持 Authorization 头
|
|
176
|
+
*
|
|
177
|
+
* @param params Bundle 参数
|
|
178
|
+
* @returns Bundle Hash
|
|
179
|
+
*/
|
|
180
|
+
sendBundleRaw(params: BlockRazorBundleParams): Promise<string>;
|
|
181
|
+
/**
|
|
182
|
+
* 发送捆绑交易(高级方法)
|
|
183
|
+
*
|
|
184
|
+
* @param options 发送选项
|
|
185
|
+
* @returns Bundle 结果
|
|
186
|
+
*/
|
|
187
|
+
sendBundle(options: SendBundleOptions): Promise<BundleResult>;
|
|
188
|
+
/**
|
|
189
|
+
* 发送带激励的 Bundle(自动添加激励交易)
|
|
190
|
+
*
|
|
191
|
+
* @param options 发送选项
|
|
192
|
+
* @param incentive 激励参数
|
|
193
|
+
* @returns Bundle 结果
|
|
194
|
+
*/
|
|
195
|
+
sendBundleWithIncentive(options: SendBundleOptions, incentive: {
|
|
196
|
+
wallet: Wallet;
|
|
197
|
+
amount: string;
|
|
198
|
+
}): Promise<BundleResult>;
|
|
199
|
+
/**
|
|
200
|
+
* 等待 Bundle 中的交易确认
|
|
201
|
+
*
|
|
202
|
+
* @param txHashes 交易哈希列表
|
|
203
|
+
* @param confirmations 确认数(默认 1)
|
|
204
|
+
* @param timeout 超时时间(毫秒,默认 120000)
|
|
205
|
+
* @returns 交易结果列表
|
|
206
|
+
*/
|
|
207
|
+
waitForBundleConfirmation(txHashes: string[], confirmations?: number, timeout?: number): Promise<TransactionResult[]>;
|
|
208
|
+
/**
|
|
209
|
+
* 签名交易批次
|
|
210
|
+
*
|
|
211
|
+
* @param wallet 钱包
|
|
212
|
+
* @param transactions 交易列表
|
|
213
|
+
* @param options 可选参数
|
|
214
|
+
* @returns 已签名的交易数组
|
|
215
|
+
*/
|
|
216
|
+
signTransactions(wallet: Wallet, transactions: TransactionLike[], options?: {
|
|
217
|
+
startNonce?: number;
|
|
218
|
+
gasPrice?: bigint;
|
|
219
|
+
gasPriceMultiplier?: number;
|
|
220
|
+
}): Promise<string[]>;
|
|
221
|
+
/**
|
|
222
|
+
* 检查交易是否已包含在区块中
|
|
223
|
+
*/
|
|
224
|
+
isTransactionIncluded(txHash: string): Promise<boolean>;
|
|
225
|
+
/**
|
|
226
|
+
* 获取客户端信息
|
|
227
|
+
*/
|
|
228
|
+
getClientInfo(): {
|
|
229
|
+
chainId: number;
|
|
230
|
+
builderEOA: string;
|
|
231
|
+
minGasPriceGwei: number;
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* 创建 BlockRazor 客户端的便捷函数
|
|
236
|
+
*/
|
|
237
|
+
export declare function createBlockRazorClient(apiKey?: string): BlockRazorClient;
|
|
@@ -0,0 +1,435 @@
|
|
|
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
|
+
// ============================================================================
|
|
30
|
+
// 常量
|
|
31
|
+
// ============================================================================
|
|
32
|
+
/**
|
|
33
|
+
* BlockRazor Builder EOA 地址
|
|
34
|
+
* 向此地址转账 BNB 可提高 Bundle 优先级
|
|
35
|
+
* 来源: https://blockrazor.gitbook.io/blockrazor/bsc/block-builder/send-bundle
|
|
36
|
+
*/
|
|
37
|
+
export const BLOCKRAZOR_BUILDER_EOA = '0x1266C6bE60392A8Ff346E8d5ECCd3E69dD9c5F20';
|
|
38
|
+
/**
|
|
39
|
+
* BlockRazor BSC RPC 端点
|
|
40
|
+
* 来源: 测试文件 008_blockrazor_smoke_test.ts
|
|
41
|
+
*/
|
|
42
|
+
const BLOCKRAZOR_RPC_ENDPOINTS = {
|
|
43
|
+
BSC: 'https://rpc.blockrazor.builders',
|
|
44
|
+
// 可以添加其他链的端点
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* 最低 Gas Price 要求 (0.05 Gwei)
|
|
48
|
+
*/
|
|
49
|
+
const MIN_GAS_PRICE_GWEI = 0.05;
|
|
50
|
+
// ============================================================================
|
|
51
|
+
// BlockRazor 客户端
|
|
52
|
+
// ============================================================================
|
|
53
|
+
/**
|
|
54
|
+
* BlockRazor 客户端
|
|
55
|
+
*/
|
|
56
|
+
export class BlockRazorClient {
|
|
57
|
+
constructor(config) {
|
|
58
|
+
// 区块号缓存
|
|
59
|
+
this.blockNumberCache = null;
|
|
60
|
+
this.chainId = config.chainId;
|
|
61
|
+
this.apiKey = config.apiKey;
|
|
62
|
+
// 普通 RPC(用于查询)
|
|
63
|
+
const rpcUrl = config.customRpcUrl || 'https://bsc-dataseed.binance.org';
|
|
64
|
+
this.provider = new JsonRpcProvider(rpcUrl, {
|
|
65
|
+
chainId: this.chainId,
|
|
66
|
+
name: 'bsc',
|
|
67
|
+
});
|
|
68
|
+
// Builder RPC URL(用于发送 Bundle)
|
|
69
|
+
// ✅ 正确的端点: https://rpc.blockrazor.builders
|
|
70
|
+
this.builderUrl = config.builderRpcUrl || BLOCKRAZOR_RPC_ENDPOINTS.BSC;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* 获取 Provider
|
|
74
|
+
*/
|
|
75
|
+
getProvider() {
|
|
76
|
+
return this.provider;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* 获取 Builder URL
|
|
80
|
+
*/
|
|
81
|
+
getBuilderUrl() {
|
|
82
|
+
return this.builderUrl;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* 获取当前区块号(带缓存)
|
|
86
|
+
*/
|
|
87
|
+
async getBlockNumber(forceRefresh = false) {
|
|
88
|
+
const now = Date.now();
|
|
89
|
+
if (!forceRefresh && this.blockNumberCache) {
|
|
90
|
+
const age = now - this.blockNumberCache.timestamp;
|
|
91
|
+
if (age < BlockRazorClient.BLOCK_CACHE_TTL_MS) {
|
|
92
|
+
return this.blockNumberCache.value;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
const blockNumber = await this.provider.getBlockNumber();
|
|
96
|
+
this.blockNumberCache = { value: blockNumber, timestamp: now };
|
|
97
|
+
return blockNumber;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* 获取 Gas 价格信息
|
|
101
|
+
*/
|
|
102
|
+
async getFeeData() {
|
|
103
|
+
return await this.provider.getFeeData();
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* 构建激励交易(向 BlockRazor Builder EOA 转账 BNB)
|
|
107
|
+
*
|
|
108
|
+
* 根据文档:向 Builder EOA 转账更多 BNB 可提高 Bundle 优先级
|
|
109
|
+
*
|
|
110
|
+
* @param params 激励交易参数
|
|
111
|
+
* @returns 已签名的交易
|
|
112
|
+
*/
|
|
113
|
+
async buildIncentiveTransaction(params) {
|
|
114
|
+
const { wallet, amount, nonce, gasPrice } = params;
|
|
115
|
+
// 获取 nonce
|
|
116
|
+
const txNonce = nonce ?? await this.provider.getTransactionCount(wallet.address, 'latest');
|
|
117
|
+
// 获取 gas price
|
|
118
|
+
let txGasPrice = gasPrice;
|
|
119
|
+
if (!txGasPrice) {
|
|
120
|
+
const feeData = await this.getFeeData();
|
|
121
|
+
txGasPrice = feeData.gasPrice || ethers.parseUnits(String(MIN_GAS_PRICE_GWEI), 'gwei');
|
|
122
|
+
}
|
|
123
|
+
// 构建交易
|
|
124
|
+
const tx = {
|
|
125
|
+
to: BLOCKRAZOR_BUILDER_EOA,
|
|
126
|
+
value: ethers.parseEther(amount),
|
|
127
|
+
nonce: txNonce,
|
|
128
|
+
gasLimit: 21000n,
|
|
129
|
+
gasPrice: txGasPrice,
|
|
130
|
+
chainId: this.chainId,
|
|
131
|
+
type: 0,
|
|
132
|
+
};
|
|
133
|
+
return await wallet.signTransaction(tx);
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* 发送捆绑交易(底层方法)
|
|
137
|
+
*
|
|
138
|
+
* ✅ 使用 fetch 直接发送请求,支持 Authorization 头
|
|
139
|
+
*
|
|
140
|
+
* @param params Bundle 参数
|
|
141
|
+
* @returns Bundle Hash
|
|
142
|
+
*/
|
|
143
|
+
async sendBundleRaw(params) {
|
|
144
|
+
if (!params.txs || params.txs.length === 0) {
|
|
145
|
+
throw new Error('Bundle transactions cannot be empty');
|
|
146
|
+
}
|
|
147
|
+
// 验证 Gas Price(最低 0.05 Gwei)
|
|
148
|
+
for (const rawTx of params.txs) {
|
|
149
|
+
try {
|
|
150
|
+
const tx = Transaction.from(rawTx);
|
|
151
|
+
const gasPrice = tx.gasPrice || 0n;
|
|
152
|
+
const minGasPrice = ethers.parseUnits(String(MIN_GAS_PRICE_GWEI), 'gwei');
|
|
153
|
+
if (gasPrice < minGasPrice) {
|
|
154
|
+
console.warn(`⚠️ 交易 Gas Price (${ethers.formatUnits(gasPrice, 'gwei')} Gwei) 低于最低要求 (${MIN_GAS_PRICE_GWEI} Gwei)`);
|
|
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
|
+
console.log(`📦 [BlockRazor] 发送 Bundle: ${params.txs.length} 笔交易`);
|
|
182
|
+
// ✅ 使用 fetch 发送请求,支持 Authorization 头
|
|
183
|
+
const requestBody = {
|
|
184
|
+
jsonrpc: '2.0',
|
|
185
|
+
id: '1',
|
|
186
|
+
method: 'eth_sendBundle',
|
|
187
|
+
params: [bundleParams]
|
|
188
|
+
};
|
|
189
|
+
const headers = {
|
|
190
|
+
'Content-Type': 'application/json',
|
|
191
|
+
};
|
|
192
|
+
// 如果有 API Key,添加 Authorization 头
|
|
193
|
+
if (this.apiKey) {
|
|
194
|
+
headers['Authorization'] = this.apiKey;
|
|
195
|
+
}
|
|
196
|
+
const response = await fetch(this.builderUrl, {
|
|
197
|
+
method: 'POST',
|
|
198
|
+
headers,
|
|
199
|
+
body: JSON.stringify(requestBody),
|
|
200
|
+
});
|
|
201
|
+
if (!response.ok) {
|
|
202
|
+
const text = await response.text();
|
|
203
|
+
throw new Error(`HTTP ${response.status}: ${text}`);
|
|
204
|
+
}
|
|
205
|
+
const result = await response.json();
|
|
206
|
+
// 检查 JSON-RPC 错误
|
|
207
|
+
if (result.error) {
|
|
208
|
+
throw new Error(`RPC Error: ${result.error.message || JSON.stringify(result.error)}`);
|
|
209
|
+
}
|
|
210
|
+
// 提取 bundle hash
|
|
211
|
+
const bundleHash = result.result;
|
|
212
|
+
if (typeof bundleHash === 'string') {
|
|
213
|
+
console.log(`✅ [BlockRazor] Bundle 发送成功: ${bundleHash}`);
|
|
214
|
+
return bundleHash;
|
|
215
|
+
}
|
|
216
|
+
if (bundleHash && typeof bundleHash === 'object') {
|
|
217
|
+
if ('bundleHash' in bundleHash) {
|
|
218
|
+
console.log(`✅ [BlockRazor] Bundle 发送成功: ${bundleHash.bundleHash}`);
|
|
219
|
+
return String(bundleHash.bundleHash);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
console.log(`✅ [BlockRazor] Bundle 发送成功:`, result);
|
|
223
|
+
return JSON.stringify(result.result || result);
|
|
224
|
+
}
|
|
225
|
+
catch (error) {
|
|
226
|
+
const errorMsg = error.message || String(error);
|
|
227
|
+
console.error(`❌ [BlockRazor] Bundle 发送失败: ${errorMsg}`);
|
|
228
|
+
throw new Error(`BlockRazor send bundle failed: ${errorMsg}`);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* 发送捆绑交易(高级方法)
|
|
233
|
+
*
|
|
234
|
+
* @param options 发送选项
|
|
235
|
+
* @returns Bundle 结果
|
|
236
|
+
*/
|
|
237
|
+
async sendBundle(options) {
|
|
238
|
+
if (!options.transactions || options.transactions.length === 0) {
|
|
239
|
+
throw new Error('Transactions array cannot be empty');
|
|
240
|
+
}
|
|
241
|
+
const blockOffset = options.blockOffset ?? 100;
|
|
242
|
+
const maxBlockOffset = options.maxBlockOffset ?? 100;
|
|
243
|
+
const autoRetry = options.autoRetry ?? false;
|
|
244
|
+
const maxRetries = options.maxRetries ?? 3;
|
|
245
|
+
let attempt = 0;
|
|
246
|
+
let lastError = null;
|
|
247
|
+
while (attempt <= (autoRetry ? maxRetries : 0)) {
|
|
248
|
+
try {
|
|
249
|
+
// 获取当前区块
|
|
250
|
+
const currentBlock = await this.getBlockNumber(true);
|
|
251
|
+
// 计算最大有效区块号
|
|
252
|
+
const actualOffset = Math.min(blockOffset, maxBlockOffset);
|
|
253
|
+
const maxBlockNumber = currentBlock + actualOffset;
|
|
254
|
+
console.log(`📊 [BlockRazor] 当前区块: ${currentBlock}, 最大有效区块: ${maxBlockNumber}`);
|
|
255
|
+
// 发送 Bundle
|
|
256
|
+
const bundleHash = await this.sendBundleRaw({
|
|
257
|
+
txs: options.transactions,
|
|
258
|
+
maxBlockNumber,
|
|
259
|
+
minTimestamp: options.minTimestamp,
|
|
260
|
+
maxTimestamp: options.maxTimestamp,
|
|
261
|
+
revertingTxHashes: options.revertingTxHashes,
|
|
262
|
+
noMerge: options.noMerge,
|
|
263
|
+
});
|
|
264
|
+
// 提取交易哈希
|
|
265
|
+
const txHashes = options.transactions.map(rawTx => {
|
|
266
|
+
try {
|
|
267
|
+
return Transaction.from(rawTx).hash || '';
|
|
268
|
+
}
|
|
269
|
+
catch {
|
|
270
|
+
return '';
|
|
271
|
+
}
|
|
272
|
+
});
|
|
273
|
+
return {
|
|
274
|
+
bundleHash,
|
|
275
|
+
txHashes,
|
|
276
|
+
maxBlockNumber,
|
|
277
|
+
txCount: options.transactions.length,
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
catch (error) {
|
|
281
|
+
lastError = error;
|
|
282
|
+
if (autoRetry && attempt < maxRetries) {
|
|
283
|
+
attempt++;
|
|
284
|
+
console.log(`🔄 [BlockRazor] 重试 ${attempt}/${maxRetries}...`);
|
|
285
|
+
await new Promise(resolve => setTimeout(resolve, 3000)); // 等待一个区块
|
|
286
|
+
continue;
|
|
287
|
+
}
|
|
288
|
+
throw error;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
throw lastError || new Error('Bundle submission failed after all retries');
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* 发送带激励的 Bundle(自动添加激励交易)
|
|
295
|
+
*
|
|
296
|
+
* @param options 发送选项
|
|
297
|
+
* @param incentive 激励参数
|
|
298
|
+
* @returns Bundle 结果
|
|
299
|
+
*/
|
|
300
|
+
async sendBundleWithIncentive(options, incentive) {
|
|
301
|
+
// 获取激励钱包的 nonce
|
|
302
|
+
const nonce = await this.provider.getTransactionCount(incentive.wallet.address, 'latest');
|
|
303
|
+
// 构建激励交易(放在 Bundle 最后)
|
|
304
|
+
const incentiveTx = await this.buildIncentiveTransaction({
|
|
305
|
+
wallet: incentive.wallet,
|
|
306
|
+
amount: incentive.amount,
|
|
307
|
+
nonce: nonce,
|
|
308
|
+
});
|
|
309
|
+
// 将激励交易添加到 Bundle 末尾
|
|
310
|
+
const allTransactions = [...options.transactions, incentiveTx];
|
|
311
|
+
console.log(`💰 [BlockRazor] 添加激励交易: ${incentive.amount} BNB -> ${BLOCKRAZOR_BUILDER_EOA}`);
|
|
312
|
+
return await this.sendBundle({
|
|
313
|
+
...options,
|
|
314
|
+
transactions: allTransactions,
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* 等待 Bundle 中的交易确认
|
|
319
|
+
*
|
|
320
|
+
* @param txHashes 交易哈希列表
|
|
321
|
+
* @param confirmations 确认数(默认 1)
|
|
322
|
+
* @param timeout 超时时间(毫秒,默认 120000)
|
|
323
|
+
* @returns 交易结果列表
|
|
324
|
+
*/
|
|
325
|
+
async waitForBundleConfirmation(txHashes, confirmations = 1, timeout = 120000) {
|
|
326
|
+
const promises = txHashes.map(async (hash, index) => {
|
|
327
|
+
try {
|
|
328
|
+
const receipt = await this.provider.waitForTransaction(hash, confirmations, timeout);
|
|
329
|
+
if (!receipt) {
|
|
330
|
+
return {
|
|
331
|
+
index,
|
|
332
|
+
hash,
|
|
333
|
+
success: false,
|
|
334
|
+
error: 'Transaction not found',
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
let gasCost;
|
|
338
|
+
if (receipt.gasUsed && receipt.gasPrice) {
|
|
339
|
+
const costWei = receipt.gasUsed * receipt.gasPrice;
|
|
340
|
+
const costBnb = Number(costWei) / 1e18;
|
|
341
|
+
gasCost = costBnb.toFixed(8);
|
|
342
|
+
}
|
|
343
|
+
return {
|
|
344
|
+
index,
|
|
345
|
+
hash,
|
|
346
|
+
success: receipt.status === 1,
|
|
347
|
+
blockNumber: receipt.blockNumber,
|
|
348
|
+
gasUsed: receipt.gasUsed.toString(),
|
|
349
|
+
effectiveGasPrice: receipt.gasPrice?.toString(),
|
|
350
|
+
gasCost,
|
|
351
|
+
};
|
|
352
|
+
}
|
|
353
|
+
catch (error) {
|
|
354
|
+
return {
|
|
355
|
+
index,
|
|
356
|
+
hash,
|
|
357
|
+
success: false,
|
|
358
|
+
error: error.message,
|
|
359
|
+
};
|
|
360
|
+
}
|
|
361
|
+
});
|
|
362
|
+
return await Promise.all(promises);
|
|
363
|
+
}
|
|
364
|
+
/**
|
|
365
|
+
* 签名交易批次
|
|
366
|
+
*
|
|
367
|
+
* @param wallet 钱包
|
|
368
|
+
* @param transactions 交易列表
|
|
369
|
+
* @param options 可选参数
|
|
370
|
+
* @returns 已签名的交易数组
|
|
371
|
+
*/
|
|
372
|
+
async signTransactions(wallet, transactions, options) {
|
|
373
|
+
if (!transactions || transactions.length === 0) {
|
|
374
|
+
throw new Error('Transactions array cannot be empty');
|
|
375
|
+
}
|
|
376
|
+
// 获取 nonce
|
|
377
|
+
let nonce = options?.startNonce;
|
|
378
|
+
if (nonce === undefined) {
|
|
379
|
+
nonce = await this.provider.getTransactionCount(wallet.address, 'latest');
|
|
380
|
+
}
|
|
381
|
+
// 获取 Gas Price(确保不低于最低要求)
|
|
382
|
+
let gasPrice = options?.gasPrice;
|
|
383
|
+
if (!gasPrice) {
|
|
384
|
+
const feeData = await this.provider.getFeeData();
|
|
385
|
+
const baseGasPrice = feeData.gasPrice || ethers.parseUnits(String(MIN_GAS_PRICE_GWEI), 'gwei');
|
|
386
|
+
const multiplier = options?.gasPriceMultiplier || 50;
|
|
387
|
+
gasPrice = (baseGasPrice * BigInt(100 + multiplier)) / 100n;
|
|
388
|
+
// 确保不低于最低要求
|
|
389
|
+
const minGasPrice = ethers.parseUnits(String(MIN_GAS_PRICE_GWEI), 'gwei');
|
|
390
|
+
if (gasPrice < minGasPrice) {
|
|
391
|
+
gasPrice = minGasPrice;
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
// 并行签名所有交易
|
|
395
|
+
const signedTxs = await Promise.all(transactions.map(async (tx, i) => {
|
|
396
|
+
const fullTx = {
|
|
397
|
+
...tx,
|
|
398
|
+
nonce: nonce + i,
|
|
399
|
+
gasPrice,
|
|
400
|
+
chainId: this.chainId,
|
|
401
|
+
};
|
|
402
|
+
return await wallet.signTransaction(fullTx);
|
|
403
|
+
}));
|
|
404
|
+
return signedTxs;
|
|
405
|
+
}
|
|
406
|
+
/**
|
|
407
|
+
* 检查交易是否已包含在区块中
|
|
408
|
+
*/
|
|
409
|
+
async isTransactionIncluded(txHash) {
|
|
410
|
+
try {
|
|
411
|
+
const receipt = await this.provider.getTransactionReceipt(txHash);
|
|
412
|
+
return receipt !== null && receipt.blockNumber !== null;
|
|
413
|
+
}
|
|
414
|
+
catch {
|
|
415
|
+
return false;
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
/**
|
|
419
|
+
* 获取客户端信息
|
|
420
|
+
*/
|
|
421
|
+
getClientInfo() {
|
|
422
|
+
return {
|
|
423
|
+
chainId: this.chainId,
|
|
424
|
+
builderEOA: BLOCKRAZOR_BUILDER_EOA,
|
|
425
|
+
minGasPriceGwei: MIN_GAS_PRICE_GWEI,
|
|
426
|
+
};
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
BlockRazorClient.BLOCK_CACHE_TTL_MS = 1000; // 1秒缓存
|
|
430
|
+
/**
|
|
431
|
+
* 创建 BlockRazor 客户端的便捷函数
|
|
432
|
+
*/
|
|
433
|
+
export function createBlockRazorClient(apiKey) {
|
|
434
|
+
return new BlockRazorClient({ apiKey, chainId: 56 });
|
|
435
|
+
}
|
|
@@ -9,6 +9,6 @@ export { fourPrivateBuyMerkle, fourPrivateSellMerkle, fourBatchPrivateBuyMerkle,
|
|
|
9
9
|
export { disperseWithBundleMerkle, sweepWithBundleMerkle } from './utils.js';
|
|
10
10
|
export { fourPancakeProxyBatchBuyMerkle, fourPancakeProxyBatchSellMerkle, approveFourPancakeProxy, approveFourPancakeProxyBatch } from './pancake-proxy.js';
|
|
11
11
|
export { approveFourTokenManagerBatch, type ApproveFourTokenManagerBatchParams, type ApproveFourTokenManagerBatchResult } from './approve-tokenmanager.js';
|
|
12
|
-
export { submitBundleToMerkle, submitMultipleBundles, submitMultipleBundlesParallel, type MerkleSubmitConfig, type SubmitBundleResult, submitDirectToRpc, submitDirectToRpcSequential, // ✅ 新增:顺序广播并等待确认(用于多跳)
|
|
12
|
+
export { submitBundleToMerkle, submitMultipleBundles, submitMultipleBundlesParallel, type MerkleSubmitConfig, type SubmitBundleResult, submitBundleToBlockRazor, submitMultipleBundlesToBlockRazor, submitMultipleBundlesToBlockRazorParallel, type BlockRazorSubmitConfig, type BlockRazorSubmitResult, submitDirectToRpc, submitDirectToRpcSequential, // ✅ 新增:顺序广播并等待确认(用于多跳)
|
|
13
13
|
submitDirectToRpcParallel, type DirectSubmitConfig, type DirectSubmitResult, type DirectTxResult } from './submit.js';
|
|
14
14
|
export { fourBundleBuyFirstMerkle, type FourBundleBuyFirstSignParams, type FourBuyFirstSignConfig, type FourBuyFirstResult } from './swap-buy-first.js';
|
|
@@ -16,7 +16,11 @@ export { fourPancakeProxyBatchBuyMerkle, fourPancakeProxyBatchSellMerkle, approv
|
|
|
16
16
|
// TokenManager 授权方法
|
|
17
17
|
export { approveFourTokenManagerBatch } from './approve-tokenmanager.js';
|
|
18
18
|
// Bundle提交方法(服务器端使用)
|
|
19
|
-
export {
|
|
19
|
+
export {
|
|
20
|
+
// Merkle 提交方法
|
|
21
|
+
submitBundleToMerkle, submitMultipleBundles, submitMultipleBundlesParallel,
|
|
22
|
+
// ✅ BlockRazor 提交方法
|
|
23
|
+
submitBundleToBlockRazor, submitMultipleBundlesToBlockRazor, submitMultipleBundlesToBlockRazorParallel,
|
|
20
24
|
// ✅ Monad 等链的逐笔广播方法
|
|
21
25
|
submitDirectToRpc, submitDirectToRpcSequential, // ✅ 新增:顺序广播并等待确认(用于多跳)
|
|
22
26
|
submitDirectToRpcParallel } from './submit.js';
|
|
@@ -9,7 +9,7 @@ const MULTICALL3_ABI = [
|
|
|
9
9
|
];
|
|
10
10
|
// 常量
|
|
11
11
|
const WBNB_ADDRESS = '0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c';
|
|
12
|
-
const FLAT_FEE =
|
|
12
|
+
const FLAT_FEE = 0n; // ✅ 已移除合约固定手续费
|
|
13
13
|
const DEFAULT_GAS_LIMIT = 800000; // ✅ 改为 number,配合 getGasLimit 使用
|
|
14
14
|
const DEADLINE_MINUTES = 20;
|
|
15
15
|
// PancakeSwapProxy ABI(PancakeSwap V3 没有 deadline 参数)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* 独立的Bundle提交方法
|
|
3
3
|
*
|
|
4
|
-
* 用于服务器端接收前端构建的签名交易后,提交到Merkle
|
|
4
|
+
* 用于服务器端接收前端构建的签名交易后,提交到Merkle或BlockRazor
|
|
5
5
|
* 以及 Monad 等不支持 Bundle 的链的逐笔广播
|
|
6
6
|
*/
|
|
7
7
|
/**
|
|
@@ -87,6 +87,100 @@ export declare function submitMultipleBundles(bundles: string[][], config: Merkl
|
|
|
87
87
|
* @returns Bundle提交结果数组
|
|
88
88
|
*/
|
|
89
89
|
export declare function submitMultipleBundlesParallel(bundles: string[][], config: MerkleSubmitConfig): Promise<SubmitBundleResult[]>;
|
|
90
|
+
/**
|
|
91
|
+
* BlockRazor 提交配置
|
|
92
|
+
* 参考: https://blockrazor.gitbook.io/blockrazor/bsc/block-builder/send-bundle
|
|
93
|
+
*/
|
|
94
|
+
export interface BlockRazorSubmitConfig {
|
|
95
|
+
/** API Key(可选,根据 Tier 需要) */
|
|
96
|
+
apiKey?: string;
|
|
97
|
+
/** 自定义 RPC URL(用于查询区块号等,可选) */
|
|
98
|
+
customRpcUrl?: string;
|
|
99
|
+
/** Builder RPC URL(用于发送 Bundle,可选) */
|
|
100
|
+
builderRpcUrl?: string;
|
|
101
|
+
/** 区块偏移量(默认 10,最大有效区块 = 当前区块 + offset) */
|
|
102
|
+
blockOffset?: number;
|
|
103
|
+
/** 最大区块偏移量(默认 100) */
|
|
104
|
+
maxBlockOffset?: number;
|
|
105
|
+
/** 是否禁止 Bundle 合并(默认 false,允许合并可提高打包率) */
|
|
106
|
+
noMerge?: boolean;
|
|
107
|
+
/** 允许 revert 的交易哈希列表 */
|
|
108
|
+
revertingTxHashes?: string[];
|
|
109
|
+
/** 是否自动重试(默认 false) */
|
|
110
|
+
autoRetry?: boolean;
|
|
111
|
+
/** 最大重试次数(默认 3) */
|
|
112
|
+
maxRetries?: number;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* BlockRazor Bundle 提交结果
|
|
116
|
+
*/
|
|
117
|
+
export interface BlockRazorSubmitResult {
|
|
118
|
+
/** 提交状态:true=成功,false=失败 */
|
|
119
|
+
code: boolean;
|
|
120
|
+
/** 交易总数 */
|
|
121
|
+
totalTransactions: number;
|
|
122
|
+
/** Bundle 哈希(成功时返回) */
|
|
123
|
+
bundleHash?: string;
|
|
124
|
+
/** 交易哈希列表(成功时返回) */
|
|
125
|
+
txHashes?: string[];
|
|
126
|
+
/** 最大有效区块号(成功时返回) */
|
|
127
|
+
maxBlockNumber?: number;
|
|
128
|
+
/** 交易数量(成功时返回) */
|
|
129
|
+
txCount?: number;
|
|
130
|
+
/** 错误信息(失败时返回) */
|
|
131
|
+
error?: string;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* 提交已签名的交易到 BlockRazor(服务器端使用)
|
|
135
|
+
*
|
|
136
|
+
* BlockRazor 是 BSC 链的 Block Builder 服务,支持 Bundle 提交
|
|
137
|
+
*
|
|
138
|
+
* 特点:
|
|
139
|
+
* - 向 Builder EOA 转账 BNB 可提高优先级
|
|
140
|
+
* - 支持 Bundle 合并提高打包率
|
|
141
|
+
* - 最低 Gas Price 要求: 0.05 Gwei
|
|
142
|
+
*
|
|
143
|
+
* @param signedTransactions 签名后的交易数组
|
|
144
|
+
* @param config BlockRazor 提交配置
|
|
145
|
+
* @returns Bundle 提交结果
|
|
146
|
+
*
|
|
147
|
+
* @example
|
|
148
|
+
* ```typescript
|
|
149
|
+
* // 服务器端代码
|
|
150
|
+
* import { submitBundleToBlockRazor } from 'four-flap-meme-sdk';
|
|
151
|
+
*
|
|
152
|
+
* const result = await submitBundleToBlockRazor(signedTransactions, {
|
|
153
|
+
* blockOffset: 10,
|
|
154
|
+
* noMerge: false, // 允许合并
|
|
155
|
+
* autoRetry: true
|
|
156
|
+
* });
|
|
157
|
+
*
|
|
158
|
+
* if (result.code) {
|
|
159
|
+
* console.log('✅ Bundle 提交成功:', result.bundleHash);
|
|
160
|
+
* console.log('交易哈希:', result.txHashes);
|
|
161
|
+
* console.log('最大有效区块:', result.maxBlockNumber);
|
|
162
|
+
* } else {
|
|
163
|
+
* console.error('❌ Bundle 提交失败:', result.error);
|
|
164
|
+
* }
|
|
165
|
+
* ```
|
|
166
|
+
*/
|
|
167
|
+
export declare function submitBundleToBlockRazor(signedTransactions: string[], config: BlockRazorSubmitConfig): Promise<BlockRazorSubmitResult>;
|
|
168
|
+
/**
|
|
169
|
+
* 批量提交多个 Bundle 到 BlockRazor(顺序执行)
|
|
170
|
+
*
|
|
171
|
+
* @param bundles 多个 Bundle 的签名交易数组
|
|
172
|
+
* @param config BlockRazor 提交配置
|
|
173
|
+
* @returns Bundle 提交结果数组
|
|
174
|
+
*/
|
|
175
|
+
export declare function submitMultipleBundlesToBlockRazor(bundles: string[][], config: BlockRazorSubmitConfig): Promise<BlockRazorSubmitResult[]>;
|
|
176
|
+
/**
|
|
177
|
+
* 并行提交多个 Bundle 到 BlockRazor(适用于独立的 Bundle)
|
|
178
|
+
*
|
|
179
|
+
* @param bundles 多个 Bundle 的签名交易数组
|
|
180
|
+
* @param config BlockRazor 提交配置
|
|
181
|
+
* @returns Bundle 提交结果数组
|
|
182
|
+
*/
|
|
183
|
+
export declare function submitMultipleBundlesToBlockRazorParallel(bundles: string[][], config: BlockRazorSubmitConfig): Promise<BlockRazorSubmitResult[]>;
|
|
90
184
|
/**
|
|
91
185
|
* 逐笔广播配置(用于不支持 Bundle 的链,如 Monad)
|
|
92
186
|
*/
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* 独立的Bundle提交方法
|
|
3
3
|
*
|
|
4
|
-
* 用于服务器端接收前端构建的签名交易后,提交到Merkle
|
|
4
|
+
* 用于服务器端接收前端构建的签名交易后,提交到Merkle或BlockRazor
|
|
5
5
|
* 以及 Monad 等不支持 Bundle 的链的逐笔广播
|
|
6
6
|
*/
|
|
7
7
|
import { MerkleClient } from '../../clients/merkle.js';
|
|
8
|
+
import { BlockRazorClient } from '../../clients/blockrazor.js';
|
|
8
9
|
import { ethers } from 'ethers';
|
|
9
10
|
// ✅ MerkleClient 缓存(复用连接,减少初始化开销)
|
|
10
11
|
const merkleClientCache = new Map();
|
|
@@ -129,6 +130,134 @@ export async function submitMultipleBundlesParallel(bundles, config) {
|
|
|
129
130
|
const promises = bundles.map(signedTransactions => submitBundleToMerkle(signedTransactions, config));
|
|
130
131
|
return await Promise.all(promises);
|
|
131
132
|
}
|
|
133
|
+
// ==================== BlockRazor Bundle 提交方法 ====================
|
|
134
|
+
// ✅ BlockRazorClient 缓存(复用连接,减少初始化开销)
|
|
135
|
+
const blockRazorClientCache = new Map();
|
|
136
|
+
/**
|
|
137
|
+
* 获取或创建 BlockRazorClient(带缓存)
|
|
138
|
+
*/
|
|
139
|
+
function getBlockRazorClient(config) {
|
|
140
|
+
const cacheKey = `${config.apiKey || 'default'}-${config.customRpcUrl || ''}-${config.builderRpcUrl || ''}`;
|
|
141
|
+
const now = Date.now();
|
|
142
|
+
const cached = blockRazorClientCache.get(cacheKey);
|
|
143
|
+
if (cached && cached.expireAt > now) {
|
|
144
|
+
return cached.client;
|
|
145
|
+
}
|
|
146
|
+
// 创建新客户端并缓存
|
|
147
|
+
const client = new BlockRazorClient({
|
|
148
|
+
apiKey: config.apiKey,
|
|
149
|
+
chainId: 56, // BlockRazor 目前只支持 BSC
|
|
150
|
+
customRpcUrl: config.customRpcUrl,
|
|
151
|
+
builderRpcUrl: config.builderRpcUrl
|
|
152
|
+
});
|
|
153
|
+
blockRazorClientCache.set(cacheKey, { client, expireAt: now + CLIENT_CACHE_TTL_MS });
|
|
154
|
+
return client;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* 提交已签名的交易到 BlockRazor(服务器端使用)
|
|
158
|
+
*
|
|
159
|
+
* BlockRazor 是 BSC 链的 Block Builder 服务,支持 Bundle 提交
|
|
160
|
+
*
|
|
161
|
+
* 特点:
|
|
162
|
+
* - 向 Builder EOA 转账 BNB 可提高优先级
|
|
163
|
+
* - 支持 Bundle 合并提高打包率
|
|
164
|
+
* - 最低 Gas Price 要求: 0.05 Gwei
|
|
165
|
+
*
|
|
166
|
+
* @param signedTransactions 签名后的交易数组
|
|
167
|
+
* @param config BlockRazor 提交配置
|
|
168
|
+
* @returns Bundle 提交结果
|
|
169
|
+
*
|
|
170
|
+
* @example
|
|
171
|
+
* ```typescript
|
|
172
|
+
* // 服务器端代码
|
|
173
|
+
* import { submitBundleToBlockRazor } from 'four-flap-meme-sdk';
|
|
174
|
+
*
|
|
175
|
+
* const result = await submitBundleToBlockRazor(signedTransactions, {
|
|
176
|
+
* blockOffset: 10,
|
|
177
|
+
* noMerge: false, // 允许合并
|
|
178
|
+
* autoRetry: true
|
|
179
|
+
* });
|
|
180
|
+
*
|
|
181
|
+
* if (result.code) {
|
|
182
|
+
* console.log('✅ Bundle 提交成功:', result.bundleHash);
|
|
183
|
+
* console.log('交易哈希:', result.txHashes);
|
|
184
|
+
* console.log('最大有效区块:', result.maxBlockNumber);
|
|
185
|
+
* } else {
|
|
186
|
+
* console.error('❌ Bundle 提交失败:', result.error);
|
|
187
|
+
* }
|
|
188
|
+
* ```
|
|
189
|
+
*/
|
|
190
|
+
export async function submitBundleToBlockRazor(signedTransactions, config) {
|
|
191
|
+
try {
|
|
192
|
+
const totalTransactions = signedTransactions?.length ?? 0;
|
|
193
|
+
// 验证输入
|
|
194
|
+
if (!signedTransactions || signedTransactions.length === 0) {
|
|
195
|
+
return {
|
|
196
|
+
code: false,
|
|
197
|
+
totalTransactions,
|
|
198
|
+
error: 'signedTransactions cannot be empty'
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
// ✅ 使用缓存的 BlockRazorClient
|
|
202
|
+
const client = getBlockRazorClient(config);
|
|
203
|
+
console.log(`📦 [BlockRazor] 提交 ${totalTransactions} 笔交易...`);
|
|
204
|
+
// 提交 Bundle
|
|
205
|
+
const bundleResult = await client.sendBundle({
|
|
206
|
+
transactions: signedTransactions,
|
|
207
|
+
blockOffset: config.blockOffset ?? 100,
|
|
208
|
+
maxBlockOffset: config.maxBlockOffset ?? 100,
|
|
209
|
+
noMerge: config.noMerge ?? false,
|
|
210
|
+
revertingTxHashes: config.revertingTxHashes,
|
|
211
|
+
autoRetry: config.autoRetry ?? false,
|
|
212
|
+
maxRetries: config.maxRetries ?? 3
|
|
213
|
+
});
|
|
214
|
+
console.log(`✅ [BlockRazor] 提交成功: ${bundleResult.bundleHash}`);
|
|
215
|
+
// ✅ 提交成功
|
|
216
|
+
return {
|
|
217
|
+
code: true,
|
|
218
|
+
totalTransactions,
|
|
219
|
+
bundleHash: bundleResult.bundleHash,
|
|
220
|
+
txHashes: bundleResult.txHashes,
|
|
221
|
+
maxBlockNumber: bundleResult.maxBlockNumber,
|
|
222
|
+
txCount: bundleResult.txCount
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
catch (error) {
|
|
226
|
+
console.error(`❌ [BlockRazor] 提交失败:`, error?.message || error);
|
|
227
|
+
// ❌ 提交失败
|
|
228
|
+
return {
|
|
229
|
+
code: false,
|
|
230
|
+
totalTransactions: signedTransactions?.length ?? 0,
|
|
231
|
+
error: error?.message || String(error)
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* 批量提交多个 Bundle 到 BlockRazor(顺序执行)
|
|
237
|
+
*
|
|
238
|
+
* @param bundles 多个 Bundle 的签名交易数组
|
|
239
|
+
* @param config BlockRazor 提交配置
|
|
240
|
+
* @returns Bundle 提交结果数组
|
|
241
|
+
*/
|
|
242
|
+
export async function submitMultipleBundlesToBlockRazor(bundles, config) {
|
|
243
|
+
const results = [];
|
|
244
|
+
for (const signedTransactions of bundles) {
|
|
245
|
+
const result = await submitBundleToBlockRazor(signedTransactions, config);
|
|
246
|
+
results.push(result);
|
|
247
|
+
}
|
|
248
|
+
return results;
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* 并行提交多个 Bundle 到 BlockRazor(适用于独立的 Bundle)
|
|
252
|
+
*
|
|
253
|
+
* @param bundles 多个 Bundle 的签名交易数组
|
|
254
|
+
* @param config BlockRazor 提交配置
|
|
255
|
+
* @returns Bundle 提交结果数组
|
|
256
|
+
*/
|
|
257
|
+
export async function submitMultipleBundlesToBlockRazorParallel(bundles, config) {
|
|
258
|
+
const promises = bundles.map(signedTransactions => submitBundleToBlockRazor(signedTransactions, config));
|
|
259
|
+
return await Promise.all(promises);
|
|
260
|
+
}
|
|
132
261
|
/**
|
|
133
262
|
* 逐笔广播到 RPC(用于不支持 Bundle 的链,如 Monad)
|
|
134
263
|
*
|
|
@@ -10,7 +10,7 @@ const MULTICALL3_ABI = [
|
|
|
10
10
|
// 常量
|
|
11
11
|
const WBNB_ADDRESS = '0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c';
|
|
12
12
|
const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000';
|
|
13
|
-
const FLAT_FEE =
|
|
13
|
+
const FLAT_FEE = 0n; // ✅ 已移除合约固定手续费
|
|
14
14
|
const DEFAULT_GAS_LIMIT = 800000; // ✅ 改为 number,配合 getGasLimit 使用
|
|
15
15
|
const DEADLINE_MINUTES = 20;
|
|
16
16
|
// PancakeSwapProxy ABI(PancakeSwap V3 没有 deadline 参数)
|
package/dist/index.d.ts
CHANGED
|
@@ -20,13 +20,14 @@ export { getFlapMetaByAddress, getFlapMetasByAddresses } from './flap/meta.js';
|
|
|
20
20
|
export { createTokenFlow, type CreateTokenFlowInput, type CreateTokenFlowOutput } from './flows/create.js';
|
|
21
21
|
export { Club48Client, sendBatchPrivateTransactions, sendBackrunBundle, type BundleParams, type BundleStatus, type Club48Config } from './clients/club48.js';
|
|
22
22
|
export { MerkleClient, createMerkleClient, type MerkleConfig, type BundleParams as MerkleBundleParams, type SendBundleOptions, type BundleResult, type TransactionResult } from './clients/merkle.js';
|
|
23
|
+
export { BlockRazorClient, createBlockRazorClient, BLOCKRAZOR_BUILDER_EOA, type BlockRazorConfig, type BlockRazorBundleParams, type SendBundleOptions as BlockRazorSendBundleOptions, type BundleResult as BlockRazorBundleResult, type TransactionResult as BlockRazorTransactionResult, type IncentiveTransactionParams } from './clients/blockrazor.js';
|
|
23
24
|
export { NonceManager, getOptimizedGasPrice, estimateGasWithSafety, estimateGasBatch, buildTransaction, signTransactionsBatch, signTransactionsBatchMultiWallet, validateSignedTransactions, type GasPriceConfig, type GasEstimateConfig, type BuildTransactionOptions } from './utils/bundle-helpers.js';
|
|
24
25
|
export { createTokenWithBundleBuy as fourCreateTokenWithBundleBuy, batchBuyWithBundle as fourBatchBuyWithBundle, batchSellWithBundle as fourBatchSellWithBundle, type FourBundleConfig, type FourCreateWithBundleBuyParams, type FourCreateWithBundleBuyResult, type FourBatchBuyParams, type FourBatchBuyResult, type FourBatchSellParams, type FourBatchSellResult } from './contracts/tm-bundle.js';
|
|
25
26
|
export { createTokenWithBundleBuy as flapCreateTokenWithBundleBuy, batchBuyWithBundle as flapBatchBuyWithBundle, batchSellWithBundle as flapBatchSellWithBundle, type FlapBundleConfig, type FlapChainForBundle, type FlapCreateWithBundleBuyParams, type FlapCreateWithBundleBuyResult, type FlapBatchBuyParams, type FlapBatchBuyResult, type FlapBatchSellParams, type FlapBatchSellResult } from './flap/portal-bundle.js';
|
|
26
27
|
export { fourPrivateBuy, fourPrivateSell, fourBatchPrivateBuy, fourBatchPrivateSell, type FourPrivateBuyParams, type FourPrivateSellParams, type FourBatchPrivateBuyParams, type FourBatchPrivateSellParams } from './contracts/tm-bundle.js';
|
|
27
28
|
export { flapPrivateBuy, flapPrivateSell, flapBatchPrivateBuy, flapBatchPrivateSell, type FlapPrivateBuyParams, type FlapPrivateSellParams, type FlapBatchPrivateBuyParams, type FlapBatchPrivateSellParams, type FlapBatchPrivateSellResult } from './flap/portal-bundle.js';
|
|
28
29
|
export { createTokenWithBundleBuyMerkle as flapCreateTokenWithBundleBuyMerkle, batchBuyWithBundleMerkle as flapBatchBuyWithBundleMerkle, batchSellWithBundleMerkle as flapBatchSellWithBundleMerkle, flapPrivateBuyMerkle, flapPrivateSellMerkle, flapBatchPrivateBuyMerkle, flapBatchPrivateSellMerkle, pancakeProxyBatchBuyMerkle, pancakeProxyBatchSellMerkle, approvePancakeProxy, approvePancakeProxyBatch, flapDisperseWithBundleMerkle, flapSweepWithBundleMerkle, type FlapBundleMerkleConfig, type FlapSignConfig, type FlapChainForMerkleBundle, type FlapCreateWithBundleBuySignParams, type FlapCreateWithBundleBuyMerkleParams, type FlapCreateWithBundleBuyMerkleResult, type FlapBatchBuySignParams, type FlapBatchBuyMerkleParams, type FlapBatchBuyMerkleResult, type FlapBatchSellSignParams, type FlapBatchSellMerkleParams, type FlapBatchSellMerkleResult, type MerkleTransactionStatus, type MerkleBundleStatus, type FlapPrivateBuyMerkleParams, type FlapPrivateSellMerkleParams, type FlapBatchPrivateBuyMerkleParams, type FlapBatchPrivateSellMerkleParams, type FlapBatchPrivateMerkleResult, type FlapPrivateTransactionResult, type PancakeProxyBatchBuyParams, type PancakeProxyBatchBuyResult, type PancakeProxyBatchSellParams, type PancakeProxyBatchSellResult, type PancakeProxyApprovalParams, type PancakeProxyApprovalBatchParams, type PancakeProxyApprovalBatchResult, type FlapDisperseSignParams, type FlapDisperseMerkleResult, type FlapSweepSignParams, type FlapSweepMerkleResult } from './flap/portal-bundle-merkle/index.js';
|
|
29
|
-
export { createTokenWithBundleBuyMerkle as fourCreateTokenWithBundleBuyMerkle, batchBuyWithBundleMerkle as fourBatchBuyWithBundleMerkle, batchSellWithBundleMerkle as fourBatchSellWithBundleMerkle, fourPrivateBuyMerkle, fourPrivateSellMerkle, fourBatchPrivateBuyMerkle, fourBatchPrivateSellMerkle, disperseWithBundleMerkle, sweepWithBundleMerkle, fourPancakeProxyBatchBuyMerkle, fourPancakeProxyBatchSellMerkle, approveFourPancakeProxy, approveFourPancakeProxyBatch, approveFourTokenManagerBatch, submitBundleToMerkle, submitMultipleBundles, submitMultipleBundlesParallel, type MerkleSubmitConfig, type SubmitBundleResult, type FourBundleMerkleConfig, type FourSignConfig, type FourCreateWithBundleBuySignParams, type FourBatchBuySignParams, type FourBatchSellSignParams, type FourPrivateBuySignParams, type FourPrivateSellSignParams, type FourBatchPrivateBuySignParams, type FourBatchPrivateSellSignParams, type FourPancakeProxyBatchBuySignParams, type FourPancakeProxyBatchSellSignParams, type DisperseSignParams as FourDisperseSignParams, type SweepSignParams as FourSweepSignParams, type FourCreateWithBundleBuyMerkleParams, type FourCreateWithBundleBuyMerkleResult, type FourBatchBuyMerkleParams, type FourBatchBuyMerkleResult, type FourBatchSellMerkleParams, type FourBatchSellMerkleResult, type FourPrivateBuyMerkleParams, type FourPrivateSellMerkleParams, type FourBatchPrivateBuyMerkleParams, type FourBatchPrivateSellMerkleParams, type FourBatchPrivateMerkleResult, type FourPrivateTransactionResult, type DisperseMerkleParams, type DisperseMerkleResult, type SweepMerkleParams, type SweepMerkleResult, type FourPancakeProxyBatchBuyParams, type FourPancakeProxyBatchBuyResult, type FourPancakeProxyBatchSellParams, type FourPancakeProxyBatchSellResult, type FourPancakeProxyApprovalParams, type FourPancakeProxyApprovalBatchParams, type FourPancakeProxyApprovalBatchResult, type ApproveFourTokenManagerBatchParams, type ApproveFourTokenManagerBatchResult } from './contracts/tm-bundle-merkle/index.js';
|
|
30
|
+
export { createTokenWithBundleBuyMerkle as fourCreateTokenWithBundleBuyMerkle, batchBuyWithBundleMerkle as fourBatchBuyWithBundleMerkle, batchSellWithBundleMerkle as fourBatchSellWithBundleMerkle, fourPrivateBuyMerkle, fourPrivateSellMerkle, fourBatchPrivateBuyMerkle, fourBatchPrivateSellMerkle, disperseWithBundleMerkle, sweepWithBundleMerkle, fourPancakeProxyBatchBuyMerkle, fourPancakeProxyBatchSellMerkle, approveFourPancakeProxy, approveFourPancakeProxyBatch, approveFourTokenManagerBatch, submitBundleToMerkle, submitMultipleBundles, submitMultipleBundlesParallel, submitBundleToBlockRazor, submitMultipleBundlesToBlockRazor, submitMultipleBundlesToBlockRazorParallel, type MerkleSubmitConfig, type SubmitBundleResult, type BlockRazorSubmitConfig, type BlockRazorSubmitResult, type FourBundleMerkleConfig, type FourSignConfig, type FourCreateWithBundleBuySignParams, type FourBatchBuySignParams, type FourBatchSellSignParams, type FourPrivateBuySignParams, type FourPrivateSellSignParams, type FourBatchPrivateBuySignParams, type FourBatchPrivateSellSignParams, type FourPancakeProxyBatchBuySignParams, type FourPancakeProxyBatchSellSignParams, type DisperseSignParams as FourDisperseSignParams, type SweepSignParams as FourSweepSignParams, type FourCreateWithBundleBuyMerkleParams, type FourCreateWithBundleBuyMerkleResult, type FourBatchBuyMerkleParams, type FourBatchBuyMerkleResult, type FourBatchSellMerkleParams, type FourBatchSellMerkleResult, type FourPrivateBuyMerkleParams, type FourPrivateSellMerkleParams, type FourBatchPrivateBuyMerkleParams, type FourBatchPrivateSellMerkleParams, type FourBatchPrivateMerkleResult, type FourPrivateTransactionResult, type DisperseMerkleParams, type DisperseMerkleResult, type SweepMerkleParams, type SweepMerkleResult, type FourPancakeProxyBatchBuyParams, type FourPancakeProxyBatchBuyResult, type FourPancakeProxyBatchSellParams, type FourPancakeProxyBatchSellResult, type FourPancakeProxyApprovalParams, type FourPancakeProxyApprovalBatchParams, type FourPancakeProxyApprovalBatchResult, type ApproveFourTokenManagerBatchParams, type ApproveFourTokenManagerBatchResult } from './contracts/tm-bundle-merkle/index.js';
|
|
30
31
|
export { PinataClient, type PinataConfig } from './flap/pinata.js';
|
|
31
32
|
export { pinFileToIPFSWithJWT, pinImageByPath, pinFileToIPFSWithJWTWeb, pinDataURLWithJWTWeb, dataURLToBlob, type PinataPinResp } from './flap/pinata.js';
|
|
32
33
|
export { generateWallets, type GeneratedWallet } from './utils/wallet.js';
|
package/dist/index.js
CHANGED
|
@@ -32,13 +32,14 @@ export { getFlapMetaByAddress, getFlapMetasByAddresses } from './flap/meta.js';
|
|
|
32
32
|
export { createTokenFlow } from './flows/create.js';
|
|
33
33
|
export { Club48Client, sendBatchPrivateTransactions, sendBackrunBundle } from './clients/club48.js';
|
|
34
34
|
export { MerkleClient, createMerkleClient } from './clients/merkle.js';
|
|
35
|
+
export { BlockRazorClient, createBlockRazorClient, BLOCKRAZOR_BUILDER_EOA } from './clients/blockrazor.js';
|
|
35
36
|
export { NonceManager, getOptimizedGasPrice, estimateGasWithSafety, estimateGasBatch, buildTransaction, signTransactionsBatch, signTransactionsBatchMultiWallet, validateSignedTransactions } from './utils/bundle-helpers.js';
|
|
36
37
|
export { createTokenWithBundleBuy as fourCreateTokenWithBundleBuy, batchBuyWithBundle as fourBatchBuyWithBundle, batchSellWithBundle as fourBatchSellWithBundle } from './contracts/tm-bundle.js';
|
|
37
38
|
export { createTokenWithBundleBuy as flapCreateTokenWithBundleBuy, batchBuyWithBundle as flapBatchBuyWithBundle, batchSellWithBundle as flapBatchSellWithBundle } from './flap/portal-bundle.js';
|
|
38
39
|
export { fourPrivateBuy, fourPrivateSell, fourBatchPrivateBuy, fourBatchPrivateSell } from './contracts/tm-bundle.js';
|
|
39
40
|
export { flapPrivateBuy, flapPrivateSell, flapBatchPrivateBuy, flapBatchPrivateSell } from './flap/portal-bundle.js';
|
|
40
41
|
export { createTokenWithBundleBuyMerkle as flapCreateTokenWithBundleBuyMerkle, batchBuyWithBundleMerkle as flapBatchBuyWithBundleMerkle, batchSellWithBundleMerkle as flapBatchSellWithBundleMerkle, flapPrivateBuyMerkle, flapPrivateSellMerkle, flapBatchPrivateBuyMerkle, flapBatchPrivateSellMerkle, pancakeProxyBatchBuyMerkle, pancakeProxyBatchSellMerkle, approvePancakeProxy, approvePancakeProxyBatch, flapDisperseWithBundleMerkle, flapSweepWithBundleMerkle } from './flap/portal-bundle-merkle/index.js';
|
|
41
|
-
export { createTokenWithBundleBuyMerkle as fourCreateTokenWithBundleBuyMerkle, batchBuyWithBundleMerkle as fourBatchBuyWithBundleMerkle, batchSellWithBundleMerkle as fourBatchSellWithBundleMerkle, fourPrivateBuyMerkle, fourPrivateSellMerkle, fourBatchPrivateBuyMerkle, fourBatchPrivateSellMerkle, disperseWithBundleMerkle, sweepWithBundleMerkle, fourPancakeProxyBatchBuyMerkle, fourPancakeProxyBatchSellMerkle, approveFourPancakeProxy, approveFourPancakeProxyBatch, approveFourTokenManagerBatch, submitBundleToMerkle, submitMultipleBundles, submitMultipleBundlesParallel } from './contracts/tm-bundle-merkle/index.js';
|
|
42
|
+
export { createTokenWithBundleBuyMerkle as fourCreateTokenWithBundleBuyMerkle, batchBuyWithBundleMerkle as fourBatchBuyWithBundleMerkle, batchSellWithBundleMerkle as fourBatchSellWithBundleMerkle, fourPrivateBuyMerkle, fourPrivateSellMerkle, fourBatchPrivateBuyMerkle, fourBatchPrivateSellMerkle, disperseWithBundleMerkle, sweepWithBundleMerkle, fourPancakeProxyBatchBuyMerkle, fourPancakeProxyBatchSellMerkle, approveFourPancakeProxy, approveFourPancakeProxyBatch, approveFourTokenManagerBatch, submitBundleToMerkle, submitMultipleBundles, submitMultipleBundlesParallel, submitBundleToBlockRazor, submitMultipleBundlesToBlockRazor, submitMultipleBundlesToBlockRazorParallel } from './contracts/tm-bundle-merkle/index.js';
|
|
42
43
|
export { PinataClient } from './flap/pinata.js';
|
|
43
44
|
export { pinFileToIPFSWithJWT, pinImageByPath, pinFileToIPFSWithJWTWeb, pinDataURLWithJWTWeb, dataURLToBlob } from './flap/pinata.js';
|
|
44
45
|
export { generateWallets } from './utils/wallet.js';
|
|
@@ -47,7 +47,7 @@ const PANCAKE_V3_QUOTER_ABI = [
|
|
|
47
47
|
const PANCAKE_PROXY_ADDRESS = ADDRESSES.BSC.PancakeProxy;
|
|
48
48
|
const PANCAKE_V2_ROUTER_ADDRESS = '0x10ED43C718714eb63d5aA57B78B54704E256024E';
|
|
49
49
|
const PANCAKE_V3_QUOTER_ADDRESS = '0xB048Bbc1Ee6b733FFfCFb9e9CeF7375518e25997';
|
|
50
|
-
const FLAT_FEE =
|
|
50
|
+
const FLAT_FEE = 0n; // ✅ 已移除合约固定手续费
|
|
51
51
|
const WBNB_ADDRESS = '0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c';
|
|
52
52
|
const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000';
|
|
53
53
|
const ERC20_BALANCE_OF_ABI = ['function balanceOf(address) view returns (uint256)'];
|
|
@@ -275,7 +275,7 @@ const PANCAKE_PROXY_ADDRESS = ADDRESSES.BSC.PancakeProxy;
|
|
|
275
275
|
const PANCAKE_V2_ROUTER_ADDRESS = '0x10ED43C718714eb63d5aA57B78B54704E256024E';
|
|
276
276
|
const PANCAKE_V3_QUOTER_ADDRESS = '0xB048Bbc1Ee6b733FFfCFb9e9CeF7375518e25997';
|
|
277
277
|
// 代理合约手续费
|
|
278
|
-
const FLAT_FEE =
|
|
278
|
+
const FLAT_FEE = 0n; // ✅ 已移除合约固定手续费
|
|
279
279
|
const WBNB_ADDRESS = '0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c';
|
|
280
280
|
const ERC20_ALLOWANCE_ABI = [
|
|
281
281
|
'function allowance(address,address) view returns (uint256)',
|