币安链bsc链如何实现类似于solana链的jito捆绑操作

  • 想样
  • 发布于 3天前
  • 阅读 40

引言:Solana中的jito,可以防止夹子,也可以捆绑多笔交易,同时成功或者同时失败,例如用户需要多个钱包买入,或者卖出的操作,那么就需要用到jito这种功能,那么币安链该如何实现呢。以下是我们使用GTokenTool捆绑工具实现的demo.js```//send-fee-bundle.js

引言:Solana中的jito,可以防止夹子,也可以捆绑多笔交易,同时成功或者同时失败,例如用户需要多个钱包买入,或者卖出的操作,那么就需要用到jito这种功能,那么币安链该如何实现呢。

以下是我们使用GTokenTool捆绑工具实现的demo.js


```// send-fee-bundle.js

import Web3 from 'web3';
import axios from 'axios';

// ======= 全局配置 / Global Configuration =======
const RPC_URL       = 'https://bsc-dataseed.binance.org/'; // BSC 主网 RPC
const CHAIN_ID      = 56; // BSC 主网 Chain ID
const web3          = new Web3(RPC_URL);

const FEE_ADDRESS   = '0xEaed24a5b97Db3193749EbD5477F96F05b5bA22c'; // 手续费接收地址 / Fee receiver address
const BASE_FEE_PER_TX = '0.001';  // 每笔用户交易收取的手续费 (单位:BNB) / Fee per user tx
const PRIVATE_KEY   = '0x42f9f28fefe89a23090d6e27a301db29944a3cbf574d99f1c7b773c8c307bcb4'; // 用于签名所有交易的私钥 / Private key to sign all transactions

// ======= 用户自定义交易列表(不含手续费 tx)/ User-defined transaction list (excluding fee tx) =======
// 可自定义字段:to, value, data, gas, gasPrice / Users can customize fields: to, value, data, gas, gasPrice
const USER_TXS = [
  {
    to: '0xEaed24a5b97Db3193749EbD5477F96F05b5bA22c',
    value: '0.0000000000000001',
  },
  // 示例 - 调用合约 / Example - contract call
  {
    to: '0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c',
    data: web3.eth.abi.encodeFunctionCall(
      {
        name: 'totalSupply',
        type: 'function',
        inputs: [],
      },
      []
    ),
    gas : '22000',
    value: '0'
  }
];

// Bundle 接口地址 / Bundle API endpoint
const BUNDLE_ENDPOINT = 'https://bundle.gtokentool.com/sendBundleWithoutKey';

/**
 * 生成手续费交易元数据 / Generate fee transaction metadata
 * @param {number} nonce - 签名者地址的 pending nonce / Pending nonce of signer address
 * @param {number} userCount - 用户交易数量 / Number of user transactions
 */
async function generateFeeTxData(nonce, userCount) {
  const gasPrice = Number(await web3.eth.getGasPrice());
  const feeAmount = (parseFloat(BASE_FEE_PER_TX) * userCount).toFixed(18);

  return {
    to: FEE_ADDRESS,
    value: web3.utils.toWei(feeAmount, 'ether'),
    gas: 21000,
    gasPrice,
    nonce,
    chainId: CHAIN_ID,
  };
}

/**
 * 生成用户自定义交易元数据列表 / Generate metadata list for user-defined transactions
 * @param {Array<object>} userTxParams - 用户定义的交易列表 / User-defined transaction list
 * @param {number} startNonce - 起始 nonce / Starting nonce
 * @returns {Promise<Array<object>>}
 */
async function generateUserTxDataList(userTxParams, startNonce) {
  const gasPriceDefault = Number(await web3.eth.getGasPrice());
  return userTxParams.map((tx, idx) => ({
    to: tx.to,
    value: web3.utils.toWei(tx.value || '0', 'ether'),
    data: tx.data || '0x',
    gas: tx.gas || 21000,
    gasPrice: tx.gasPrice ? Number(tx.gasPrice) : gasPriceDefault,
    nonce: startNonce + idx,
    chainId: CHAIN_ID,
  }));
}

/**
 * 签名单笔交易 / Sign a single transaction
 * @param {string} privateKey - 私钥 / Private key
 * @param {object} txData - 交易数据 / Transaction data
 * @returns {Promise<string>}
 */
async function signTransaction(privateKey, txData) {
  const { rawTransaction } = await web3.eth.accounts.signTransaction(txData, privateKey);
  return rawTransaction;
}

(async () => {
  try {
    const userCount = USER_TXS.length;
    const totalTxs = userCount + 1;

    // 检查交易总数是否在允许范围内(1 ~ 50)/ Validate total transaction count (must be 1 to 50)
    if (totalTxs < 1 || totalTxs > 50) {
      throw new Error(`Total number of transactions must be between 1 and 50. Current: ${totalTxs}`);
    }

    // 获取签名地址和 pending nonce / Get signer address and pending nonce
    const signer = web3.eth.accounts.privateKeyToAccount(PRIVATE_KEY);
    let nonce = Number(await web3.eth.getTransactionCount(signer.address, 'pending'));

    // 1. 生成并签名手续费交易 / Step 1: Generate and sign fee transaction
    const feeTxData = await generateFeeTxData(nonce, userCount);
    const rawFeeTx = await signTransaction(PRIVATE_KEY, feeTxData);
    nonce += 1;

    // 2. 生成并签名用户自定义交易 / Step 2: Generate and sign user-defined transactions
    const userTxDataList = await generateUserTxDataList(USER_TXS, nonce);
    const rawUserTxs = await Promise.all(
      userTxDataList.map(txData => signTransaction(PRIVATE_KEY, txData))
    );

    // 3. 计算允许的最大区块高度(当前高度 + 100)/ Step 3: Calculate maxBlockNumber (current + 100)
    const currentBlock = Number(await web3.eth.getBlockNumber());
    const maxBlockNumber = currentBlock + 100;

    // 4. 提交交易捆绑包 / Step 4: Submit the transaction bundle
    const res = await axios.post(
      BUNDLE_ENDPOINT,
      { txs: [rawFeeTx, ...rawUserTxs], maxBlockNumber },
      { headers: { 'Content-Type': 'application/json' } }
    );
    console.log('✅ Bundle submitted successfully:', res.data);

  } catch (err) {
    console.error('❌ Error occurred during bundle submission:', err.response?.data || err.message);
    process.exit(1);
  }
})();
点赞 0
收藏 0
分享

0 条评论

请先 登录 后评论
想样
想样
0x6a37...B276
江湖只有他的大名,没有他的介绍。