diff --git a/Makefile b/Makefile index 37673a5..b4bb8da 100644 --- a/Makefile +++ b/Makefile @@ -7,6 +7,9 @@ run: test-e2e: go test -v $(ROOT_DIR)/test/e2e +generate-api: + swag init -g api/server.go -o api/swagger --parseDependency + generate-abi: abigen --abi $(ROOT_DIR)/scheme/evm/eip3009/eip3009.abi \ --pkg eip3009 \ diff --git a/README.md b/README.md index db1241c..060a331 100644 --- a/README.md +++ b/README.md @@ -12,4 +12,9 @@ It Supports facilitator and client roles on EVM-compatible chains. # How to run ```bash docker compose up -``` \ No newline at end of file +``` + +# Api Specification +``` +/swagger/index.html +``` diff --git a/api/server.go b/api/server.go index 6f0922e..08b560f 100644 --- a/api/server.go +++ b/api/server.go @@ -1,31 +1,40 @@ package api import ( + "encoding/base64" + "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" + echoSwagger "github.com/swaggo/echo-swagger" + "github.com/rabbitprincess/x402-facilitator/api/middleware" "github.com/rabbitprincess/x402-facilitator/facilitator" + "github.com/rabbitprincess/x402-facilitator/types" ) -// server represents the HTTP server for the API +// @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 } -// Ensure server implements http.Handler var _ http.Handler = (*server)(nil) -// NewServer creates and configures a new API server func NewServer(facilitator facilitator.Facilitator) *server { s := &server{ Echo: echo.New(), facilitator: facilitator, } - // Register middleware s.Use(middleware.RequestID()) s.Use(middleware.Logger()) s.Use(middleware.ErrorWrapper()) @@ -34,9 +43,114 @@ func NewServer(facilitator facilitator.Facilitator) *server { })) s.Use(echomiddleware.CORS()) - // Register routes s.POST("/verify", s.Verify) s.POST("/settle", s.Settle) + s.GET("/supported", s.Supported) + s.GET("/swagger/*", echoSwagger.WrapHandler) return s } + +var ( + validate = validator.New(validator.WithRequiredStructEnabled()) +) + +// Settle handles payment settlement requests +// @Summary Settle payment +// @Description Settle a payment using the facilitator +// @Tags payments +// @Accept json +// @Produce json +// @Param body body types.PaymentSettleRequest true "Settlement request" +// @Success 200 {object} types.PaymentSettleResponse +// @Failure 400 {object} echo.HTTPError +// @Failure 500 {object} echo.HTTPError +// @Router /settle [post] +func (s *server) Settle(c echo.Context) error { + ctx := c.Request().Context() + + requirement := &types.PaymentSettleRequest{} + 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 { + return echo.NewHTTPError(http.StatusBadRequest, "Received malformed Payment header") + } + 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()) + } + return c.JSON(http.StatusOK, settle) +} + +// Verify handles payment verification requests +// @Summary Verify payment +// @Description Verify a payment using the facilitator +// @Tags payments +// @Accept json +// @Produce json +// @Param body body types.PaymentVerifyRequest true "Payment verification request" +// @Success 200 {object} types.PaymentVerifyResponse +// @Failure 400 {object} echo.HTTPError +// @Failure 500 {object} echo.HTTPError +// @Router /verify [post] +func (s *server) Verify(c echo.Context) error { + ctx := c.Request().Context() + + // validate payment requirements + requirement := &types.PaymentVerifyRequest{} + 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{} + paymentDecoded, err := base64.StdEncoding.DecodeString(requirement.PaymentHeader) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, "Received malformed Payment header") + } + 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 { + return echo.NewHTTPError(http.StatusInternalServerError, err.Error()) + } + + return c.JSON(http.StatusOK, verified) +} + +// Supported returns the list of supported payment kinds +// @Summary List supported kinds +// @Description Get supported payment kinds +// @Tags payments +// @Produce json +// @Success 200 {array} types.SupportedKind +// @Failure 404 {object} echo.HTTPError +// @Router /supported [get] +func (s *server) Supported(c echo.Context) error { + kinds := s.facilitator.Supported() + if len(kinds) == 0 { + return echo.NewHTTPError(http.StatusNotFound, "No supported payment kinds found") + } + + return c.JSON(http.StatusOK, kinds) +} diff --git a/api/settle.go b/api/settle.go deleted file mode 100644 index 4fc40a2..0000000 --- a/api/settle.go +++ /dev/null @@ -1,20 +0,0 @@ -package api - -import ( - "net/http" - - "github.com/labstack/echo/v4" - "github.com/rs/zerolog/log" -) - -// Settle handles settlement requests -// TODO: Implement actual settlement logic -func (s *server) Settle(c echo.Context) error { - ctx := c.Request().Context() - - log.Ctx(ctx).Info().Msg("Settlement request received") - - return c.JSON(http.StatusNotImplemented, map[string]string{ - "message": "settlement not implemented yet", - }) -} diff --git a/api/swagger/docs.go b/api/swagger/docs.go new file mode 100644 index 0000000..8d73b69 --- /dev/null +++ b/api/swagger/docs.go @@ -0,0 +1,310 @@ +// Package swagger Code generated by swaggo/swag. DO NOT EDIT +package swagger + +import "github.com/swaggo/swag" + +const docTemplate = `{ + "schemes": {{ marshal .Schemes }}, + "swagger": "2.0", + "info": { + "description": "{{escape .Description}}", + "title": "{{.Title}}", + "contact": {}, + "version": "{{.Version}}" + }, + "host": "{{.Host}}", + "basePath": "{{.BasePath}}", + "paths": { + "/settle": { + "post": { + "description": "Settle a payment using the facilitator", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "payments" + ], + "summary": "Settle payment", + "parameters": [ + { + "description": "Settlement request", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/types.PaymentSettleRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/types.PaymentSettleResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/echo.HTTPError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/echo.HTTPError" + } + } + } + } + }, + "/supported": { + "get": { + "description": "Get supported payment kinds", + "produces": [ + "application/json" + ], + "tags": [ + "payments" + ], + "summary": "List supported kinds", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/types.SupportedKind" + } + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/echo.HTTPError" + } + } + } + } + }, + "/verify": { + "post": { + "description": "Verify a payment using the facilitator", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "payments" + ], + "summary": "Verify payment", + "parameters": [ + { + "description": "Payment verification request", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/types.PaymentVerifyRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/types.PaymentVerifyResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/echo.HTTPError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/echo.HTTPError" + } + } + } + } + } + }, + "definitions": { + "echo.HTTPError": { + "type": "object", + "properties": { + "message": {} + } + }, + "types.PaymentRequirements": { + "type": "object", + "required": [ + "asset", + "maxAmountRequired", + "network", + "payTo", + "resource", + "scheme" + ], + "properties": { + "asset": { + "description": "Address of the EIP-3009 compliant ERC20 contract", + "type": "string" + }, + "description": { + "description": "Description of the resource", + "type": "string" + }, + "extra": { + "description": "Extra information about the payment details specific to the scheme", + "type": "array", + "items": { + "type": "integer" + } + }, + "maxAmountRequired": { + "description": "Maximum amount required to pay for the resource in atomic units", + "type": "string" + }, + "maxTimeoutSeconds": { + "description": "Maximum time in seconds for the resource server to respond", + "type": "integer" + }, + "mimeType": { + "description": "MIME type of the resource response", + "type": "string" + }, + "network": { + "description": "Network of the blockchain to send payment on (e.g., \"base-sepolia\")", + "type": "string" + }, + "outputSchema": { + "description": "Output schema of the resource response (optional)", + "type": "array", + "items": { + "type": "integer" + } + }, + "payTo": { + "description": "Address to pay value to", + "type": "string" + }, + "resource": { + "description": "URL of the resource to pay for", + "type": "string" + }, + "scheme": { + "description": "Scheme of the payment protocol to use (e.g., \"exact\")", + "type": "string" + } + } + }, + "types.PaymentSettleRequest": { + "type": "object", + "properties": { + "paymentHeader": { + "type": "string" + }, + "paymentRequirements": { + "$ref": "#/definitions/types.PaymentRequirements" + }, + "x402Version": { + "type": "integer" + } + } + }, + "types.PaymentSettleResponse": { + "type": "object", + "properties": { + "error": { + "description": "Error message, if any", + "type": "string" + }, + "networkId": { + "description": "Network ID where the transaction was submitted", + "type": "string" + }, + "success": { + "description": "Whether the payment was successful", + "type": "boolean" + }, + "txHash": { + "description": "Transaction hash of the settled payment", + "type": "string" + } + } + }, + "types.PaymentVerifyRequest": { + "type": "object", + "required": [ + "paymentHeader", + "paymentRequirements", + "x402Version" + ], + "properties": { + "paymentHeader": { + "type": "string" + }, + "paymentRequirements": { + "$ref": "#/definitions/types.PaymentRequirements" + }, + "x402Version": { + "type": "integer" + } + } + }, + "types.PaymentVerifyResponse": { + "type": "object", + "properties": { + "invalidReason": { + "description": "Error message or reason for invalidity, if applicable", + "type": "string" + }, + "isValid": { + "description": "Whether the payment payload is valid", + "type": "boolean" + }, + "payer": { + "type": "string" + } + } + }, + "types.SupportedKind": { + "type": "object", + "properties": { + "network": { + "type": "string" + }, + "scheme": { + "type": "string" + } + } + } + } +}` + +// SwaggerInfo holds exported Swagger Info so clients can modify it +var SwaggerInfo = &swag.Spec{ + Version: "1.0", + Host: "localhost:8080", + BasePath: "/", + Schemes: []string{"http"}, + Title: "x402 Facilitator API", + Description: "API server for x402 payment facilitator", + InfoInstanceName: "swagger", + SwaggerTemplate: docTemplate, + LeftDelim: "{{", + RightDelim: "}}", +} + +func init() { + swag.Register(SwaggerInfo.InstanceName(), SwaggerInfo) +} diff --git a/api/swagger/swagger.json b/api/swagger/swagger.json new file mode 100644 index 0000000..13b1f4e --- /dev/null +++ b/api/swagger/swagger.json @@ -0,0 +1,289 @@ +{ + "schemes": [ + "http" + ], + "swagger": "2.0", + "info": { + "description": "API server for x402 payment facilitator", + "title": "x402 Facilitator API", + "contact": {}, + "version": "1.0" + }, + "host": "localhost:8080", + "basePath": "/", + "paths": { + "/settle": { + "post": { + "description": "Settle a payment using the facilitator", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "payments" + ], + "summary": "Settle payment", + "parameters": [ + { + "description": "Settlement request", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/types.PaymentSettleRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/types.PaymentSettleResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/echo.HTTPError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/echo.HTTPError" + } + } + } + } + }, + "/supported": { + "get": { + "description": "Get supported payment kinds", + "produces": [ + "application/json" + ], + "tags": [ + "payments" + ], + "summary": "List supported kinds", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/types.SupportedKind" + } + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/echo.HTTPError" + } + } + } + } + }, + "/verify": { + "post": { + "description": "Verify a payment using the facilitator", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "payments" + ], + "summary": "Verify payment", + "parameters": [ + { + "description": "Payment verification request", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/types.PaymentVerifyRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/types.PaymentVerifyResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/echo.HTTPError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/echo.HTTPError" + } + } + } + } + } + }, + "definitions": { + "echo.HTTPError": { + "type": "object", + "properties": { + "message": {} + } + }, + "types.PaymentRequirements": { + "type": "object", + "required": [ + "asset", + "maxAmountRequired", + "network", + "payTo", + "resource", + "scheme" + ], + "properties": { + "asset": { + "description": "Address of the EIP-3009 compliant ERC20 contract", + "type": "string" + }, + "description": { + "description": "Description of the resource", + "type": "string" + }, + "extra": { + "description": "Extra information about the payment details specific to the scheme", + "type": "array", + "items": { + "type": "integer" + } + }, + "maxAmountRequired": { + "description": "Maximum amount required to pay for the resource in atomic units", + "type": "string" + }, + "maxTimeoutSeconds": { + "description": "Maximum time in seconds for the resource server to respond", + "type": "integer" + }, + "mimeType": { + "description": "MIME type of the resource response", + "type": "string" + }, + "network": { + "description": "Network of the blockchain to send payment on (e.g., \"base-sepolia\")", + "type": "string" + }, + "outputSchema": { + "description": "Output schema of the resource response (optional)", + "type": "array", + "items": { + "type": "integer" + } + }, + "payTo": { + "description": "Address to pay value to", + "type": "string" + }, + "resource": { + "description": "URL of the resource to pay for", + "type": "string" + }, + "scheme": { + "description": "Scheme of the payment protocol to use (e.g., \"exact\")", + "type": "string" + } + } + }, + "types.PaymentSettleRequest": { + "type": "object", + "properties": { + "paymentHeader": { + "type": "string" + }, + "paymentRequirements": { + "$ref": "#/definitions/types.PaymentRequirements" + }, + "x402Version": { + "type": "integer" + } + } + }, + "types.PaymentSettleResponse": { + "type": "object", + "properties": { + "error": { + "description": "Error message, if any", + "type": "string" + }, + "networkId": { + "description": "Network ID where the transaction was submitted", + "type": "string" + }, + "success": { + "description": "Whether the payment was successful", + "type": "boolean" + }, + "txHash": { + "description": "Transaction hash of the settled payment", + "type": "string" + } + } + }, + "types.PaymentVerifyRequest": { + "type": "object", + "required": [ + "paymentHeader", + "paymentRequirements", + "x402Version" + ], + "properties": { + "paymentHeader": { + "type": "string" + }, + "paymentRequirements": { + "$ref": "#/definitions/types.PaymentRequirements" + }, + "x402Version": { + "type": "integer" + } + } + }, + "types.PaymentVerifyResponse": { + "type": "object", + "properties": { + "invalidReason": { + "description": "Error message or reason for invalidity, if applicable", + "type": "string" + }, + "isValid": { + "description": "Whether the payment payload is valid", + "type": "boolean" + }, + "payer": { + "type": "string" + } + } + }, + "types.SupportedKind": { + "type": "object", + "properties": { + "network": { + "type": "string" + }, + "scheme": { + "type": "string" + } + } + } + } +} \ No newline at end of file diff --git a/api/swagger/swagger.yaml b/api/swagger/swagger.yaml new file mode 100644 index 0000000..30d241e --- /dev/null +++ b/api/swagger/swagger.yaml @@ -0,0 +1,197 @@ +basePath: / +definitions: + echo.HTTPError: + properties: + message: {} + type: object + types.PaymentRequirements: + properties: + asset: + description: Address of the EIP-3009 compliant ERC20 contract + type: string + description: + description: Description of the resource + type: string + extra: + description: Extra information about the payment details specific to the scheme + items: + type: integer + type: array + maxAmountRequired: + description: Maximum amount required to pay for the resource in atomic units + type: string + maxTimeoutSeconds: + description: Maximum time in seconds for the resource server to respond + type: integer + mimeType: + description: MIME type of the resource response + type: string + network: + description: Network of the blockchain to send payment on (e.g., "base-sepolia") + type: string + outputSchema: + description: Output schema of the resource response (optional) + items: + type: integer + type: array + payTo: + description: Address to pay value to + type: string + resource: + description: URL of the resource to pay for + type: string + scheme: + description: Scheme of the payment protocol to use (e.g., "exact") + type: string + required: + - asset + - maxAmountRequired + - network + - payTo + - resource + - scheme + type: object + types.PaymentSettleRequest: + properties: + paymentHeader: + type: string + paymentRequirements: + $ref: '#/definitions/types.PaymentRequirements' + x402Version: + type: integer + type: object + types.PaymentSettleResponse: + properties: + error: + description: Error message, if any + type: string + networkId: + description: Network ID where the transaction was submitted + type: string + success: + description: Whether the payment was successful + type: boolean + txHash: + description: Transaction hash of the settled payment + type: string + type: object + types.PaymentVerifyRequest: + properties: + paymentHeader: + type: string + paymentRequirements: + $ref: '#/definitions/types.PaymentRequirements' + x402Version: + type: integer + required: + - paymentHeader + - paymentRequirements + - x402Version + type: object + types.PaymentVerifyResponse: + properties: + invalidReason: + description: Error message or reason for invalidity, if applicable + type: string + isValid: + description: Whether the payment payload is valid + type: boolean + payer: + type: string + type: object + types.SupportedKind: + properties: + network: + type: string + scheme: + type: string + type: object +host: localhost:8080 +info: + contact: {} + description: API server for x402 payment facilitator + title: x402 Facilitator API + version: "1.0" +paths: + /settle: + post: + consumes: + - application/json + description: Settle a payment using the facilitator + parameters: + - description: Settlement request + in: body + name: body + required: true + schema: + $ref: '#/definitions/types.PaymentSettleRequest' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/types.PaymentSettleResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/echo.HTTPError' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/echo.HTTPError' + summary: Settle payment + tags: + - payments + /supported: + get: + description: Get supported payment kinds + produces: + - application/json + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/types.SupportedKind' + type: array + "404": + description: Not Found + schema: + $ref: '#/definitions/echo.HTTPError' + summary: List supported kinds + tags: + - payments + /verify: + post: + consumes: + - application/json + description: Verify a payment using the facilitator + parameters: + - description: Payment verification request + in: body + name: body + required: true + schema: + $ref: '#/definitions/types.PaymentVerifyRequest' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/types.PaymentVerifyResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/echo.HTTPError' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/echo.HTTPError' + summary: Verify payment + tags: + - payments +schemes: +- http +swagger: "2.0" diff --git a/api/verify.go b/api/verify.go deleted file mode 100644 index c2e5c91..0000000 --- a/api/verify.go +++ /dev/null @@ -1,52 +0,0 @@ -package api - -import ( - "encoding/base64" - "encoding/json" - "net/http" - - "github.com/go-playground/validator/v10" - "github.com/labstack/echo/v4" - "github.com/rabbitprincess/x402-facilitator/types" -) - -var ( - // https://github.com/go-playground/validator?tab=readme-ov-file#special-notes - // NOTE: If new to using validator it is highly recommended to initialize it using the WithRequiredStructEnabled option which is opt-in to new behaviour that will become the default behaviour in v11+. See documentation for more details. - validate = validator.New(validator.WithRequiredStructEnabled()) -) - -// Verify handles verification requests -// Specification:https://github.com/coinbase/x402/tree/3895881f3d6c71fa060076958c8eabc139fcbe5a?tab=readme-ov-file#facilitator-types--interface -func (s *server) Verify(c echo.Context) error { - ctx := c.Request().Context() - - // validate payment requirements - requirement := &types.PaymentVerifyRequest{} - 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{} - paymentDecoded, err := base64.StdEncoding.DecodeString(requirement.PaymentHeader) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, "Received malformed Payment header") - } - 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 { - return echo.NewHTTPError(http.StatusInternalServerError, err.Error()) - } - - return c.JSON(http.StatusOK, verified) -} diff --git a/cmd/facilitator/config.go b/cmd/facilitator/config.go index e98e5fb..e83f043 100644 --- a/cmd/facilitator/config.go +++ b/cmd/facilitator/config.go @@ -12,7 +12,7 @@ type Config struct { Network string `mapstructure:"network"` Port int `mapstructure:"port"` Url string `mapstructure:"url"` - PrivateKey string `mapstructure:"private_key"` + PrivateKey string `mapstructure:"privateKey"` } func LoadConfig(path string) (*Config, error) { diff --git a/cmd/facilitator/main.go b/cmd/facilitator/main.go index dd7f6ee..e634945 100644 --- a/cmd/facilitator/main.go +++ b/cmd/facilitator/main.go @@ -30,7 +30,7 @@ var ( func init() { cmd.PersistentFlags(). - StringVarP(&configPath, "config", "c", "config.toml", "Path to the configuration file") + StringVarP(&configPath, "config", "c", "../../config.toml", "Path to the configuration file") } func main() { @@ -48,7 +48,7 @@ func run() { facilitator, err := facilitator.NewFacilitator(config.Scheme, config.Network, config.Url, config.PrivateKey) if err != nil { - log.Fatal().Err(err).Msg("Failed to create facilitator, shutting down...") + log.Fatal().Err(err).Msg("Failed to init facilitator, shutting down...") } api := api.NewServer(facilitator) diff --git a/config.toml b/config.toml index a10174d..1e2074b 100644 --- a/config.toml +++ b/config.toml @@ -5,5 +5,5 @@ port = 9090 # HTTP Port scheme = "evm" # "evm", "solana", "sui", "tron" network = "base-sepolia" # Network name url = "https://sepolia.base.org" # URL of the blockchain -private_key = "" # Hex encoded fee payer key for the facilitator +privateKey = "ef635a97985a15029dea94e7cca2589c688b59bc98b8cd4a90d857048fcbeec1" diff --git a/docker-compose.yml b/docker-compose.yml index 89f2e28..2e38372 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -9,7 +9,7 @@ services: volumes: - ./config.toml:/app/config.toml ports: - - "9000:9000" + - "9090:9090" networks: - x402-network diff --git a/go.mod b/go.mod index fe1fa99..95f1573 100644 --- a/go.mod +++ b/go.mod @@ -16,12 +16,17 @@ require ( github.com/rs/zerolog v1.34.0 github.com/spf13/cobra v1.9.1 github.com/stretchr/testify v1.10.0 + github.com/swaggo/echo-swagger v1.4.1 + github.com/swaggo/swag v1.16.4 golang.org/x/crypto v0.38.0 ) require ( filippo.io/edwards25519 v1.0.0-rc.1 // indirect + github.com/KyleBanks/depth v1.2.1 // indirect github.com/Microsoft/go-winio v0.6.2 // indirect + github.com/PuerkitoBio/purell v1.1.1 // indirect + github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect github.com/bits-and-blooms/bitset v1.20.0 // indirect github.com/consensys/bavard v0.1.27 // indirect github.com/consensys/gnark-crypto v0.16.0 // indirect @@ -33,8 +38,13 @@ require ( 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 + github.com/go-openapi/jsonpointer v0.19.5 // indirect + 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 @@ -45,9 +55,11 @@ require ( github.com/gorilla/websocket v1.4.2 // indirect github.com/holiman/uint256 v1.3.2 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect + 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 github.com/mitchellh/copystructure v1.2.0 // indirect @@ -59,6 +71,7 @@ require ( github.com/shirou/gopsutil v3.21.11+incompatible // indirect github.com/spf13/pflag v1.0.6 // indirect github.com/supranational/blst v0.3.14 // indirect + github.com/swaggo/files/v2 v2.0.0 // indirect github.com/tklauser/go-sysconf v0.3.12 // indirect github.com/tklauser/numcpus v0.6.1 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect @@ -71,6 +84,7 @@ require ( golang.org/x/text v0.25.0 // indirect golang.org/x/time v0.11.0 // indirect golang.org/x/tools v0.31.0 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect rsc.io/tmplfunc v0.0.3 // indirect ) diff --git a/go.sum b/go.sum index 616db7a..dc42ca2 100644 --- a/go.sum +++ b/go.sum @@ -2,8 +2,14 @@ filippo.io/edwards25519 v1.0.0-rc.1 h1:m0VOOB23frXZvAOK44usCgLWvtsxIoMCTBGJZlpmG filippo.io/edwards25519 v1.0.0-rc.1/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns= github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ= github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= +github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= +github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= +github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= +github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/VictoriaMetrics/fastcache v1.12.2 h1:N0y9ASrJ0F6h0QaC3o6uJb3NIZ9VKLjCM7NQbSmF7WI= github.com/VictoriaMetrics/fastcache v1.12.2/go.mod h1:AmC+Nzz1+3G2eCPapF6UcsnkThDcMsQicp4xDukwJYI= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -41,6 +47,8 @@ github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a h1:W8mUrRp6NOV github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a/go.mod h1:sTwzHBvIzm2RfVCGNEBZgRyjwK40bVoun3ZnGOCafNM= github.com/crate-crypto/go-kzg-4844 v1.1.0 h1:EN/u9k2TF6OWSHrCCDBBU6GLNMq88OspHHlMnHfoyU4= github.com/crate-crypto/go-kzg-4844 v1.1.0/go.mod h1:JolLjpSff1tCCJKaJx4psrlEdlXuJEC996PL3tTAFks= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/deckarep/golang-set/v2 v2.8.0 h1:swm0rlPCmdWn9mESxKOjWk8hXSqoxOp+ZlfuyaAdFlQ= @@ -67,11 +75,23 @@ github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff h1:tY80oXqG 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= github.com/getsentry/sentry-go v0.27.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY= +github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= +github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= +github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonreference v0.19.6 h1:UBIxjkht+AWIgYzCDSv2GN+E/togfwXUJFRTWhl2Jjs= +github.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns= +github.com/go-openapi/spec v0.20.4 h1:O8hJrt0UMnhHcluhIdUgCLRWyM2x7QkBXRvOs7m+O1M= +github.com/go-openapi/spec v0.20.4/go.mod h1:faYFR1CvsJZ0mNsmsphTMSoRrNV3TEDoAM7FOEWeq8I= +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= @@ -128,6 +148,8 @@ github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839 h1:W9WBk7 github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo= github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/klauspost/compress v1.16.0 h1:iULayQNOReoYUe+1qtKOqw9CwJv3aNQu8ivo7lw1HU4= github.com/klauspost/compress v1.16.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4= @@ -140,8 +162,11 @@ github.com/knadh/koanf/providers/file v1.2.0 h1:hrUJ6Y9YOA49aNu/RSYzOTFlqzXSCpmY github.com/knadh/koanf/providers/file v1.2.0/go.mod h1:bp1PM5f83Q+TOUu10J/0ApLBd9uIzg+n9UgthfY+nRA= github.com/knadh/koanf/v2 v2.2.0 h1:FZFwd9bUjpb8DyCWARUBy5ovuhDs1lI87dOEn2K8UVU= github.com/knadh/koanf/v2 v2.2.0/go.mod h1:PSFru3ufQgTsI7IF+95rf9s8XA1+aHxKuO/W+dPoHEY= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= @@ -154,6 +179,11 @@ github.com/leanovate/gopter v0.2.11 h1:vRjThO1EKPb/1NsDXuDrzldR28RLkBflWYcU9CvzW 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= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= @@ -179,6 +209,7 @@ github.com/mmcloughlin/addchain v0.4.0/go.mod h1:A86O+tHqZLMNO4w6ZZ4FlVQEadcoqky github.com/mmcloughlin/profile v0.1.1/go.mod h1:IhHD7q1ooxgwTgjxQYkACGA77oFTDdFVejUS1/tS/qU= github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/onsi/ginkgo/v2 v2.23.4 h1:ktYTpKJAVZnDT4VjxSbiBenUjmlL/5QkBEocaWXiQus= @@ -232,10 +263,19 @@ github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo= github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0= github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/supranational/blst v0.3.14 h1:xNMoHRJOTwMn63ip6qoWJ2Ymgvj7E2b9jY2FAwY+qRo= github.com/supranational/blst v0.3.14/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= +github.com/swaggo/echo-swagger v1.4.1 h1:Yf0uPaJWp1uRtDloZALyLnvdBeoEL5Kc7DtnjzO/TUk= +github.com/swaggo/echo-swagger v1.4.1/go.mod h1:C8bSi+9yH2FLZsnhqMZLIZddpUxZdBYuNHbtaS1Hljc= +github.com/swaggo/files/v2 v2.0.0 h1:hmAt8Dkynw7Ssz46F6pn8ok6YmGZqHSVLZ+HQM7i0kw= +github.com/swaggo/files/v2 v2.0.0/go.mod h1:24kk2Y9NYEJ5lHuCra6iVwkMjIekMCaFq/0JQj66kyM= +github.com/swaggo/swag v1.16.4 h1:clWJtd9LStiG3VeijiCfOVODP6VpHtKdQy9ELFG3s1A= +github.com/swaggo/swag v1.16.4/go.mod h1:VBsHJRsDvfYvqoiMKnsdwhNV9LEMHgEDZcyVYX0sxPg= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= @@ -258,11 +298,16 @@ golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8= golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw= golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df h1:UA2aFVmmsIlefxMk29Dp2juaUSth8Pyn3Tq5Y5mJGME= golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= +golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU= +golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= +golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM= golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c= golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ= golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -271,21 +316,30 @@ golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4= golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA= golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0= golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.31.0 h1:0EedkvKDbh+qistFTd0Bcwe/YLh4vHwWEkiI0toFIBU= golang.org/x/tools v0.31.0/go.mod h1:naFTU+Cev749tSJRXJlna0T3WxKvb1kWEx15xA4SdmQ= google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM= google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= rsc.io/tmplfunc v0.0.3 h1:53XFQh69AfOa8Tw0Jm7t+GV7KZhOi6jzsCzTtKbMvzU= diff --git a/types/facilitator.go b/types/facilitator.go index 143b21e..2eb1ee1 100644 --- a/types/facilitator.go +++ b/types/facilitator.go @@ -2,6 +2,8 @@ package types import "encoding/json" +// Specification: https://github.com/coinbase/x402/tree/main?tab=readme-ov-file#type-specifications + // PaymentRequirements defines the structure for accepted payments by the resource server. // This corresponds to the server's response in the 402 Payment Required flow. type PaymentRequirements struct {