Problem
Today zap_transport.py (PR #21) decodes the outer ZAP envelope and returns the inner payload as opaque bytes. When the inner payload is itself an x402 envelope (the common case for agent payments — Warp/ZAP wraps x402 to traverse a cross-subnet bridge), callers have to:
- Decode the ZAP frame
- Re-instantiate the x402 decoder on
payload
- Re-parse the x402 envelope
That's two passes over the same byte range and forces every consumer (AgentEscrow, oracle pushers, bridge receipts) to know both wire formats. We should surface nested x402 envelopes in a typed nestedPayload field with a discriminator tag, decoded in a single pass.
Proposed Approach
- Extend the ZAP frame header with a
nested_tag byte:
0x00 = no nesting
0x01 = x402 nested
0x02 = Warp 2.0 nested
0x03..0xFF reserved
- Update
zap_transport.py decode to return a structured tuple (version, scheme, header_digest, payload, nested_tag, nested_payload). When nested_tag != 0x00, nested_payload carries the inner envelope bytes already validated for length-fit.
- The decoder does not recursively decode the x402 envelope — callers that need x402 field access call the existing x402 decoder on
nested_payload. This keeps the wire-layer scope tight and matches the LP-183 precompile's behavior so on-chain and off-chain code see the same shape.
- Round-trip test: build a
Warp(x402(PaymentProof)) frame, decode in one pass, verify all three layers cleanly recoverable.
Acceptance Criteria
References
Problem
Today
zap_transport.py(PR #21) decodes the outer ZAP envelope and returns the inner payload as opaque bytes. When the inner payload is itself an x402 envelope (the common case for agent payments — Warp/ZAP wraps x402 to traverse a cross-subnet bridge), callers have to:payloadThat's two passes over the same byte range and forces every consumer (AgentEscrow, oracle pushers, bridge receipts) to know both wire formats. We should surface nested x402 envelopes in a typed
nestedPayloadfield with a discriminator tag, decoded in a single pass.Proposed Approach
nested_tagbyte:0x00= no nesting0x01= x402 nested0x02= Warp 2.0 nested0x03..0xFFreservedzap_transport.pydecode to return a structured tuple(version, scheme, header_digest, payload, nested_tag, nested_payload). Whennested_tag != 0x00,nested_payloadcarries the inner envelope bytes already validated for length-fit.nested_payload. This keeps the wire-layer scope tight and matches the LP-183 precompile's behavior so on-chain and off-chain code see the same shape.Warp(x402(PaymentProof))frame, decode in one pass, verify all three layers cleanly recoverable.Acceptance Criteria
zap_transport.decode()returns the 6-tuple includingnested_tag+nested_payloadnested_tag == 0x01round-trips againstx402_middlewareparsernested_tag == 0x02reserved field present (decoder accepts; consumer code not required yet)0x03..0xFF) revert cleanly withRESERVED_NESTED_TAGnested_tag == 0x00) round-trip identical to current behaviorReferences