构建捆绑包
401 字约 1 分钟
2026-01-15
一个简单的代币交换示例 (go语言)
package main
import (
"bytes"
"context"
"crypto/ecdsa"
"encoding/json"
"log"
"math/big"
"net/http"
"strings"
"time"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethclient"
)
type RPCRequest struct {
JSONRPC string `json:"jsonrpc"`
ID int `json:"id"`
Method string `json:"method"`
Params []SendBundleArgs `json:"params"`
}
type SendBundleArgs struct {
Txs []hexutil.Bytes `json:"txs"`
MaxBlockNumber uint64 `json:"maxBlockNumber"`
RevertingTxHashes []common.Hash `json:"revertingTxHashes"`
}
func main() {
rpcURL := "RPC_URL"
client, err := ethclient.Dial(rpcURL)
if err != nil {
log.Fatal(err)
}
chainId := big.NewInt(56)
ctx := context.Background()
sk, err := crypto.HexToECDSA(strings.TrimPrefix("privateKey", "0x"))
if err != nil {
return
}
pk := sk.Public()
pkECDSA, ok := pk.(*ecdsa.PublicKey)
if !ok {
log.Fatal(err)
}
from := crypto.PubkeyToAddress(*pkECDSA)
nonce, err := client.PendingNonceAt(ctx, from)
if err != nil {
log.Fatal(err)
}
gasPrice, err := client.SuggestGasPrice(ctx)
if err != nil {
log.Fatal(err)
}
wbnb := common.HexToAddress("WBNBTokenAddr")
amountInBNB := big.NewInt(0) // Send token amount : Wei
tokenOutAddr := common.HexToAddress("tokenOutAddr") // Token Address to be exchanged
amountOutMin := big.NewInt(0) // Minimum amount of tokens to receive : Wei
fee := big.NewInt(100) // Pool Fee
routerV3 := common.HexToAddress("RouterPancakeV3") // Pancake Router Address
routerABI, _ := abi.JSON(strings.NewReader("routerV3ABIJSON")) // contract ABI
deadline := big.NewInt(time.Now().Add(5 * time.Minute).Unix())
type Params struct {
TokenIn common.Address
TokenOut common.Address
Fee *big.Int
Recipient common.Address
Deadline *big.Int
AmountIn *big.Int
AmountOutMinimum *big.Int
SqrtPriceLimitX96 *big.Int
}
params := Params{
TokenIn: wbnb, TokenOut: tokenOutAddr, Fee: fee,
Recipient: from, Deadline: deadline, AmountIn: amountInBNB,
AmountOutMinimum: amountOutMin, SqrtPriceLimitX96: big.NewInt(0),
}
dataSwap, err := routerABI.Pack("exactInputSingle", params)
if err != nil {
log.Fatal(err)
}
var gasLimit uint64 = 100000
tx := types.NewTx(&types.LegacyTx{
Nonce: nonce,
To: &routerV3,
Value: amountInBNB,
Gas: gasLimit,
GasPrice: gasPrice,
Data: dataSwap,
})
signer := types.NewEIP155Signer(chainId)
signedTx, err := types.SignTx(tx, signer, sk)
if err != nil {
log.Fatal(err)
}
signedTxByte, err := signedTx.MarshalBinary()
if err != nil {
log.Fatal(err)
}
txs := make([]hexutil.Bytes, 0)
txs = append(txs, signedTxByte)
// You can also continue to add other signed transactions.
// ......
reqBody := RPCRequest{
JSONRPC: "2.0",
ID: 1,
Method: "eth_sendBundle",
Params: []SendBundleArgs{
{
Txs: txs,
// MaxBlockNumber: 74925998, // Optional
RevertingTxHashes: make([]common.Hash, 0),
},
},
}
b, _ := json.Marshal(reqBody)
httpClient := &http.Client{Timeout: 10 * time.Second}
req, err := http.NewRequest("POST", "https://bsc-eu.flashblock.trade/proxy", bytes.NewReader(b))
if err != nil {
log.Fatal(err)
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", "YOUR KEY HERE")
resp, err := httpClient.Do(req)
if err != nil {
log.Fatal(err)
}
var respBody map[string]any
if err = json.NewDecoder(resp.Body).Decode(&respBody); err != nil {
log.Fatal(err)
}
log.Printf("status=%d body=%v\n", resp.StatusCode, respBody)
_ = resp.Body.Close()
}