Commit 34b01480 authored by luxq's avatar luxq

fix bug

parent 090c2d86
# pancakeSwaper # Program for swap on pancake
This is a program for swap usdt/klko on pancake.
## How to use it?
#### 1. install golang v1.24 and make
```shell
wget https://go.dev/dl/go1.24.1.linux-amd64.tar.gz
tar zxf go1.24.1.linux-amd64.tar.gz -C /usr/local
export PATH=$PATH:/usr/local/go/bin
export GOPATH=$HOME/go
export PATH=$PATH:$GOPATH/bin
sudo apt install make
```
#### 2. clone the code and build the program
```shell
git clone https://code.wuban.net.cn/luxueqian/pancakeswaper
cd pancakeswaper
make
```
#### 2. fill in the `accounts.json` file with the accounts you want to do swap for.
The example of the `accounts.json` file is as follow:
```json
[
{
"address": "0x",
"private": "0x"
},
{
"address": "0x",
"private": "0x"
}
]
```
#### 4. change configure
There is a `config.yml`, you can change the configure in it.
```yaml
param:
# routine count.
routine: 10
# swap volume for each transaction, unit is 0.1 usdt. example: 1 is 0.1 usdt.
volume: 1
# count of transactions per user.
count: 2
# gas_price unit is Gwei.
gas_price: 1
# slippage, unit is 1/1000. example: 20 means 2.0%.
slippage: 20
# tx deadline, unit is minutes, set 0 to disable.
deadline: 20
rpc:
env: "bsc"
pool: 20
log:
level: "debug"
users: "accounts.json"
```
#### 5. run the program
After check the configure, you can run the program.
```shell
./build/bin/swapper
```
#### 6. check result
When the program is running, you can check the progress in the console.
```text
REPORT Failed/Total Finished/Total
USER 0/80 18/80
TX 0/0
0.18 Cost / 0.28 Receive
```
After the program is finished, you can check the result in the console.
```text
all done, no failed user
```
If an error occurs, you can check the error details in `detail.log`, and the accounts that failed will be recorded in the `failed.json` file.
If the issue is with the account format, please verify that the account format in the `accounts.json` file is correct. After correcting it, rerun the program.
param: param:
# routine count. # routine count.
routine: 10 routine: 10
# swap volume for each transaction, unit is usdt. # swap volume for each transaction, unit is 0.1 usdt. example: 1 is 0.1 usdt.
volume: 1 volume: 1
# count of transactions per user. # count of transactions per user.
count: 2 count: 2
......
[{"inputs":[{"internalType":"address","name":"_deployer","type":"address"},{"internalType":"address","name":"_factory","type":"address"},{"internalType":"address","name":"_WETH9","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"WETH9","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"deployer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bytes","name":"path","type":"bytes"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMinimum","type":"uint256"}],"internalType":"struct ISwapRouter.ExactInputParams","name":"params","type":"tuple"}],"name":"exactInput","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint24","name":"fee","type":"uint24"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMinimum","type":"uint256"},{"internalType":"uint160","name":"sqrtPriceLimitX96","type":"uint160"}],"internalType":"struct ISwapRouter.ExactInputSingleParams","name":"params","type":"tuple"}],"name":"exactInputSingle","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes","name":"path","type":"bytes"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"amountInMaximum","type":"uint256"}],"internalType":"struct ISwapRouter.ExactOutputParams","name":"params","type":"tuple"}],"name":"exactOutput","outputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint24","name":"fee","type":"uint24"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"amountInMaximum","type":"uint256"},{"internalType":"uint160","name":"sqrtPriceLimitX96","type":"uint160"}],"internalType":"struct ISwapRouter.ExactOutputSingleParams","name":"params","type":"tuple"}],"name":"exactOutputSingle","outputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"factory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"results","type":"bytes[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"int256","name":"amount0Delta","type":"int256"},{"internalType":"int256","name":"amount1Delta","type":"int256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"pancakeV3SwapCallback","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"refundETH","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"selfPermit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"selfPermitAllowed","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"selfPermitAllowedIfNecessary","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"selfPermitIfNecessary","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amountMinimum","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"}],"name":"sweepToken","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amountMinimum","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"feeBips","type":"uint256"},{"internalType":"address","name":"feeRecipient","type":"address"}],"name":"sweepTokenWithFee","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountMinimum","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"}],"name":"unwrapWETH9","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountMinimum","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"feeBips","type":"uint256"},{"internalType":"address","name":"feeRecipient","type":"address"}],"name":"unwrapWETH9WithFee","outputs":[],"stateMutability":"payable","type":"function"},{"stateMutability":"payable","type":"receive"}]
#!/bin/bash
# build abi.json to go package.
abigen --abi=abi.json --pkg=v3router --type=V3Router --out=contract.go
This diff is collapsed.
module code.wuban.net.cn/service/pancakeswapper module code.wuban.net.cn/service/pancakeswapper
go 1.22.8 go 1.24
require ( require (
github.com/adshao/go-binance/v2 v2.6.1 github.com/adshao/go-binance/v2 v2.6.1
......
...@@ -6,11 +6,13 @@ var ( ...@@ -6,11 +6,13 @@ var (
func init() { func init() {
allEnv["bsc"] = Env{ allEnv["bsc"] = Env{
RPC: "https://bscnode.bitheart.org", //RPC: "https://bscnode.bitheart.org",
RPC: "https://four.rpc.48.club",
USDT: "0x55d398326f99059ff775485246999027b3197955", USDT: "0x55d398326f99059ff775485246999027b3197955",
KLKO: "0x215324115417a13879f865Dc5BB651B18A781a59", // KLKO KLKO: "0x215324115417a13879f865Dc5BB651B18A781a59", // KLKO
Permit2: "0x31c2F6fcFf4F8759b3Bd5Bf0e1084A055615c768", Permit2: "0x31c2F6fcFf4F8759b3Bd5Bf0e1084A055615c768",
Router: "0x1A0A18AC4BECDDbd6389559687d1A73d8927E416", Router: "0x1b81D678ffb9C0263b24A97847620C99d213eB14",
//Router: "0x1A0A18AC4BECDDbd6389559687d1A73d8927E416",
Pool: "0xcB0AE3B8337f0Cc35563e6b9fC357F2298C0D24a", Pool: "0xcB0AE3B8337f0Cc35563e6b9fC357F2298C0D24a",
ChainId: 56, ChainId: 56,
} }
......
...@@ -5,6 +5,7 @@ import ( ...@@ -5,6 +5,7 @@ import (
"code.wuban.net.cn/service/pancakeswapper/config" "code.wuban.net.cn/service/pancakeswapper/config"
"code.wuban.net.cn/service/pancakeswapper/contracts/buildparam" "code.wuban.net.cn/service/pancakeswapper/contracts/buildparam"
"code.wuban.net.cn/service/pancakeswapper/contracts/erc20" "code.wuban.net.cn/service/pancakeswapper/contracts/erc20"
"code.wuban.net.cn/service/pancakeswapper/contracts/v3router"
"code.wuban.net.cn/service/pancakeswapper/pancake" "code.wuban.net.cn/service/pancakeswapper/pancake"
"code.wuban.net.cn/service/pancakeswapper/types" "code.wuban.net.cn/service/pancakeswapper/types"
"context" "context"
...@@ -59,7 +60,7 @@ func waitTx(client *ethclient.Client, tx *ethtypes.Transaction) *ethtypes.Receip ...@@ -59,7 +60,7 @@ func waitTx(client *ethclient.Client, tx *ethtypes.Transaction) *ethtypes.Receip
func accountApprove(client *ethclient.Client, acc *types.Account, env types.Env) error { func accountApprove(client *ethclient.Client, acc *types.Account, env types.Env) error {
cfg := config.Global cfg := config.Global
permit2 := common.HexToAddress(env.Permit2) //permit2 := common.HexToAddress(env.Permit2)
usdt, err := erc20.NewTokenContract(common.HexToAddress(env.USDT), client) usdt, err := erc20.NewTokenContract(common.HexToAddress(env.USDT), client)
if err != nil { if err != nil {
return fmt.Errorf("erc20.NewTokenContract failed: %v", err) return fmt.Errorf("erc20.NewTokenContract failed: %v", err)
...@@ -77,15 +78,15 @@ func accountApprove(client *ethclient.Client, acc *types.Account, env types.Env) ...@@ -77,15 +78,15 @@ func accountApprove(client *ethclient.Client, acc *types.Account, env types.Env)
addNewTx := func(tx *ethtypes.Transaction) { addNewTx := func(tx *ethtypes.Transaction) {
waitTx(client, tx) waitTx(client, tx)
} }
if tx, err := usdt.Approve(txopts, permit2, abi.MaxUint256); err != nil { //if tx, err := usdt.Approve(txopts, permit2, abi.MaxUint256); err != nil {
return fmt.Errorf("usdt approve permit2 failed: %v", err) // return fmt.Errorf("usdt approve permit2 failed: %v", err)
} else { //} else {
addNewTx(tx) // addNewTx(tx)
} //}
// first approve usdt to permit2. // first approve usdt to permit2.
//if tx, err := usdt.Approve(txopts, permit2, abi.MaxUint256); err != nil { //if tx, err := usdt.Approve(txopts, permit2, abi.MaxUint256); err != nil {
if tx, err := usdt.Approve(txopts, common.HexToAddress(env.Pool), abi.MaxUint256); err != nil { if tx, err := usdt.Approve(txopts, common.HexToAddress(env.Router), abi.MaxUint256); err != nil {
return fmt.Errorf("usdt approve pool failed: %v", err) return fmt.Errorf("usdt approve pool failed: %v", err)
} else { } else {
addNewTx(tx) addNewTx(tx)
...@@ -200,12 +201,12 @@ func HandlerAccountSwap(acc *types.Account, env types.Env, idx uint) { ...@@ -200,12 +201,12 @@ func HandlerAccountSwap(acc *types.Account, env types.Env, idx uint) {
return return
} }
router, err := buildparam.NewParamContract(common.HexToAddress(env.Router), client) //router, err := buildparam.NewParamContract(common.HexToAddress(env.Router), client)
if err != nil { //if err != nil {
addTofailed(acc) // addTofailed(acc)
WriteLog(fmt.Sprintf("[%s] failed: failed to create router contract: %v", acc.Address, err)) // WriteLog(fmt.Sprintf("[%s] failed: failed to create router contract: %v", acc.Address, err))
return // return
} //}
txopts := &bind.TransactOpts{ txopts := &bind.TransactOpts{
From: acc.Addr, From: acc.Addr,
...@@ -236,9 +237,12 @@ func HandlerAccountSwap(acc *types.Account, env types.Env, idx uint) { ...@@ -236,9 +237,12 @@ func HandlerAccountSwap(acc *types.Account, env types.Env, idx uint) {
} }
dec := new(big.Int).SetUint64(1000000000000000000) dec := new(big.Int).SetUint64(1000000000000000000)
fee := big.NewInt(1000) fee := big.NewInt(10000)
for i := 0; i < cfg.Param.Count; i++ { for i := 0; i < cfg.Param.Count; i++ {
in := new(big.Int).Mul(big.NewInt(cfg.Param.Volume), dec) in := new(big.Int).Mul(big.NewInt(cfg.Param.Volume), dec)
in = new(big.Int).Div(in, big.NewInt(10)) // param volume 1 is 0.1
v3r, err := v3router.NewV3Router(common.HexToAddress(env.Router), client)
// calc amountOutMin with price and slippage. // calc amountOutMin with price and slippage.
amountOutMin, err := pancake.GetAmountOutMin(client, env, in, cfg.Param.Slippage, fee) amountOutMin, err := pancake.GetAmountOutMin(client, env, in, cfg.Param.Slippage, fee)
if err != nil { if err != nil {
...@@ -262,7 +266,23 @@ func HandlerAccountSwap(acc *types.Account, env types.Env, idx uint) { ...@@ -262,7 +266,23 @@ func HandlerAccountSwap(acc *types.Account, env types.Env, idx uint) {
inputs := make([][]byte, 0) inputs := make([][]byte, 0)
inputs = append(inputs, data) inputs = append(inputs, data)
deadline := time.Now().Unix() + cfg.Param.Deadline*60 deadline := time.Now().Unix() + cfg.Param.Deadline*60
if execTx, err := router.Execute(txopts, []byte{byte(pancake.V3_SWAP_EXACT_IN)}, inputs, big.NewInt(deadline)); err != nil { //if execTx, err := router.Execute(txopts, []byte{byte(pancake.V3_SWAP_EXACT_IN)}, inputs, big.NewInt(deadline)); err != nil {
// addTofailed(acc)
// WriteLog(fmt.Sprintf("[%s] failed: failed execute swap: %v", acc.Address, err))
// return
//} else {
// addNewTx(execTx)
//}
if execTx, err := v3r.ExactInputSingle(txopts, v3router.ISwapRouterExactInputSingleParams{
TokenIn: common.HexToAddress(env.USDT),
TokenOut: common.HexToAddress(env.KLKO),
Recipient: acc.Addr,
AmountIn: in,
AmountOutMinimum: amountOutMin,
Deadline: big.NewInt(deadline),
Fee: fee,
SqrtPriceLimitX96: big.NewInt(0),
}); err != nil {
addTofailed(acc) addTofailed(acc)
WriteLog(fmt.Sprintf("[%s] failed: failed execute swap: %v", acc.Address, err)) WriteLog(fmt.Sprintf("[%s] failed: failed execute swap: %v", acc.Address, err))
return return
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment