Commit f68cffcd authored by vicotor's avatar vicotor

add test code.

parent baf36d8e
...@@ -5,14 +5,12 @@ import ( ...@@ -5,14 +5,12 @@ import (
"code.wuban.net.cn/service/pancakeswapper/contracts/buildparam" "code.wuban.net.cn/service/pancakeswapper/contracts/buildparam"
"code.wuban.net.cn/service/pancakeswapper/contracts/v3pool" "code.wuban.net.cn/service/pancakeswapper/contracts/v3pool"
"code.wuban.net.cn/service/pancakeswapper/types" "code.wuban.net.cn/service/pancakeswapper/types"
"context"
"fmt" "fmt"
"github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/signer/core/apitypes" log "github.com/sirupsen/logrus"
"math/big" "math/big"
"strings" "strings"
"time" "time"
...@@ -142,88 +140,68 @@ func GetAmountOutMin(cfg *config.Config, client *ethclient.Client, env types.Env ...@@ -142,88 +140,68 @@ func GetAmountOutMin(cfg *config.Config, client *ethclient.Client, env types.Env
} }
func MakePermit2PermitData2(acc *types.Account, env types.Env, client *ethclient.Client) ([]byte, error) { func MakePermit2PermitData2(acc *types.Account, env types.Env, client *ethclient.Client) ([]byte, error) {
//00000000000000000000000055d398326f99059ff775485246999027b3197955
//000000000000000000000000ffffffffffffffffffffffffffffffffffffffff
//00000000000000000000000000000000000000000000000000000000681dd1ab
//0000000000000000000000000000000000000000000000000000000000000000
//0000000000000000000000001a0a18ac4becddbd6389559687d1a73d8927e416
//0000000000000000000000000000000000000000000000000000000067f64bb3
//00000000000000000000000000000000000000000000000000000000000000e0
//0000000000000000000000000000000000000000000000000000000000000041
//747b8fa98714e48b5db6e5585c8278ef7de03431ab30aed0b3d999cbf360d8db
//4fd9920bf48fbec49957def82ffa6e3441c6094b5cccd5ceee70ce19b1f96d11
//1c00000000000000000000000000000000000000000000000000000000000000
//00000000000000000000000055d398326f99059ff775485246999027b3197955
//000000000000000000000000ffffffffffffffffffffffffffffffffffffffff
//0000000000000000000000000000000000000000000000000000000069d9bfbd
//0000000000000000000000000000000000000000000000000000000067f88c3d
//0000000000000000000000001a0a18ac4becddbd6389559687d1a73d8927e416
//0000000000000000000000000000000000000000000000000000000067f9ddbd
//00000000000000000000000000000000000000000000000000000000000000e0
//0000000000000000000000000000000000000000000000000000000000000041
//7e90d529be5a0c36f2a59226382e22b9b38e258584ca7cca8e6c74faf4734fbe
//42d5b2b152b6325729818115eb27b0421104fc5ad0b9a068d8212e1e17e8e8fd
//1c00000000000000000000000000000000000000000000000000000000000000
// Constants // Constants
year := int64(365 * 24 * 60 * 60) year := int64(365 * 24 * 60 * 60)
hour := int64(60 * 60) day := int64(60 * 60 * 24)
// Create permit details expiration := big.NewInt(time.Now().Unix() + year)
permitSingle := buildparam.IPancakePermitSingle{ chainId := big.NewInt(env.ChainId)
Details: buildparam.IPancakePermitDetails{ token := common.HexToAddress(env.USDT)
Token: common.HexToAddress(env.USDT), permit2Address := common.HexToAddress(env.Permit2)
Amount: abi.MaxUint256, amount := new(big.Int).Sub(new(big.Int).Lsh(big.NewInt(1), 160), big.NewInt(1))
Expiration: big.NewInt(time.Now().Unix() + year), nonce := big.NewInt(time.Now().Unix())
Nonce: big.NewInt(time.Now().Unix()),
},
Spender: common.HexToAddress(env.Router),
SigDeadline: big.NewInt(time.Now().Unix() + hour),
}
// Get chain ID for domain separator signature, err := acc.SignTypedData(chainId, permit2Address, token, amount, expiration, nonce)
chainId, err := client.ChainID(context.Background())
if err != nil { if err != nil {
return nil, err return nil, err
} }
// Get permit2 contract address // Create permit details
permit2Address := common.HexToAddress(env.Permit2) permitSingle := buildparam.IPancakePermitSingle{
Details: buildparam.IPancakePermitDetails{
// Create the domain separator Token: common.HexToAddress(env.USDT),
domain := apitypes.TypedDataDomain{ Amount: amount,
Name: "Permit2", Expiration: expiration,
ChainId: math.NewHexOrDecimal256(chainId.Int64()), Nonce: nonce,
VerifyingContract: permit2Address.Hex(),
}
// Create the types for EIP-712 signing
types := apitypes.Types{
"PermitSingle": []apitypes.Type{
{Name: "details", Type: "PermitDetails"},
{Name: "spender", Type: "address"},
{Name: "sigDeadline", Type: "uint256"},
},
"PermitDetails": []apitypes.Type{
{Name: "token", Type: "address"},
{Name: "amount", Type: "uint256"},
{Name: "expiration", Type: "uint256"},
{Name: "nonce", Type: "uint256"},
},
}
// Create the typed data message
message := map[string]interface{}{
"details": map[string]interface{}{
"token": permitSingle.Details.Token.Hex(),
"amount": permitSingle.Details.Amount,
"expiration": permitSingle.Details.Expiration,
"nonce": permitSingle.Details.Nonce,
}, },
"spender": permitSingle.Spender.Hex(), Spender: common.HexToAddress(env.UniversalRouter),
"sigDeadline": permitSingle.SigDeadline, SigDeadline: big.NewInt(time.Now().Unix() + day),
}
// Create the typed data
typedData := apitypes.TypedData{
Types: types,
PrimaryType: "PermitSingle",
Domain: domain,
Message: message,
}
// Generate EIP-712 signature hash
signature, err := acc.SignTypedData(typedData)
if err != nil {
return nil, err
} }
// Pack the data // Pack the data
buildAbi, _ := abi.JSON(strings.NewReader(buildparam.ParamContractMetaData.ABI)) buildAbi, _ := abi.JSON(strings.NewReader(buildparam.ParamContractMetaData.ABI))
// todo: check method name.
data, err := buildAbi.Pack("buildParamPermit2", permitSingle, signature) data, err := buildAbi.Pack("buildParamPermit2", permitSingle, signature)
if err != nil { if err != nil {
log.WithError(err).Error("build permit2 permit")
return nil, err return nil, err
} }
// Remove method ID // Remove method ID
data = data[4:] data = data[4:]
return data, nil return data, nil
} }
...@@ -33,6 +33,7 @@ func (s *Swapper) Run() { ...@@ -33,6 +33,7 @@ func (s *Swapper) Run() {
// 2. init account info // 2. init account info
go func(w chan struct{}, accounts []*types.Account) { go func(w chan struct{}, accounts []*types.Account) {
grouptask.DoMultiTasks(s.cfg.Param.Routine, env, work.HandlerAccountSwap, accounts) grouptask.DoMultiTasks(s.cfg.Param.Routine, env, work.HandlerAccountSwap, accounts)
//grouptask.DoMultiTasks(s.cfg.Param.Routine, env, work.HandlerAccountSwapWithUniversalRouter, accounts)
w <- struct{}{} w <- struct{}{}
}(waitCh, accs) }(waitCh, accs)
......
...@@ -2,7 +2,10 @@ package types ...@@ -2,7 +2,10 @@ package types
import ( import (
"crypto/ecdsa" "crypto/ecdsa"
"fmt"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/signer/core/apitypes" "github.com/ethereum/go-ethereum/signer/core/apitypes"
...@@ -40,23 +43,66 @@ func (a *Account) SignMessage(msg []byte) ([]byte, error) { ...@@ -40,23 +43,66 @@ func (a *Account) SignMessage(msg []byte) ([]byte, error) {
return sig, nil return sig, nil
} }
func (a *Account) SignTypedData(typedData apitypes.TypedData) ([]byte, error) { func (a *Account) SignTypedData(chainID *big.Int, permit2Address, tokenAddress common.Address,
// Use the go-ethereum hash generator for EIP-712 amount *big.Int, expiration *big.Int, nonce *big.Int) ([]byte, error) {
hash, _, err := apitypes.TypedDataAndHash(typedData)
mchainId := math.HexOrDecimal256(*chainID)
// 创建EIP-712结构化数据
typedData := apitypes.TypedData{
Types: apitypes.Types{
"EIP712Domain": []apitypes.Type{
{Name: "name", Type: "string"},
{Name: "version", Type: "string"},
{Name: "chainId", Type: "uint256"},
{Name: "verifyingContract", Type: "address"},
},
"TokenPermissions": []apitypes.Type{
{Name: "token", Type: "address"},
{Name: "amount", Type: "uint256"},
},
"PermitTransferFrom": []apitypes.Type{
{Name: "permitted", Type: "TokenPermissions"},
{Name: "nonce", Type: "uint256"},
{Name: "deadline", Type: "uint256"},
},
},
PrimaryType: "PermitTransferFrom",
Domain: apitypes.TypedDataDomain{
Name: "Permit2",
Version: "1",
ChainId: &mchainId,
VerifyingContract: permit2Address.Hex(),
},
Message: apitypes.TypedDataMessage{
"permitted": map[string]interface{}{
"token": tokenAddress.Hex(),
"amount": amount.String(),
},
"nonce": hexutil.EncodeUint64(nonce.Uint64()),
"deadline": expiration.String(),
},
}
domain, err := typedData.HashStruct("EIP712Domain", typedData.Domain.Map())
if err != nil { if err != nil {
return nil, err return nil, fmt.Errorf("domain hash failed: %v", err)
} }
// Sign the hash with the private key permitHash, err := typedData.HashStruct(typedData.PrimaryType, typedData.Message)
sig, err := crypto.Sign(hash, a.PK)
if err != nil { if err != nil {
return nil, err return nil, fmt.Errorf("message hash failed: %v", err)
} }
// Adjust V value for Ethereum standard rawData := []byte(fmt.Sprintf("\x19\x01%s%s", string(domain), string(permitHash)))
if sig[64] < 27 { signHash := crypto.Keccak256(rawData)
sig[64] += 27
signature, err := crypto.Sign(signHash, a.PK)
if err != nil {
return nil, fmt.Errorf("sign message failed: %v", err)
} }
return sig, nil signature[64] += 27
return signature, nil
} }
...@@ -5,11 +5,13 @@ import ( ...@@ -5,11 +5,13 @@ 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"
router2 "code.wuban.net.cn/service/pancakeswapper/contracts/router"
"code.wuban.net.cn/service/pancakeswapper/contracts/v3router" "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"
"encoding/csv" "encoding/csv"
"encoding/hex"
"encoding/json" "encoding/json"
"fmt" "fmt"
"github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/accounts/abi"
...@@ -145,9 +147,18 @@ func accountApproveWithPermit(client *ethclient.Client, acc *types.Account, env ...@@ -145,9 +147,18 @@ func accountApproveWithPermit(client *ethclient.Client, acc *types.Account, env
inputs := make([][]byte, 0) inputs := make([][]byte, 0)
inputs = append(inputs, permitData) inputs = append(inputs, permitData)
fmt.Println("permit input data is ", hex.EncodeToString(permitData))
deadline := time.Now().Unix() + cfg.Param.Deadline*60
routerAbi, _ := abi.JSON(strings.NewReader(router2.RouterMetaData.ABI))
txdata, err := routerAbi.Pack("execute0", []byte{byte(pancake.PERMIT2_PERMIT)}, inputs, big.NewInt(deadline))
if err != nil {
fmt.Println()
return fmt.Errorf("pack execute failed: %v", err)
}
fmt.Println("txdata is ", hex.EncodeToString(txdata))
// set permit with universal router execute. // set permit with universal router execute.
deadline := time.Now().Unix() + cfg.Param.Deadline*60
if execTx, err := router.Execute(txopts, []byte{byte(pancake.PERMIT2_PERMIT)}, inputs, big.NewInt(deadline)); err != nil { if execTx, err := router.Execute(txopts, []byte{byte(pancake.PERMIT2_PERMIT)}, inputs, big.NewInt(deadline)); err != nil {
return fmt.Errorf("execute permit2 permit failed: %v", err) return fmt.Errorf("execute permit2 permit failed: %v", err)
} else { } else {
......
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