Skip to content

feat(golang): add Go implementation using x402 v2 protocol with testable architecture#65

Open
0xfakeSpike wants to merge 13 commits intogoogle-agentic-commerce:mainfrom
0xfakeSpike:main
Open

feat(golang): add Go implementation using x402 v2 protocol with testable architecture#65
0xfakeSpike wants to merge 13 commits intogoogle-agentic-commerce:mainfrom
0xfakeSpike:main

Conversation

@0xfakeSpike
Copy link

Summary

Add complete Go implementation of x402 A2A payment protocol with improved architecture for testability and comprehensive test coverage.

Changes

Features

  • Add Go implementation using x402 v2 protocol
  • Implement merchant and client components
  • Add example implementations for both merchant and client

Refactoring

  • Introduce interface abstraction (ResourceServer, ExtensionChecker) for dependency injection
  • Refactor BusinessOrchestrator to support testable architecture
  • Maintain backward compatibility with existing code

Fixes

  • Ensure errors are properly returned even when state transitions succeed
  • Fix error propagation in payment flow (ensureExtension, handlePaymentSubmitted)

Testing

  • Add comprehensive orchestrator tests with mock dependencies
  • Complete payment extraction test functions (payload, requirements, receipts)
  • Add utility function tests (ToMap, FromMap, ToSlice)

Files Changed

  • 37 files changed, 4270 insertions(+)
  • Core merchant/client implementation
  • State management and extraction utilities
  • Example applications
  • Comprehensive test suite

…jection

- Add ResourceServer and ExtensionChecker interfaces for testability
- Add NewBusinessOrchestratorWithDeps constructor for dependency injection
- Create resourceServerWrapper to adapt concrete type to interface
- Maintain backward compatibility with existing code
…succeeds

- Fix ensureExtension to return error even if transitionToFailed succeeds
- Fix handlePaymentSubmitted to return error even if transitionToFailed succeeds
- Ensures proper error propagation in payment flow
- Add TestExtractPaymentPayload with coverage for message and task extraction
- Add TestExtractPaymentRequirements with error handling tests
- Add TestExtractPaymentReceipts with multiple receipt scenarios
Update client configuration documentation to use 'networkName' instead of 'network' to match the actual configuration field name.
- ExtractPaymentStatus now only reads from task status, completely ignores message metadata
- Merchant orchestrator only processes payment based on task state, not client-submitted status
- Added PaymentRequired branch to handle client payment submission correctly
- Updated tests to reflect security changes

This fixes a critical security vulnerability where malicious clients could
bypass payment verification by setting x402.payment.status in message metadata
to 'payment-verified' or 'payment-completed'. Now merchant only uses task
status which is merchant-controlled.
Previously, when payment failed, if marshalling the error message failed
or if there was no message, the function would return nil, effectively
swallowing the error. This could lead to payment failures being silently
ignored.

Now the function always returns an error in the PaymentFailed case:
- First tries to marshal the full message object
- Falls back to extracting text from message parts if marshalling fails
- Returns a generic error if no message is available

This ensures payment failures are never silently ignored.
… task

Previously, when encountering an unknown payment state in a working task,
if json.Marshal failed or if there was no message, the function would
return nil, effectively swallowing the error. This could lead to silent
failures.

Now the function always returns an error when task is in working state
with unknown payment state:
- First tries to marshal the full message object
- Falls back to extracting text from message parts if marshalling fails
- Returns a generic error with payment state if no message is available

This ensures unknown payment states in working tasks are never silently
ignored and errors are properly propagated to the caller.
Previously, when payment verification failed, the task was transitioned to
a failed state but then the verification error was returned. This caused
the Execute method in the orchestrator to propagate an error, suggesting
an orchestrator failure rather than a normal business flow failure.

After successfully transitioning the task to a failed state, the function
now returns nil, nil. This indicates that the request was handled
successfully (by failing the task), allowing the orchestrator's Execute
method to complete without an error, which is consistent with how other
business logic failures are handled.
@0xfakeSpike 0xfakeSpike requested a review from a team as a code owner February 27, 2026 00:32
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces a full Go implementation of the x402 Agent-to-Agent (A2A) payment protocol, focusing on version 2. The changes establish a robust and testable architecture for both merchant and client functionalities, complete with example applications. It also includes significant improvements in error handling and comprehensive test coverage to ensure reliability and maintainability.

Highlights

  • Go Implementation of x402 v2 Protocol: Added a complete Go implementation of the x402 A2A payment protocol, supporting version 2.
  • Merchant and Client Components: Implemented both merchant and client components, including example implementations for each.
  • Improved Architecture for Testability: Introduced interface abstractions (ResourceServer, ExtensionChecker) and refactored BusinessOrchestrator to enhance testability.
  • Error Handling Enhancements: Ensured proper error return even on successful state transitions and fixed error propagation in the payment flow.
  • Comprehensive Test Coverage: Added extensive orchestrator tests with mock dependencies, complete payment extraction test functions, and utility function tests.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • .gitignore
    • Added Go-specific ignore rules for binaries, build directories, test coverage files, and sensitive configuration files.
  • golang/README.md
    • Added a new README file detailing the Go implementation of the x402 A2A Payment Protocol.
    • Included sections on features, requirements, quick start guides for merchant and client, project structure, and configuration.
  • golang/core/business/merchant_service_interface.go
    • Defined the BusinessService interface and ServiceRequirements struct for integrating merchant business logic with the x402 framework.
  • golang/core/client/a2a_client.go
    • Implemented functions for creating a new A2A client, fetching AgentCards, extracting extension URIs, and determining RPC endpoints.
    • Added a SendMessage function to handle sending messages and processing task/message responses.
  • golang/core/client/a2a_extension_header.go
    • Introduced an extensionHeaderInterceptor to add X-A2A-Extensions headers to client requests.
  • golang/core/client/client.go
    • Created a Client struct that wraps both the x402 client and the A2A client.
    • Provided a constructor function NewClient to initialize the client with merchant URL and network key pairs.
  • golang/core/client/payment_handler.go
    • Implemented the processPaymentState method to handle different payment states (Required, Completed, Failed) on the client side.
    • Included logic for processing payment requirements and sending payment messages.
  • golang/core/client/task_handler.go
    • Added the WaitForCompletion method to send a message and poll for task completion, including payment state processing.
  • golang/core/client/x402_client.go
    • Implemented the X402Client struct to manage x402 payment mechanisms for different networks (EVM, Solana).
    • Provided a NewX402Client constructor and a ProcessPaymentRequired method to select payment requirements and create payment payloads.
  • golang/core/merchant/interfaces.go
    • Defined ResourceServer and ExtensionChecker interfaces to abstract x402 resource server operations and extension checking for testability.
    • Provided a defaultExtensionChecker implementation.
  • golang/core/merchant/merchant.go
    • Implemented the Merchant struct, which encapsulates the BusinessOrchestrator.
    • Provided a NewMerchant constructor and an Orchestrator method to expose the orchestrator as an A2A AgentExecutor.
  • golang/core/merchant/orchestrator.go
    • Implemented the BusinessOrchestrator, which manages the payment and business logic flow.
    • Introduced NewBusinessOrchestrator and NewBusinessOrchestratorWithDeps for production and testable orchestrator creation.
    • Added Execute and Cancel methods to handle task execution and cancellation, including extension validation.
  • golang/core/merchant/orchestrator_test.go
    • Added comprehensive unit tests for the BusinessOrchestrator, covering extension checking, payment flow, and initial request handling.
  • golang/core/merchant/payment_handler.go
    • Implemented merchant-side payment handling functions: buildPaymentRequirements, findMatchingRequirement, verifyPayment, handlePaymentSubmitted, handlePaymentVerified, and settlePayment.
  • golang/core/merchant/resource_server.go
    • Implemented NewResourceServer to create and initialize an x402 resource server with various scheme servers.
    • Introduced resourceServerWrapper to adapt the x402.X402ResourceServer to the ResourceServer interface.
    • Added BuildPaymentRequirements function to construct payment requirements from network configurations and service parameters.
  • golang/core/merchant/state_transitions.go
    • Implemented functions for managing task state transitions: createTask, transitionToPaymentRequired, transitionToCompleted, transitionToFailed, and transitionToPaymentVerified.
  • golang/core/types/types.go
    • Defined NetworkConfig and NetworkKeyPair structs for consistent handling of network-specific configurations and private keys.
  • golang/core/utils/utils.go
    • Added generic utility functions ToMap, FromMap, and ToSlice for converting between Go types and map/slice interfaces using JSON marshaling.
  • golang/core/utils/utils_test.go
    • Added unit tests for the ToMap, FromMap, and ToSlice utility functions.
  • golang/core/x402/a2a_fields.go
    • Defined constants for A2A specific extra metadata keys (Resource, Description, MimeType, OutputSchema).
    • Implemented AddA2AFieldsToExtra and A2AFieldsFromExtra functions to manage these fields within x402 payment requirements.
  • golang/core/x402/constants.go
    • Defined constants for the x402 extension URI, various blockchain network identifiers (Base, Base Sepolia, Solana), and metadata keys used in A2A messages.
    • Added a NormalizeNetwork function to convert network aliases to CAIP-2 format.
  • golang/core/x402/state/encode.go
    • Implemented EncodePaymentSubmission to create an A2A message containing the x402 payment payload and status.
  • golang/core/x402/state/extract.go
    • Implemented functions to extract various payment-related information from A2A tasks and messages, including payment status, payload, requirements, receipts, original prompt, and message text.
  • golang/core/x402/state/extract_test.go
    • Added comprehensive unit tests for the payment state extraction functions, covering various scenarios and edge cases.
  • golang/core/x402/state/record.go
    • Implemented functions to record payment states (Required, Verified, Completed, Failed) and associated metadata within A2A task messages.
  • golang/core/x402/state/set.go
    • Implemented functions to set payment status, requirements, payload, receipts, error codes, and original prompt in A2A messages.
    • Added ClearPaymentMetadata to remove sensitive payment-related metadata.
  • golang/core/x402/state/types.go
    • Defined PaymentStatus enum and PaymentState struct to represent the various stages and data associated with an x402 payment flow.
  • golang/examples/client/client_config.example.json
    • Added an example JSON configuration file for the client, specifying network key pairs for Solana and EVM.
  • golang/examples/client/config.go
    • Implemented the Config struct and LoadConfig function to parse client configuration from a JSON file.
  • golang/examples/client/main.go
    • Implemented the main client application, which loads configuration, creates an A2A client, and sends a message to a merchant, waiting for task completion.
  • golang/examples/merchant/config.go
    • Implemented the ServerConfig struct and LoadServerConfig function to parse merchant server configuration from a JSON file.
  • golang/examples/merchant/image_service.go
    • Implemented an ImageService that uses the Google Generative AI API to generate images based on prompts.
    • Defined Execute and ServiceRequirements methods to integrate with the business logic interface.
  • golang/examples/merchant/main.go
    • Implemented the main merchant server application, which loads configuration, initializes an image generation service, and starts an A2A server handler.
  • golang/examples/merchant/server_config.example.json
    • Added an example JSON configuration file for the merchant server, specifying network configurations for Base Sepolia and Solana Devnet.
  • golang/examples/merchant/server_handler.go
    • Implemented the ServerHandler for the merchant, including AgentCard creation and A2A JSON-RPC handling.
    • Added middleware to extract HTTP headers for context propagation.
  • golang/go.mod
    • Added new Go module dependencies for a2a-go, coinbase/x402/go, and gin-gonic/gin.
  • golang/go.sum
    • Updated Go module checksums to reflect new dependencies.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a comprehensive Go implementation for the x402 A2A payment protocol, including both client and merchant components, along with a full set of tests and example applications. The architecture is well-designed for testability, with clear separation of concerns and dependency injection through interfaces like ResourceServer and ExtensionChecker. The state management and error handling are generally robust. I've identified a few areas for improvement, including a potential race condition in the merchant's payment handling logic, some code duplication in the client, and an ignored error in the example code. Overall, this is a high-quality contribution that significantly expands the project's capabilities.

- Reorder payment settlement to execute before business logic
  * Prevents side effects (e.g., image generation) if settlement fails
  * If business logic fails after successful settlement, merchant can handle
    as business-level issue (e.g., refund) rather than protocol failure

- Refactor duplicated error message extraction logic
  * Extract common error message extraction into extractErrorMessage helper
  * Reduces code duplication in PaymentFailed and default cases
  * Improves maintainability and readability

- Improve error handling in image service
  * Add proper error logging for file write operations
"prompt": prompt,
}

// if imageBase64 != "" {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we uncomment this to handle the image generation or include it in the datapart response

}, nil
}

func (o *BusinessOrchestrator) settlePayment(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here we are currently returning nil for the response. The x402 spec requires that we append all settlement attempts (including failures) to the x402.payment.receipts array. Could you update settlePayment to return the settleResponse even if it fails, so handlePaymentVerified can properly record the failed receipt before transitioning to the failed state?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants