Skip to content

Commit

Permalink
refactor: update AA service integration and test URLs
Browse files Browse the repository at this point in the history
- Update Golang base image to 1.23.0 in Dockerfiles
- Remove outdated migration file
- Modify userop utility functions to focus on Biconomy AA service
- Update test cases with new Biconomy bundler and paymaster URLs
- Simplify AA service detection and endpoint handling
- Remove Stackup-specific code paths
  • Loading branch information
chibie committed Feb 20, 2025
1 parent 7edcb35 commit 394cd6c
Show file tree
Hide file tree
Showing 7 changed files with 37 additions and 120 deletions.
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Start from golang base image
FROM golang:1.22.11-bullseye
FROM golang:1.23.0-bullseye

# Install the air binary
RUN curl -sSfL https://raw.githubusercontent.com/cosmtrek/air/master/install.sh | sh -s -- -b $(go env GOPATH)/bin
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile.prod
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Start from golang base image
FROM golang:1.22.11-alpine3.21 as builder
FROM golang:1.23-alpine3.21 as builder

# Install git.
RUN apk update && apk add --no-cache git
Expand Down

This file was deleted.

2 changes: 2 additions & 0 deletions ent/migrate/migrations/20250220014823_aa_to_db.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-- Modify "networks" table
ALTER TABLE "networks" ADD COLUMN "bundler_url" character varying NULL, ADD COLUMN "paymaster_url" character varying NULL;
3 changes: 2 additions & 1 deletion ent/migrate/migrations/atlas.sum
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
h1:0TorEmKfcV3nUsITm2cbp5Yv14Y/YkjEuBOXQsvpcH4=
h1:dR+GjJoPfeuDFy3ZE8clPJfTvnRV/Q1LPkeT1nxVxJ4=
20240118234246_initial.sql h1:dYuYBqns33WT+3p8VQvbKUP62k3k6w6h8S+FqNqgSvU=
20240130122324_order_from_address.sql h1:mMVI2iBUd1roIYLUqu0d2jZ7+B6exppRN8qqn+aIHx4=
20240202010744_fees_on_order.sql h1:P7ngxZKqDKefBM5vk6M3kbWeMPVwbZ4MZVcLBjEfS34=
Expand Down Expand Up @@ -43,3 +43,4 @@ h1:0TorEmKfcV3nUsITm2cbp5Yv14Y/YkjEuBOXQsvpcH4=
20241011010524_linked_addresses.sql h1:JvCXlyrRTwXqYPwz5YoGoh+/KEaGiswxmRp//wyxyhU=
20241226183354_add_reference.sql h1:oS3oVJcfD6q7EvDQrTWudCEf3HjBm/yI8XTlPvGqLC8=
20250205002723_lof_optional_txid.sql h1:Ew1wBRx/K1cBIA//BAOjReVJW11idWCIkLnuaF8FdXY=
20250220014823_aa_to_db.sql h1:pqbdJZe7CXgXI7ak+ggHUhjncM7l5Kiw02S4N/hqCXU=
64 changes: 10 additions & 54 deletions utils/userop.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,7 @@ func InitializeUserOperation(ctx context.Context, client types.RPCClient, rpcUrl
return userOperation, nil
}

// SponsorUserOperation sponsors the user operation from stackup
// ref: https://docs.stackup.sh/docs/paymaster-api-rpc-methods#pm_sponsoruseroperation
// SponsorUserOperation sponsors the user operation with different AA services
func SponsorUserOperation(userOp *userop.UserOperation, mode string, token string, chainId int64) error {

_, paymasterUrl, err := getEndpoints(chainId)
Expand All @@ -126,23 +125,6 @@ func SponsorUserOperation(userOp *userop.UserOperation, mode string, token strin
var requestParams []interface{}

switch aaService {
case "stackup":
switch mode {
case "sponsored":
payload = map[string]interface{}{
"type": "payg",
}
case "erc20":
if token == "" {
return fmt.Errorf("token address is required")
}
payload = map[string]interface{}{
"type": "erc20token",
"token": token,
}
default:
return fmt.Errorf("invalid mode")
}
case "biconomy":
switch mode {
case "sponsored":
Expand Down Expand Up @@ -201,26 +183,6 @@ func SponsorUserOperation(userOp *userop.UserOperation, mode string, token strin
}

switch aaService {
case "stackup":
type Response struct {
PaymasterAndData string `json:"paymasterAndData" mapstructure:"paymasterAndData"`
PreVerificationGas string `json:"preVerificationGas" mapstructure:"preVerificationGas"`
VerificationGasLimit string `json:"verificationGasLimit" mapstructure:"verificationGasLimit"`
CallGasLimit string `json:"callGasLimit" mapstructure:"callGasLimit"`
}

var response Response
err = json.Unmarshal(result, &response)

if err != nil {
return fmt.Errorf("failed to unmarshal response: %w", err)
}

userOp.CallGasLimit, _ = new(big.Int).SetString(response.CallGasLimit, 0)
userOp.VerificationGasLimit, _ = new(big.Int).SetString(response.VerificationGasLimit, 0)
userOp.PreVerificationGas, _ = new(big.Int).SetString(response.PreVerificationGas, 0)
userOp.PaymasterAndData = common.FromHex(response.PaymasterAndData)

case "biconomy":
var response map[string]interface{}
err = json.Unmarshal(result, &response)
Expand Down Expand Up @@ -272,13 +234,11 @@ func SendUserOperation(userOp *userop.UserOperation, chainId int64) (string, str
return "", "", 0, fmt.Errorf("invalid AA service URL pattern: %w", err)
}

op, _ := userOp.MarshalJSON()
log.Println("userOp", string(op))

var requestParams []interface{}
switch aaService {
case "stackup":
requestParams = []interface{}{
userOp,
orderConf.EntryPointContractAddress.Hex(),
}
case "biconomy":
requestParams = []interface{}{
userOp,
Expand All @@ -291,6 +251,8 @@ func SendUserOperation(userOp *userop.UserOperation, chainId int64) (string, str
return "", "", 0, fmt.Errorf("unsupported AA service: %s", aaService)
}

log.Println("requestParams", requestParams)

var result json.RawMessage
err = client.Call(&result, "eth_sendUserOperation", requestParams...)
if err != nil {
Expand Down Expand Up @@ -335,7 +297,6 @@ func SendUserOperation(userOp *userop.UserOperation, chainId int64) (string, str

// GetUserOperationByReceipt fetches the user operation by hash
func GetUserOperationByReceipt(userOpHash string, chainId int64) (map[string]interface{}, error) {

bundlerUrl, _, err := getEndpoints(chainId)
if err != nil {
return nil, fmt.Errorf("failed to get endpoints for chain ID %d: %w", chainId, err)
Expand Down Expand Up @@ -427,8 +388,7 @@ func GetUserOperationByReceipt(userOpHash string, chainId int64) (map[string]int
}, nil
}

// GetPaymasterAccount fetches the paymaster account from stackup
// ref: https://docs.stackup.sh/docs/paymaster-api-rpc-methods#pm_accounts
// GetPaymasterAccount returns the paymaster account for the given chain ID
func GetPaymasterAccount(chainId int64) (string, error) {

_, paymasterUrl, err := getEndpoints(chainId)
Expand Down Expand Up @@ -568,31 +528,27 @@ func getEndpoints(chainID int64) (string, string, error) {
}

// Validate URL patterns
aaService, err := detectAAService(network.BundlerURL)
_, err = detectAAService(network.BundlerURL)
if err != nil {
return "", "", fmt.Errorf("invalid bundler URL pattern: %w", err)
}

log.Printf("Chain ID %d using AA service: %s", chainID, aaService)
return network.BundlerURL, network.PaymasterURL, nil
}

// detectAAService detects the AA service based on the provided URL pattern
func detectAAService(url string) (string, error) {
switch {
case strings.Contains(url, "api.stackup"):
return "stackup", nil
case strings.Contains(url, "api.biconomy"):
case strings.Contains(url, "biconomy.io"):
return "biconomy", nil
case strings.Contains(url, "api.pimlico"):
case strings.Contains(url, "api.pimlico.io"):
return "pimlico", nil
default:
return "", fmt.Errorf("unsupported AA service URL pattern: %s", url)
}
}

// getNonce returns the nonce for the given sender
// https://docs.stackup.sh/docs/useroperation-nonce
func getNonce(client types.RPCClient, sender common.Address) (nonce *big.Int, err error) {
entrypoint, err := contracts.NewEntryPoint(orderConf.EntryPointContractAddress, client.(bind.ContractBackend))
if err != nil {
Expand Down
56 changes: 21 additions & 35 deletions utils/userop_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ func TestUserOp(t *testing.T) {
SetIdentifier("ethereum").
SetIsTestnet(true).
SetRPCEndpoint("https://mock-rpc-url").
SetBundlerURL("http://api.stackup-bundler-url").
SetPaymasterURL("http://api.stackup-paymaster-url").
SetBundlerURL("http://bundler.biconomy.io").
SetPaymasterURL("http://paymaster.biconomy.io").
SetFee(decimal.NewFromInt(1)).
Save(ctx)
assert.NoError(t, err)
Expand All @@ -47,8 +47,8 @@ func TestUserOp(t *testing.T) {
t.Run("test getEndpoints with mock data", func(t *testing.T) {
bundlerURL, paymasterURL, err := getEndpoints(1)
assert.NoError(t, err)
assert.Equal(t, "http://api.stackup-bundler-url", bundlerURL)
assert.Equal(t, "http://api.stackup-paymaster-url", paymasterURL)
assert.Equal(t, "http://bundler.biconomy.io", bundlerURL)
assert.Equal(t, "http://paymaster.biconomy.io", paymasterURL)
})
t.Run("when chainID is supported getEndpoints", func(t *testing.T) {
bundlerID, paymaster, err := getEndpoints(1)
Expand Down Expand Up @@ -86,7 +86,7 @@ func TestUserOp(t *testing.T) {
}

// register mock response
httpmock.RegisterResponder("POST", "http://api.stackup-bundler-url",
httpmock.RegisterResponder("POST", "http://bundler.biconomy.io",
func(r *http.Request) (*http.Response, error) {
bytes, err := io.ReadAll(r.Body)
if err != nil {
Expand All @@ -95,7 +95,7 @@ func TestUserOp(t *testing.T) {

if strings.Contains(string(bytes), "eth_sendUserOperation") {

aaService, err := detectAAService("http://api.stackup-bundler-url")
aaService, err := detectAAService("http://bundler.biconomy.io")
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -186,46 +186,32 @@ func TestUserOp(t *testing.T) {
}

// register mock response
httpmock.RegisterResponder("POST", "http://api.stackup-paymaster-url",
httpmock.RegisterResponder("POST", "http://paymaster.biconomy.io",
func(r *http.Request) (*http.Response, error) {
bytes, err := io.ReadAll(r.Body)
if err != nil {
log.Fatal(err)
}

if strings.Contains(string(bytes), "pm_sponsorUserOperation") {
aaService, err := detectAAService("http://api.stackup-paymaster-url")
aaService, err := detectAAService("http://paymaster.biconomy.io")
if err != nil {
return nil, err
}
assert.Equal(t, "biconomy", aaService)
assert.True(t, strings.Contains(string(bytes), "INFINITISM"))

if aaService == "biconomy" {
assert.True(t, strings.Contains(string(bytes), "INFINITISM"))
resp, err := httpmock.NewJsonResponse(200, map[string]interface{}{
"jsonrpc": "2.0",
"id": 1,
"result": map[string]interface{}{
"paymasterAndData": "0x00000f79b7faf42eebadba19acc07cd08af447890000000000000000000...",
"preVerificationGas": "186034",
"verificationGasLimit": 395693,
"callGasLimit": 55412,
},
})
return resp, err
} else {
assert.True(t, strings.Contains(string(bytes), "pm_sponsorUserOperation"))
resp, err := httpmock.NewJsonResponse(200, map[string]interface{}{
"jsonrpc": "2.0",
"id": 1,
"result": map[string]interface{}{
"paymasterAndData": "0x00000f79b7faf42eebadba19acc07cd08af447890000000000000000000...",
"preVerificationGas": "0x1234",
"verificationGasLimit": "0x1234",
"callGasLimit": "0x1234",
},
})
return resp, err
}
resp, err := httpmock.NewJsonResponse(200, map[string]interface{}{
"jsonrpc": "2.0",
"id": 1,
"result": map[string]interface{}{
"paymasterAndData": "0x00000f79b7faf42eebadba19acc07cd08af447890000000000000000000...",
"preVerificationGas": "186034",
"verificationGasLimit": 395693,
"callGasLimit": 55412,
},
})
return resp, err
}
return httpmock.NewBytesResponse(200, []byte(`{"jsonrpc": "2.0","id": 1,"result":[]}`)), nil

Expand Down

0 comments on commit 394cd6c

Please sign in to comment.