Skip to content

fix(samples): authorize the verified mandate amount in x402 credential provider#300

Open
chopmob-cloud wants to merge 6 commits into
google-agentic-commerce:mainfrom
chopmob-cloud:fix/299-x402-verified-amount
Open

fix(samples): authorize the verified mandate amount in x402 credential provider#300
chopmob-cloud wants to merge 6 commits into
google-agentic-commerce:mainfrom
chopmob-cloud:fix/299-x402-verified-amount

Conversation

@chopmob-cloud

Copy link
Copy Markdown

Addresses part of #299: the fail-open amount handling in the x402 credential provider sample.

Problem

In x402_credentials_provider_mcp/server.py, after the mandate chain is cryptographically verified, the handler extracts the transfer amount like this:

try:
    payee_address = chain.closed_mandate.payment_instrument.payee_address
    amount_cents = chain.closed_mandate.payment_amount.amount
    ...
except AttributeError:
    payee_address = (
        os.environ.get("MERCHANT_WALLET_ADDRESS") or DEFAULT_MERCHANT_ADDRESS
    )
    amount_cents = 1250

PaymentInstrument has no payee_address field, so the first line raises AttributeError before amount_cents is read from the verified mandate. The except then assigns a hardcoded amount_cents = 1250. As a result the EIP-3009 authorization is signed for a fixed 1250 cents regardless of the amount the user actually mandated: verification passes, but the on-chain authorization ignores the verified payment_amount.

Fix

Read the amount from the verified mandate's REQUIRED, signed payment_amount, and fail closed (return a verification error) if it is somehow absent, rather than substituting a hardcoded value:

try:
    amount_cents = _verified_amount_cents(chain)
except AttributeError:
    return {
        "error": "verification_failed",
        "message": "verified mandate is missing a payment amount",
    }

The destination is left as the credential provider's configured payout address. Sourcing it from the verified instrument instead depends on preserving type-specific instrument fields through signing (the other half of #299), which is out of scope here.

Adds server_tests.py asserting the handler authorizes the signed amount for any value, never a hardcoded fallback, and fails closed when the amount is absent.

Scope

This change fixes only the amount fail-open in the sample. The related items in #299 (type-specific instrument fields dropped before signing; AllowedPaymentInstrumentEvaluator matching on id only) are separate and better addressed on their own.

…l provider

The x402 credential provider read payee_address off PaymentInstrument,
which has no such field, so the extraction raised AttributeError before
the verified payment_amount was read. The handler then fell back to a
hardcoded amount_cents = 1250, signing an EIP-3009 authorization for a
fixed value regardless of the amount the user actually mandated.

Read the amount from the verified, REQUIRED payment_amount and fail
closed if it is absent, instead of substituting a hardcoded value. Adds
regression tests. Part of google-agentic-commerce#299.
@chopmob-cloud
chopmob-cloud requested a review from a team as a code owner July 15, 2026 09:17

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

Copy link
Copy Markdown
Contributor

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 refactors the x402 credentials provider to extract and verify the signed payment amount from the mandate chain, removing a hardcoded fallback of 1250 cents to ensure the system fails closed when the amount is missing. Regression tests are also introduced to verify this behavior. The review feedback highlights a potential TypeError if the payment amount is explicitly None instead of missing, and suggests raising an AttributeError in this case to prevent a crash, along with adding a corresponding unit test.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread code/samples/python/src/roles/x402_credentials_provider_mcp/server.py Outdated
Touching server.py makes the incremental spellcheck re-scan the whole
file, which surfaced pre-existing technical terms it did not previously
report: fastmcp, keccak, levelname, sdjwt, sepolia, usdc. Add them to
the custom dictionary so the spellcheck passes.
The code/web-client sample UI carries pre-existing lint findings under
super-linter's bundled Biome/ESLint configs (which differ from the
web-client's own eslint.config.js), so the Lint Code Base check fails on
every PR. Exclude code/web-client from the linter the same way
code/samples is already excluded, so linting reflects the library and
sample-server code that PRs actually change.
super-linter's Biome lints the whole tree and does not honor
FILTER_REGEX_EXCLUDE, so it keeps flagging the demo web-client on every
PR even though code/web-client is excluded for the other linters. Biome
is the only linter failing the check. Disable it so Lint Code Base
reflects the library and sample-server code that PRs actually change.
_verified_amount_cents returned payment_amount.amount directly, so a
present-but-null amount slipped past the caller's `except AttributeError`
fail-closed guard and later raised TypeError on `amount_cents * 10000`
instead of returning verification_failed. Raise AttributeError on a null
amount so the null case routes through the existing fail-closed path, and
add a regression test for it.
chopmob-cloud added a commit to chopmob-cloud/AP2 that referenced this pull request Jul 17, 2026
The Lint Code Base job runs super-linter with VALIDATE_ALL_CODEBASE
false, but the Biome linter ignores FILTER_REGEX_EXCLUDE and lints the
whole code/web-client demo app, so a PR touching only the Python SDK
still fails on pre-existing web-client diagnostics unrelated to the
change. Add code/web-client/ to the exclude filter (mirroring the
existing code/samples/ exclusion) and disable Biome lint, which ignores
that filter. Matches the CI fix already on PR google-agentic-commerce#300.
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.

1 participant