diff --git a/.vscode/launch.json b/.vscode/launch.json deleted file mode 100644 index 7706247..0000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "name": "Launch Facilitator Server", - "type": "go", - "request": "launch", - "mode": "auto", - "program": "${workspaceFolder}/cmd/facilitator", - "args": [ - "--config", - "${workspaceFolder}/config.toml" - ] - } - ] -} diff --git a/Makefile b/Makefile index b4bb8da..96984b4 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,10 @@ ROOT_DIR := $(dir $(realpath $(lastword $(MAKEFILE_LIST)))) -run: +build: + go build -o $(ROOT_DIR)/bin/facilitator $(ROOT_DIR)/cmd/facilitator + go build -o $(ROOT_DIR)/bin/client $(ROOT_DIR)/cmd/client + +run-facilitator: go run $(ROOT_DIR)/cmd/facilitator \ --config $(ROOT_DIR)/config.toml diff --git a/README.md b/README.md index 1897a71..13455ae 100644 --- a/README.md +++ b/README.md @@ -14,11 +14,35 @@ | Sui | 🚧 Planned | | | Tron | 🚧 Planned | | -# How to run +## How to run + +### Build binary +```bash +make build +``` + +### Run x402-facilitator using docker ```bash docker compose up ``` +### Run x402-client +``` +Usage: + client [flags] + +Flags: + -A, --amount string Amount to send + -F, --from string Sender address + -h, --help help for x402-client + -n, --network string Blockchain network to use (default "base-sepolia") + -P, --privkey string Sender private key + -s, --scheme string Scheme to use (default "evm") + -T, --to string Recipient address + -t, --token string token contract for sending (default "USDC") + -u, --url string Base URL of the facilitator server (default "http://localhost:9090") +``` + ## Api Specification After starting the service, open your browser to: ``` diff --git a/api/client/client.go b/api/client/client.go new file mode 100644 index 0000000..19f2721 --- /dev/null +++ b/api/client/client.go @@ -0,0 +1,136 @@ +package client + +import ( + "bytes" + "context" + "encoding/base64" + "encoding/json" + "fmt" + "io" + "net/http" + "net/url" + + "github.com/rabbitprincess/x402-facilitator/types" +) + +type Client struct { + BaseURL *url.URL + HTTPClient *http.Client + CreateAuthHeader func() (map[string]map[string]string, error) +} + +func NewClient(baseURL string) (*Client, error) { + parsed, err := url.Parse(baseURL) + if err != nil { + return nil, fmt.Errorf("invalid base URL: %w", err) + } + return &Client{ + BaseURL: parsed, + HTTPClient: http.DefaultClient, + }, nil +} + +// Supported fetches the list of supported schemes. +func (c *Client) Supported(ctx context.Context) ([]types.SupportedKind, error) { + var result []types.SupportedKind + if err := c.doRequest(ctx, http.MethodGet, "/supported", nil, "", &result); err != nil { + return nil, err + } + return result, nil +} + +func (c *Client) Verify(ctx context.Context, payload *types.PaymentPayload, req *types.PaymentRequirements) (*types.PaymentVerifyResponse, error) { + payloadJson, err := json.Marshal(payload) + if err != nil { + return nil, fmt.Errorf("marshal payment payload: %w", err) + } + header := base64.StdEncoding.EncodeToString(payloadJson) + + body := types.PaymentVerifyRequest{ + X402Version: int(types.X402VersionV1), + PaymentHeader: header, + PaymentRequirements: *req, + } + + var resp types.PaymentVerifyResponse + if err := c.doRequest(ctx, http.MethodPost, "/verify", body, "verify", &resp); err != nil { + return nil, err + } + return &resp, nil +} + +// Settle sends a payment settlement request. +func (c *Client) Settle(ctx context.Context, payload *types.PaymentPayload, req *types.PaymentRequirements) (*types.PaymentSettleResponse, error) { + payloadJson, err := json.Marshal(payload) + if err != nil { + return nil, fmt.Errorf("marshal payment payload: %w", err) + } + header := base64.StdEncoding.EncodeToString(payloadJson) + + body := types.PaymentSettleRequest{ + X402Version: int(types.X402VersionV1), + PaymentHeader: header, + PaymentRequirements: *req, + } + + var resp types.PaymentSettleResponse + if err := c.doRequest(ctx, http.MethodPost, "/settle", body, "settle", &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *Client) doRequest(ctx context.Context, method, path string, body any, authKey string, out any) error { + // Build URL + u := c.BaseURL.ResolveReference(&url.URL{Path: path}) + + // Prepare body + var reader io.Reader + if body != nil { + payload, err := json.Marshal(body) + if err != nil { + return fmt.Errorf("marshal request body: %w", err) + } + reader = bytes.NewReader(payload) + } + + // Create HTTP request + req, err := http.NewRequestWithContext(ctx, method, u.String(), reader) + if err != nil { + return err + } + if body != nil { + req.Header.Set("Content-Type", "application/json") + } + + if authKey != "" && c.CreateAuthHeader != nil { + hdrs, err := c.CreateAuthHeader() + if err != nil { + return fmt.Errorf("create auth headers: %w", err) + } + if section, ok := hdrs[authKey]; ok { + for k, v := range section { + req.Header.Set(k, v) + } + } + } + + // Execute + resp, err := c.HTTPClient.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + data, _ := io.ReadAll(resp.Body) + return fmt.Errorf("%s %s failed: status %d, body: %s", method, path, resp.StatusCode, string(data)) + } + + if out != nil { + if err := json.NewDecoder(resp.Body).Decode(out); err != nil { + return fmt.Errorf("decode %s response: %w", path, err) + } + } + return nil +} diff --git a/api/server.go b/api/server.go index 08b560f..9672a74 100644 --- a/api/server.go +++ b/api/server.go @@ -5,7 +5,6 @@ import ( "encoding/json" "net/http" - "github.com/go-playground/validator/v10" "github.com/labstack/echo/v4" echomiddleware "github.com/labstack/echo/v4/middleware" _ "github.com/rabbitprincess/x402-facilitator/api/swagger" @@ -19,9 +18,6 @@ import ( // @title x402 Facilitator API // @version 1.0 // @description API server for x402 payment facilitator -// @host localhost:8080 -// @BasePath / -// @schemes http type server struct { *echo.Echo facilitator facilitator.Facilitator @@ -51,10 +47,6 @@ func NewServer(facilitator facilitator.Facilitator) *server { return s } -var ( - validate = validator.New(validator.WithRequiredStructEnabled()) -) - // Settle handles payment settlement requests // @Summary Settle payment // @Description Settle a payment using the facilitator @@ -73,9 +65,7 @@ func (s *server) Settle(c echo.Context) error { if err := json.NewDecoder(c.Request().Body).Decode(requirement); err != nil { return echo.NewHTTPError(http.StatusBadRequest, "Received malformed settlement request") } - if err := validate.Struct(requirement); err != nil { - return echo.NewHTTPError(http.StatusBadRequest, "Received invalid settlement request") - } + payment := &types.PaymentPayload{} paymentDecoded, err := base64.StdEncoding.DecodeString(requirement.PaymentHeader) if err != nil { @@ -84,9 +74,7 @@ func (s *server) Settle(c echo.Context) error { if err := json.Unmarshal(paymentDecoded, payment); err != nil { return echo.NewHTTPError(http.StatusBadRequest, "Received malformed Payment header") } - if err := validate.Struct(payment); err != nil { - return echo.NewHTTPError(http.StatusBadRequest, "Received invalid Payment header") - } + settle, err := s.facilitator.Settle(ctx, payment, &requirement.PaymentRequirements) if err != nil { return echo.NewHTTPError(http.StatusInternalServerError, err.Error()) @@ -113,9 +101,6 @@ func (s *server) Verify(c echo.Context) error { if err := json.NewDecoder(c.Request().Body).Decode(requirement); err != nil { return echo.NewHTTPError(http.StatusBadRequest, "Received malformed payment requirements") } - if err := validate.Struct(requirement); err != nil { - return echo.NewHTTPError(http.StatusBadRequest, "Received invalid payment requirements") - } // validate payment payload payment := &types.PaymentPayload{} @@ -126,9 +111,6 @@ func (s *server) Verify(c echo.Context) error { if err := json.Unmarshal(paymentDecoded, payment); err != nil { return echo.NewHTTPError(http.StatusBadRequest, "Received malformed Payment header") } - if err := validate.Struct(payment); err != nil { - return echo.NewHTTPError(http.StatusBadRequest, "Received invalid Payment header") - } verified, err := s.facilitator.Verify(ctx, payment, &requirement.PaymentRequirements) if err != nil { diff --git a/api/swagger/docs.go b/api/swagger/docs.go index 8d73b69..927f6db 100644 --- a/api/swagger/docs.go +++ b/api/swagger/docs.go @@ -294,9 +294,9 @@ const docTemplate = `{ // SwaggerInfo holds exported Swagger Info so clients can modify it var SwaggerInfo = &swag.Spec{ Version: "1.0", - Host: "localhost:8080", - BasePath: "/", - Schemes: []string{"http"}, + Host: "", + BasePath: "", + Schemes: []string{}, Title: "x402 Facilitator API", Description: "API server for x402 payment facilitator", InfoInstanceName: "swagger", diff --git a/api/swagger/swagger.json b/api/swagger/swagger.json index 13b1f4e..55023b7 100644 --- a/api/swagger/swagger.json +++ b/api/swagger/swagger.json @@ -1,7 +1,4 @@ { - "schemes": [ - "http" - ], "swagger": "2.0", "info": { "description": "API server for x402 payment facilitator", @@ -9,8 +6,6 @@ "contact": {}, "version": "1.0" }, - "host": "localhost:8080", - "basePath": "/", "paths": { "/settle": { "post": { diff --git a/api/swagger/swagger.yaml b/api/swagger/swagger.yaml index 30d241e..29c5895 100644 --- a/api/swagger/swagger.yaml +++ b/api/swagger/swagger.yaml @@ -1,4 +1,3 @@ -basePath: / definitions: echo.HTTPError: properties: @@ -106,7 +105,6 @@ definitions: scheme: type: string type: object -host: localhost:8080 info: contact: {} description: API server for x402 payment facilitator @@ -192,6 +190,4 @@ paths: summary: Verify payment tags: - payments -schemes: -- http swagger: "2.0" diff --git a/cmd/client/main.go b/cmd/client/main.go index 06ab7d0..298b4c8 100644 --- a/cmd/client/main.go +++ b/cmd/client/main.go @@ -1 +1,108 @@ package main + +import ( + "encoding/hex" + "encoding/json" + + "github.com/rabbitprincess/x402-facilitator/api/client" + "github.com/rabbitprincess/x402-facilitator/scheme/evm" + "github.com/rabbitprincess/x402-facilitator/types" + "github.com/rs/zerolog/log" + "github.com/spf13/cobra" +) + +var cmd = &cobra.Command{ + Use: "x402-client", + Short: "Start the facilitator client", + Run: run, +} + +var ( + url string + scheme string + network string + token string + from string + to string + amount string + privkey string +) + +func init() { + fs := cmd.PersistentFlags() + + fs.StringVarP(&url, "url", "u", "http://localhost:9090", "Base URL of the facilitator server") + fs.StringVarP(&scheme, "scheme", "s", "evm", "Scheme to use") + fs.StringVarP(&network, "network", "n", "base-sepolia", "Blockchain network to use") + fs.StringVarP(&token, "token", "t", "USDC", "token contract for sending") + fs.StringVarP(&from, "from", "F", "", "Sender address") + fs.StringVarP(&to, "to", "T", "", "Recipient address") + fs.StringVarP(&amount, "amount", "A", "", "Amount to send") + fs.StringVarP(&privkey, "privkey", "P", "", "Sender private key") +} + +func main() { + if err := cmd.Execute(); err != nil { + log.Fatal().Err(err).Msg("Failed to execute command") + } +} + +func run(cmd *cobra.Command, args []string) { + client, err := client.NewClient(url) + if err != nil { + log.Fatal().Err(err).Msg("Failed to create client") + } + + // Here you would implement the logic to interact with the facilitator server + // using the provided parameters. + log.Info().Msg("Sending payment request") + var paymentPayload *types.PaymentPayload + var paymentRequirements *types.PaymentRequirements + switch scheme { + case "evm": + priv, err := hex.DecodeString(privkey) + if err != nil { + log.Fatal().Err(err).Msg("Failed to decode private key") + } + evmPayload, err := evm.NewEVMPayload(network, token, from, to, amount, evm.NewRawPrivateSigner(priv)) + if err != nil { + log.Fatal().Err(err).Msg("Failed to create EVM payload") + } + jsonPayload, err := json.Marshal(evmPayload) + if err != nil { + log.Fatal().Err(err).Msg("Failed to marshal EVM payload to JSON") + } + paymentPayload = &types.PaymentPayload{ + X402Version: int(types.X402VersionV1), + Scheme: scheme, + Network: network, + Payload: jsonPayload, + } + paymentRequirements = &types.PaymentRequirements{ + Scheme: scheme, + Network: network, + PayTo: to, + Asset: token, + } + } + + verifyResp, err := client.Verify(cmd.Context(), paymentPayload, paymentRequirements) + if err != nil { + log.Fatal().Err(err).Msg("Failed to verify payment") + } + if !verifyResp.IsValid { + log.Error().Str("invalidReason", verifyResp.InvalidReason).Msg("Payment verification failed") + return + } + + settleResp, err := client.Settle(cmd.Context(), paymentPayload, paymentRequirements) + if err != nil { + log.Fatal().Err(err).Msg("Failed to settle payment") + } + if !settleResp.Success { + log.Error().Msg("Payment settlement failed") + return + } + log.Info().Msg("Payment settled successfully") + +} diff --git a/cmd/facilitator/main.go b/cmd/facilitator/main.go index e634945..1050d27 100644 --- a/cmd/facilitator/main.go +++ b/cmd/facilitator/main.go @@ -17,7 +17,7 @@ import ( ) var cmd = &cobra.Command{ - Use: "facilitator", + Use: "x402-facilitator", Short: "Start the facilitator server", Run: func(cmd *cobra.Command, args []string) { run() @@ -29,8 +29,7 @@ var ( ) func init() { - cmd.PersistentFlags(). - StringVarP(&configPath, "config", "c", "../../config.toml", "Path to the configuration file") + cmd.PersistentFlags().StringVarP(&configPath, "config", "c", "config.toml", "Path to the configuration file") } func main() { @@ -62,8 +61,7 @@ func run() { go func() { log.Info().Msgf("Starting server on port %d", config.Port) if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed { - log.Fatal().Err(err). - Msg("Failed to start server, shutting down...") + log.Fatal().Err(err).Msg("Failed to start server, shutting down...") } }() @@ -77,9 +75,7 @@ func run() { defer cancel() if err := server.Shutdown(ctx); err != nil { - log.Fatal().Err(err). - Msg("Failed to shutdown server gracefully") + log.Fatal().Err(err).Msg("Failed to shutdown server gracefully") } - log.Info(). - Msg("Server shutdown gracefully") + log.Info().Msg("Server shutdown gracefully") } diff --git a/docker-compose.yml b/docker-compose.yml index 2e38372..bc54d53 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -3,7 +3,7 @@ services: build: context: . dockerfile: Dockerfile - image: x402-facilitator:latest + image: dreamcacao/x402-facilitator:latest container_name: x402-facilitator command: "/app/facilitator" volumes: diff --git a/facilitator/evm_test.go b/facilitator/evm_test.go index 3f13bcf..aaaf6ca 100644 --- a/facilitator/evm_test.go +++ b/facilitator/evm_test.go @@ -4,7 +4,6 @@ import ( "encoding/hex" "encoding/json" "fmt" - "math/big" "testing" "github.com/rabbitprincess/x402-facilitator/scheme/evm" @@ -25,7 +24,7 @@ func TestEVMVerify(t *testing.T) { privKey, err := hex.DecodeString("") require.NoError(t, err) evmPayload, err := evm.NewEVMPayload(Network, Token, - "", "", big.NewInt(10000), evm.NewRawPrivateSigner(privKey)) + "", "", "10000", evm.NewRawPrivateSigner(privKey)) require.NoError(t, err) evmPayloadJson, err := json.Marshal(evmPayload) @@ -57,7 +56,7 @@ func TestEVMSettle(t *testing.T) { privKey, err := hex.DecodeString("") require.NoError(t, err) evmPayload, err := evm.NewEVMPayload(Network, Token, - "", "", big.NewInt(10000), evm.NewRawPrivateSigner(privKey)) + "", "", "10000", evm.NewRawPrivateSigner(privKey)) require.NoError(t, err) evmPayloadJson, err := json.Marshal(evmPayload) require.NoError(t, err) diff --git a/go.mod b/go.mod index 95f1573..5a8abb5 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,6 @@ require ( github.com/blocto/solana-go-sdk v1.30.0 github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 github.com/ethereum/go-ethereum v1.15.11 - github.com/go-playground/validator/v10 v10.26.0 github.com/knadh/koanf/parsers/toml v0.1.0 github.com/knadh/koanf/providers/file v1.2.0 github.com/knadh/koanf/v2 v2.2.0 @@ -37,7 +36,6 @@ require ( github.com/ethereum/c-kzg-4844/v2 v2.1.0 // indirect github.com/ethereum/go-verkle v0.2.2 // indirect github.com/fsnotify/fsnotify v1.9.0 // indirect - github.com/gabriel-vasile/mimetype v1.4.8 // indirect github.com/ghodss/yaml v1.0.0 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-ole/go-ole v1.3.0 // indirect @@ -45,8 +43,6 @@ require ( github.com/go-openapi/jsonreference v0.19.6 // indirect github.com/go-openapi/spec v0.20.4 // indirect github.com/go-openapi/swag v0.19.15 // indirect - github.com/go-playground/locales v0.14.1 // indirect - github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-task/slim-sprig/v3 v3.0.0 // indirect github.com/go-viper/mapstructure/v2 v2.2.1 // indirect github.com/google/go-cmp v0.7.0 // indirect @@ -58,7 +54,6 @@ require ( github.com/josharian/intern v1.0.0 // indirect github.com/knadh/koanf/maps v0.1.2 // indirect github.com/labstack/gommon v0.4.2 // indirect - github.com/leodido/go-urn v1.4.0 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect diff --git a/go.sum b/go.sum index dc42ca2..853f358 100644 --- a/go.sum +++ b/go.sum @@ -69,8 +69,6 @@ github.com/ferranbt/fastssz v0.1.2 h1:Dky6dXlngF6Qjc+EfDipAkE83N5I5DE68bY6O0VLNP github.com/ferranbt/fastssz v0.1.2/go.mod h1:X5UPrE2u1UJjxHA8X54u04SBwdAQjG2sFtWs39YxyWs= github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= -github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM= -github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8= github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff h1:tY80oXqGNY4FhTFhk+o9oFHGINQ/+vhlm8HFzi6znCI= github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= github.com/getsentry/sentry-go v0.27.0 h1:Pv98CIbtB3LkMWmXi4Joa5OOcwbmnX88sF5qbK3r3Ps= @@ -92,14 +90,6 @@ github.com/go-openapi/spec v0.20.4/go.mod h1:faYFR1CvsJZ0mNsmsphTMSoRrNV3TEDoAM7 github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.15 h1:D2NRCBzS9/pEY3gP9Nl8aDqGUcPFrwG2p+CNFrLyrCM= github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= -github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= -github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= -github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= -github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= -github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= -github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= -github.com/go-playground/validator/v10 v10.26.0 h1:SP05Nqhjcvz81uJaRfEV0YBSSSGMc/iMaVtFbr3Sw2k= -github.com/go-playground/validator/v10 v10.26.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss= @@ -177,8 +167,6 @@ github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0 github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU= github.com/leanovate/gopter v0.2.11 h1:vRjThO1EKPb/1NsDXuDrzldR28RLkBflWYcU9CvzWu4= github.com/leanovate/gopter v0.2.11/go.mod h1:aK3tzZP/C+p1m3SPRE4SYZFGP7jjkuSI4f7Xvpt0S9c= -github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= -github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= diff --git a/scheme/evm/signer_test.go b/scheme/evm/signer_test.go index 90ba0ff..1022166 100644 --- a/scheme/evm/signer_test.go +++ b/scheme/evm/signer_test.go @@ -2,7 +2,6 @@ package evm import ( "encoding/hex" - "math/big" "testing" "github.com/decred/dcrd/dcrec/secp256k1/v4" @@ -45,7 +44,7 @@ func TestPayloadSignVerify(t *testing.T) { token := "USDC" payload, err := NewEVMPayload(chain, token, - "0x1234567890abcdef1234567890abcdef12345678", "0xabcdefabcdefabcdefabcdefabcdefabcdefabcdef", big.NewInt(100), signer) + "0x1234567890abcdef1234567890abcdef12345678", "0xabcdefabcdefabcdefabcdefabcdefabcdefabcdef", "100", signer) require.NoError(t, err) message := HashEip3009(payload.Authorization, GetDomainConfig(chain, token)) signature, err := hex.DecodeString(payload.Signature) diff --git a/scheme/evm/types.go b/scheme/evm/types.go index 038ef5d..f40682e 100644 --- a/scheme/evm/types.go +++ b/scheme/evm/types.go @@ -17,8 +17,12 @@ import ( "github.com/rabbitprincess/x402-facilitator/types" ) -func NewEVMPayload(chain, token, from, to string, value *big.Int, signer types.Signer) (*EVMPayload, error) { - authorization := NewAuthorization(from, to, value) +func NewEVMPayload(chain, token, from, to string, value string, signer types.Signer) (*EVMPayload, error) { + valueBig, ok := big.NewInt(0).SetString(value, 10) + if !ok { + return nil, fmt.Errorf("invalid value: %s", value) + } + authorization := NewAuthorization(from, to, valueBig) domain := GetDomainConfig(chain, token) if domain == nil { return nil, fmt.Errorf("domain config not found for chain %s and token %s", chain, token)