feat(python/batch-settlement): add foundation (PR1)#2199
Open
shuhei0866 wants to merge 2 commits intox402-foundation:mainfrom
Open
feat(python/batch-settlement): add foundation (PR1)#2199shuhei0866 wants to merge 2 commits intox402-foundation:mainfrom
shuhei0866 wants to merge 2 commits intox402-foundation:mainfrom
Conversation
…1 gate) Python port of x402-foundation#2061 (batch-settlement TS SDK), introduced as PR1 of a stacked series. This PR ships only the dependency foundation; the wire interface (Pydantic models, EIP-712 digest cross-language fixtures) lands in subsequent PRs. - mechanisms/evm/batch_settlement/{__init__,constants,abi}.py: scheme identifier, contract addresses, EIP-712 type definitions, and the contract ABI, mirroring the TypeScript SDK verbatim. - tests/unit/mechanisms/evm/batch_settlement/{test_constants,test_abi}.py: 20 self-consistency tests (field ordering, EIP-55 checksum, TYPEHASH canonical signature, ABI function/event names). - scripts/check.sh: Layer 1 universal gate (ruff / mypy --follow-imports=silent / pytest / commit signing warn / towncrier fragment). - changelog.d/+batch-settlement-foundation.feature.md: towncrier issueless fragment, renamed once the PR number is assigned. Refs: x402-foundation#2061 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds the wire interface for the batch-settlement mechanism, mirroring the TypeScript ``types.ts``. Per the pre-existing x402 SDK convention, wire-level invariants (XOR deposit auth, hex format, integer-as-string, EIP-712 byte equivalence) are enforced through cross-language fixture tests (Layer 2 invariants) rather than Pydantic Annotated validators or discriminated unions, keeping consistency with the ``exact`` / ``upto`` mechanisms. - mechanisms/evm/batch_settlement/types.py: 18 wire models inheriting ``BaseX402Model``, two Union type aliases (BatchSettlementPayload / BatchSettlementFacilitatorSettlePayload), and ``parse_payload`` / ``parse_facilitator_payload`` helpers performing manual ``type`` discrimination plus XOR auth validation. Module docstring documents wire spec conventions (uint256 → str, uint40 → int) and the ``extra="ignore"`` policy. - tests/unit/mechanisms/evm/batch_settlement/test_types.py: 36 tests covering camelCase ↔ snake_case round-trips, ``from``/``from_`` alias handling, optional 三状態 (absent/null/present), manual discrimination, XOR auth, large-integer round-trip without IntStr, and the ``extra="ignore"`` wire contract. - mechanisms/evm/batch_settlement/__init__.py: re-export the wire types and parse helpers. The ``AuthorizerSigner`` Protocol, ``encoding.py``, ``utils.py``, and the TypeScript-side fixture generator are deferred to subsequent stacked PRs. Refs: x402-foundation#2061 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
@shuhei0866 is attempting to deploy a commit to the Coinbase Team on Vercel. A member of the Team first needs to authorize it. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This is part 1 of a planned 13-PR Python port of
@x402/evm/batch-settlement(TS PR #2061). It delivers the wire-level foundation that subsequent PRs will build on: constants, ABI, and 18 Pydantic wire-format models with manual discriminator/XOR helpers.Per our intent comment on #2061, this opens the series.
Stacking strategy & branch request
We would like to land this as a stacked PR series into a long-lived
feat/batch-settlement-python-sdkbranch on upstream, mirroring two existing precedents in this repo:feat/python-v2-sdk— Coinbase ran a 16-PR stacked series (2025-12-29 → 2026-01-21) into this branch to land Python SDK v2. External and internal PRs were both accepted there.feat/batch-settlement-go-sdk— sibling Go-language port currently in progress under the same naming convention.If a
feat/batch-settlement-python-sdkbranch is created, we'll rebase this PR onto it and continue with PR2-PR13 stacked. If you'd prefer a different shape (sequential into main, or fewer larger PRs), happy to adapt — flagging this up front so we can align before review effort accumulates.What's in PR1
Wire decisions affirmed
PR1 locks down 12 wire-level decisions to keep subsequent PR review focused on behavior. Statement of intent:
Notable D7/D8 implementation note: Pydantic v2's
Field(discriminator=)does not allow two models in a Union to share the sameLiteralvalue. The batch-settlement wire has bothBatchSettlementRefundPayload(client) andBatchSettlementEnrichedRefundPayload(facilitator) carryingtype: "refund", so we route them via manual helpers (parse_payload/parse_facilitator_payload) — also keeping consistency withexact/uptowhich use noField(discriminator=).BaseX402ModelT | None = None+ callerexclude_none=Truenormalize_address()parse_payload_validate_deposit_xorTest plan
Notable test vectors:
test_large_integer_round_trips_as_str(D1):"123456789012345678901234567890"survivesmodel_dump → model_validateas str — demonstrates no IntStr alias neededtest_payload_round_trip_is_stable(D4/D5): parametrized over 5 fixtures (deposit / voucher / refund / claim / settle);model_dump(by_alias=True, exclude_none=True)round-trips losslesslytest_validate_deposit_xor(D8): all 4 combinations (erc3009-only / permit2-only / both / neither)Roadmap
Re-architected by reviewer-concern: each PR has one Yes/No claim the reviewer verifies. LOC is now a sanity check, not a scoping input.
Note on Layer 2 invariants split: L2.1-L2.6 are byte-level (EIP-712 digests × 4, ERC-3009 deposit nonce, collectorData ABI encoding) and land in PR2 with cross-language fixtures. L2.7-L2.11 are type-level (JSON roundtrip, payload discriminator, deposit XOR, optional field tri-state, large integer serialization) and are already covered by this PR's 36 unit tests in
test_types.py.Open questions
enrich-payment-required-responseflow (TShandleEnrichPaymentRequiredResponseequivalent) — investigating whether mutatingVerifyFailureContext.extrafromon_verify_failureis sufficient, or whether a smallon_enrich_responsecore hook (~30 LOC) is needed. Resolution targeted in PR2.recovery.tsleaves it caller-responsibility. Will propose in PR7 description.References
typescript/packages/mechanisms/evm/src/batch-settlement/(PR Batch-settlement TS sdk #2061)feat/python-v2-sdkfeat/batch-settlement-go-sdkcc @phdargen @CarsonRoscoe