Skip to content

Commit

Permalink
add userop convert
Browse files Browse the repository at this point in the history
  • Loading branch information
cherry-yl-sh committed Mar 12, 2024
1 parent 3e5c9f7 commit abf8840
Show file tree
Hide file tree
Showing 20 changed files with 247 additions and 110 deletions.
12 changes: 6 additions & 6 deletions common/model/api_request.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ import (
)

type TryPayUserOpRequest struct {
ForceStrategyId string `json:"force_strategy_id"`
ForceNetwork types.Network `json:"force_network"`
ForceToken string `json:"force_token"`
ForceEntryPointAddress string `json:"force_entrypoint_address"`
UserOperation UserOperationItem `json:"user_operation"`
Extra interface{} `json:"extra"`
ForceStrategyId string `json:"force_strategy_id"`
ForceNetwork types.Network `json:"force_network"`
ForceToken string `json:"force_token"`
ForceEntryPointAddress string `json:"force_entrypoint_address"`
UserOp map[string]any `json:"user_operation"`
Extra interface{} `json:"extra"`
}

func (request *TryPayUserOpRequest) Validate() error {
Expand Down
2 changes: 1 addition & 1 deletion common/model/api_response.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ type PayReceipt struct {
}

type GetSupportEntryPointResponse struct {
EntrypointDomains []EntrypointDomain `json:"entrypoints"`
EntrypointDomains *[]EntrypointDomain `json:"entrypoints"`
}
type EntrypointDomain struct {
Address string `json:"address"`
Expand Down
1 change: 1 addition & 0 deletions common/model/strategy.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import "AAStarCommunity/EthPaymaster_BackService/common/types"
type Strategy struct {
Id string `json:"id"`
EntryPointAddress string `json:"entrypoint_address"`
EntryPointTag types.EntrypointTag `json:"entrypoint_tag"`
PayMasterAddress string `json:"paymaster_address"`
PayType types.PayType `json:"pay_type"`
NetWork types.Network `json:"network"`
Expand Down
104 changes: 99 additions & 5 deletions common/model/user_operation.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,109 @@
package model

type UserOperationItem struct {
import (
"encoding/hex"
"github.com/ethereum/go-ethereum/common"
"github.com/mitchellh/mapstructure"
"golang.org/x/xerrors"
"math/big"
"reflect"
)

// UserOperation entrypoint v0.0.6
type UserOperation struct {
Sender common.Address `json:"sender" mapstructure:"sender" binding:"required,hexParam"`
Nonce *big.Int `json:"nonce" mapstructure:"nonce" binding:"required"`
InitCode []byte `json:"initCode" mapstructure:"initCode" `
CallData []byte `json:"callData" mapstructure:"callData" binding:"required"`
CallGasLimit *big.Int `json:"callGasLimit" mapstructure:"callGasLimit" binding:"required"`
VerificationGasList *big.Int `json:"verificationGasLimit" mapstructure:"verificationGasLimit" binding:"required"`
PreVerificationGas *big.Int `json:"preVerificationGas" mapstructure:"preVerificationGas" binding:"required"`
MaxFeePerGas *big.Int `json:"maxFeePerGas" mapstructure:"maxFeePerGas" binding:"required"`
MaxPriorityFeePerGas *big.Int `json:"maxPriorityFeePerGas" mapstructure:"maxPriorityFeePerGas" binding:"required"`
Signature []byte `json:"signature" mapstructure:"signature" binding:"required"`
PaymasterAndData []byte `json:"paymasterAndData" mapstructure:"paymasterAndData"`
}

// PackUserOperation entrypoint v0.0.67
type PackUserOperation struct {
Sender string `json:"sender" binding:"required,hexParam"`
Nonce string `json:"nonce" binding:"required"`
InitCode string `json:"init_code"`
CallData string `json:"call_data" binding:"required"`
CallGasLimit string `json:"call_gas_limit" binding:"required"`
VerificationGasList string `json:"verification_gas_list" binding:"required"`
PreVerificationGas string `json:"per_verification_gas" binding:"required"`
AccountGasLimit string `json:"account_gas_limit" binding:"required"`
PreVerificationGas string `json:"pre_verification_gas" binding:"required"`
MaxFeePerGas string `json:"max_fee_per_gas" binding:"required"`
MaxPriorityFeePerGas string `json:"max_priority_fee_per_gas" binding:"required"`
Signature string `json:"signature" binding:"required"`
PaymasterAndData string `json:"paymaster_and_data"`
Signature string `json:"signature" binding:"required"`
}

func NewUserOp(userOp *map[string]any) (*UserOperation, error) {

var result UserOperation
// Convert map to struct
decodeConfig := &mapstructure.DecoderConfig{
DecodeHook: decodeOpTypes,
Result: &result,
ErrorUnset: true,
MatchName: exactFieldMatch,
}
decoder, err := mapstructure.NewDecoder(decodeConfig)
if err != nil {
return nil, err
}
if err := decoder.Decode(userOp); err != nil {
return nil, xerrors.Errorf("data [%w] convert failed: [%w]", userOp, err)
}

return &result, nil
}

func exactFieldMatch(mapKey, fieldName string) bool {
return mapKey == fieldName
}

func decodeOpTypes(
f reflect.Kind,
t reflect.Kind,
data interface{}) (interface{}, error) {
// String to common.Address conversion
if f == reflect.String && t == reflect.Array {
return common.HexToAddress(data.(string)), nil
}

// String to big.Int conversion
if f == reflect.String && t == reflect.Struct {
n := new(big.Int)
n, ok := n.SetString(data.(string), 0)
if !ok {
return nil, xerrors.Errorf("bigInt conversion failed")
}
return n, nil
}

// Float64 to big.Int conversion
if f == reflect.Float64 && t == reflect.Struct {
n, ok := data.(float64)
if !ok {
return nil, xerrors.Errorf("bigInt conversion failed")
}
return big.NewInt(int64(n)), nil
}

// String to []byte conversion
if f == reflect.String && t == reflect.Slice {
byteStr := data.(string)
if len(byteStr) < 2 || byteStr[:2] != "0x" {
return nil, xerrors.Errorf("not byte string")
}

b, err := hex.DecodeString(byteStr[2:])
if err != nil {
return nil, err
}
return b, nil
}

return data, nil
}
8 changes: 8 additions & 0 deletions common/types/entrypoint_tag.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package types

type EntrypointTag string

const (
EntrypointV06 EntrypointTag = "v0.6"
EntryPointV07 EntrypointTag = "v0.7"
)
41 changes: 26 additions & 15 deletions common/utils/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package utils

import (
"AAStarCommunity/EthPaymaster_BackService/common/model"
"encoding/hex"
"encoding/json"
"github.com/ethereum/go-ethereum/crypto"
"regexp"
Expand All @@ -10,20 +11,23 @@ import (

var HexPattern = regexp.MustCompile(`^0x[a-fA-F\d]*$`)

func GenerateMockUserOperation() *model.UserOperationItem {
func GenerateMockUserOperation() *map[string]any {
//TODO use config
return &model.UserOperationItem{
Sender: "0x4A2FD3215420376DA4eD32853C19E4755deeC4D1",
Nonce: "1",
InitCode: "0x",
CallData: "0xb61d27f6000000000000000000000000c206b552ab127608c3f666156c8e03a8471c72df000000000000000000000000000000000000000000000000002386f26fc1000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000",
CallGasLimit: "39837",
VerificationGasList: "100000",
PreVerificationGas: "44020",
MaxFeePerGas: "1743509478",
MaxPriorityFeePerGas: "1500000000",
Signature: "0x760868cd7d9539c6e31c2169c4cab6817beb8247516a90e4301e929011451658623455035b83d38e987ef2e57558695040a25219c39eaa0e31a0ead16a5c925c1c",
var MockUserOpData = map[string]any{
"sender": "0x4A2FD3215420376DA4eD32853C19E4755deeC4D1",
"nonce": "1",
"initCode": "0xe19e9755942bb0bd0cccce25b1742596b8a8250b3bf2c3e700000000000000000000000078d4f01f56b982a3b03c4e127a5d3afa8ebee6860000000000000000000000008b388a082f370d8ac2e2b3997e9151168bd09ff50000000000000000000000000000000000000000000000000000000000000000",
"callData": "0xb61d27f6000000000000000000000000c206b552ab127608c3f666156c8e03a8471c72df000000000000000000000000000000000000000000000000002386f26fc1000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000",
"callGasLimit": "39837",
"verificationGasLimit": "100000",
"maxFeePerGas": "44020",
"maxPriorityFeePerGas": "1743509478",
"paymasterAndData": "0x",
"preVerificationGas": "44020",
"signature": "0x760868cd7d9539c6e31c2169c4cab6817beb8247516a90e4301e929011451658623455035b83d38e987ef2e57558695040a25219c39eaa0e31a0ead16a5c925c1c",
}

return &MockUserOpData
}
func ValidateHex(value string) bool {
if HexPattern.MatchString(value) {
Expand All @@ -39,11 +43,18 @@ func IsStringInUint64Range(s string) bool {
// 0 <= num <= MaxUint64
return num <= ^uint64(0)
}
func GenerateUserOperation() *model.UserOperationItem {
return &model.UserOperationItem{}
func GenerateUserOperation() *model.UserOperation {
return &model.UserOperation{}
}
func EncodeToStringWithPrefix(data []byte) string {
res := hex.EncodeToString(data)
if res[:2] != "0x" {
return "0x" + res
}
return res
}

func SignUserOp(privateKeyHex string, userOp *model.UserOperationItem) ([]byte, error) {
func SignUserOp(privateKeyHex string, userOp *model.UserOperation) ([]byte, error) {

serializedUserOp, err := json.Marshal(userOp)
if err != nil {
Expand Down
20 changes: 17 additions & 3 deletions common/utils/util_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package utils

import (
"AAStarCommunity/EthPaymaster_BackService/common/model"
"crypto/ecdsa"
"encoding/hex"
"fmt"
Expand All @@ -24,15 +25,28 @@ func TestSignUserOp(t *testing.T) {
//privateKeyHex: 1d8a58126e87e53edc7b24d58d1328230641de8c4242c135492bf5560e0ff421
//publicKey: 044eaed6b1f16e60354156fa334a094affc76d7b7061875a0b04290af9a14cc14ce2bce6ceba941856bd55c63f8199f408fff6495ce9d4c76899055972d23bdb3e
//address: 0x0E1375d18a4A2A867bEfe908E87322ad031386a6
signByte, err := SignUserOp("1d8a58126e87e53edc7b24d58d1328230641de8c4242c135492bf5560e0ff421", GenerateMockUserOperation())
userOp, newErr := model.NewUserOp(GenerateMockUserOperation())
if newErr != nil {
fmt.Println(newErr)
}
signByte, err := SignUserOp("1d8a58126e87e53edc7b24d58d1328230641de8c4242c135492bf5560e0ff421", userOp)
assert.NoError(t, err)
fmt.Printf("signByte: %x\n", signByte)
singature := hex.EncodeToString(signByte)
fmt.Printf("singature: %s\n", singature)

}
func TestNewUserOp(t *testing.T) {
userOp, newErr := model.NewUserOp(GenerateMockUserOperation())
if newErr != nil {
fmt.Println(newErr)
}
//initcode byte to string
fmt.Printf("userOp: %s\n", hex.EncodeToString(userOp.InitCode))

}

func TestValidate(t *testing.T) {
userOp := GenerateMockUserOperation()
assert.True(t, ValidateHex(userOp.Sender))
//userOp := GenerateMockUserOperation()
//assert.True(t, ValidateHex(userOp.Sender))
}
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ require (
github.com/leodido/go-urn v1.4.0 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/mmcloughlin/addchain v0.4.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,8 @@ github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182aff
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag=
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/pointerstructure v1.2.0 h1:O+i9nHnXS3l/9Wu7r4NrEdwA2VFTicjUEN1uBnDo34A=
github.com/mitchellh/pointerstructure v1.2.0/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4=
github.com/mmcloughlin/addchain v0.4.0 h1:SobOdjm2xLj1KkXN5/n0xTIWyZA2+s99UCY1iPfkHRY=
Expand Down
2 changes: 1 addition & 1 deletion paymaster_data_generator/erc20_paymaster_generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import "AAStarCommunity/EthPaymaster_BackService/common/model"
type Erc20PaymasterGenerator struct {
}

func (e Erc20PaymasterGenerator) GeneratePayMaster(strategy *model.Strategy, userOp *model.UserOperationItem) (string, error) {
func (e Erc20PaymasterGenerator) GeneratePayMaster(strategy *model.Strategy, userOp *model.UserOperation) (string, error) {
//ERC20:[0-1]pay type,[1-21]paymaster address,[21-53]token Amount
return "0x", nil
}
2 changes: 1 addition & 1 deletion paymaster_data_generator/paymaster_generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@ package paymaster_data_generator
import "AAStarCommunity/EthPaymaster_BackService/common/model"

type PaymasterGenerator interface {
GeneratePayMaster(strategy *model.Strategy, userOp *model.UserOperationItem) (string, error)
GeneratePayMaster(strategy *model.Strategy, userOp *model.UserOperation) (string, error)
}
2 changes: 1 addition & 1 deletion paymaster_data_generator/vertifying_paymaster_generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import "AAStarCommunity/EthPaymaster_BackService/common/model"
type VerifyingPaymasterGenerator struct {
}

func (v VerifyingPaymasterGenerator) GeneratePayMaster(strategy *model.Strategy, userOp *model.UserOperationItem) (string, error) {
func (v VerifyingPaymasterGenerator) GeneratePayMaster(strategy *model.Strategy, userOp *model.UserOperation) (string, error) {
//verifying:[0-1]pay type,[1-21]paymaster address,[21-85]valid timestamp,[85-] signature
return "0x", nil

Expand Down
6 changes: 3 additions & 3 deletions service/chain_service/chain_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (
)

var NetworkInfoMap map[types.Network]*types.NetworkInfo
var NetWorkClientMap map[types.Network]*ethclient.Client
var EthCompatibleNetWorkClientMap map[types.Network]*ethclient.Client

func init() {
ConfigInit()
Expand All @@ -27,13 +27,13 @@ func ConfigInit() {
}

func ClientInit() {
NetWorkClientMap = make(map[types.Network]*ethclient.Client)
EthCompatibleNetWorkClientMap = make(map[types.Network]*ethclient.Client)
for chain, networkInfo := range NetworkInfoMap {
client, err := ethclient.Dial(networkInfo.RpcUrl)
if err != nil {
panic(err)
}
NetWorkClientMap[chain] = client
EthCompatibleNetWorkClientMap[chain] = client
continue
}
}
11 changes: 5 additions & 6 deletions service/chain_service/chain_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,16 @@ import (
var GweiFactor = new(big.Float).SetInt(big.NewInt(1e9))
var EthWeiFactor = new(big.Float).SetInt(new(big.Int).Exp(big.NewInt(10), big.NewInt(18), nil))

func CheckContractAddressAccess(contract string, chain types.Network) (bool, error) {
func CheckContractAddressAccess(contract common.Address, chain types.Network) (bool, error) {
if chain == "" {
return false, xerrors.Errorf("chain can not be empty")
}
contractAddress := common.HexToAddress(contract)

client, exist := NetWorkClientMap[chain]
client, exist := EthCompatibleNetWorkClientMap[chain]
if !exist {
return false, xerrors.Errorf("chain Client [%s] not exist", chain)
}
code, err := client.CodeAt(context.Background(), contractAddress, nil)
code, err := client.CodeAt(context.Background(), contract, nil)
if err != nil {
return false, err
}
Expand All @@ -35,7 +34,7 @@ func CheckContractAddressAccess(contract string, chain types.Network) (bool, err

// GetGasPrice return gas price in wei, gwei, ether
func GetGasPrice(chain types.Network) (*big.Int, *big.Float, *string, error) {
client, exist := NetWorkClientMap[chain]
client, exist := EthCompatibleNetWorkClientMap[chain]
if !exist {
return nil, nil, nil, xerrors.Errorf("chain Client [%s] not exist", chain)
}
Expand All @@ -57,7 +56,7 @@ func GetEntryPointDeposit(entrypoint string, depositAddress string) uint256.Int
return uint256.Int{1}
}
func EstimateGasLimitAndCost(chain types.Network, msg ethereum.CallMsg) (uint64, error) {
client, exist := NetWorkClientMap[chain]
client, exist := EthCompatibleNetWorkClientMap[chain]
if !exist {
return 0, xerrors.Errorf("chain Client [%s] not exist", chain)
}
Expand Down
6 changes: 4 additions & 2 deletions service/chain_service/chain_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ import (
"AAStarCommunity/EthPaymaster_BackService/common/types"
"context"
"fmt"
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/assert"
"testing"
)

func TestCheckContractAddressAccess(t *testing.T) {
res, err := CheckContractAddressAccess("0x0576a174D229E3cFA37253523E645A78A0C91B57", types.Sepolia)
address := "0x0576a174D229E3cFA37253523E645A78A0C91B57"
res, err := CheckContractAddressAccess(common.HexToAddress(address), types.Sepolia)
assert.NoError(t, err)
assert.True(t, res)
}
Expand All @@ -23,7 +25,7 @@ func TestGetGasPrice(t *testing.T) {
}

func TestGethClient(t *testing.T) {
client, _ := NetWorkClientMap[types.Sepolia]
client, _ := EthCompatibleNetWorkClientMap[types.Sepolia]
num, _ := client.BlockNumber(context.Background())
assert.NotEqual(t, 0, num)
fmt.Println(num)
Expand Down
Loading

0 comments on commit abf8840

Please sign in to comment.