{
  "description": "Conformance vectors for the x402 Signed Offers and Receipts extension, EIP-712 format (secp256k1). Complements the JWS vectors in x402-foundation/x402#3207, which cover the other format of the same extension. Deterministic and regenerable byte for byte. The signing key is a TEST key whose seed is published here on purpose; it has never signed a real artifact.",
  "version": 2,
  "spec": "x402-foundation/x402 specs/extensions/extension-offer-and-receipt.md",
  "format": "eip712",
  "how_to_use": {
    "key": "Recover the signer and compare against signing.address. Do not resolve a DID; this key is deliberately published in no DID document, because a test key inside a trust anchor is a foothold rather than a convenience.",
    "schema": "Take types and primaryType from the specification, never from the artifact. One vector transmits them precisely to check you ignore them.",
    "conformance": "A conformant verifier ACCEPTS every entry under valid and REJECTS every entry under invalid. reject_at names the layer we expect to catch it; catching it at a different layer is still conformant. Accepting is never conformant.",
    "recovery_note": "With ECDSA recovery there is no such thing as a failed signature for a well-formed 65-byte value: it always recovers SOME address. So an altered payload, a wrong domain chainId and a wrong domain name all surface as a recovered signer that is not the expected one, which is an authorization failure rather than a signature failure. reject_at says signature for those because that is the layer conceptually at fault; an implementation reporting them as unauthorized is behaving correctly. What matters is that it does not accept them.",
    "authorization": "offer_signed_by_unauthorized_key has a valid signature. It must still be rejected, on authorization. Report signature validity and signer authorization as two separate answers, or you cannot express this case.",
    "time": "Fixed and deterministic. Only offer_valid (live until 2100) and offer_expired_but_wellformed (expired 2024) depend on the clock, and both say so."
  },
  "constants": {
    "note": "Independently derivable from the EIP-712 definition; check yours against these first, because if a domain separator disagrees nothing else will match either.",
    "domainSeparator": {
      "offer": "0x5dc92544087ab60aa57c539b9543f9282416b0dcf2c2ae0d4d0051052a9e61b6",
      "receipt": "0xfd7f8c81cdd24b25c99ba22e191cee41d8809abbc12e8fdbd42fddfa5bb9e406"
    },
    "canonicalType": {
      "note": "The exact strings the type hashes are the keccak of. Published because a type hash cannot be checked without them, and because a verifier that accepts a sender-supplied schema is then a conformance failure someone can point at rather than a design opinion. Byte exact: no spaces after the commas.",
      "offer": "Offer(uint256 version,string resourceUrl,string scheme,string network,string asset,string payTo,string amount,uint256 validUntil)",
      "receipt": "Receipt(uint256 version,string network,string resourceUrl,string payer,uint256 issuedAt,string transaction)"
    },
    "typeHash": {
      "offer": "0x85143d3249b5e62ed5edd3d59a352d4e1181c775ff4f762f9c8a617f6bf1e97d",
      "receipt": "0x616944bc4bb51b3d5fcbba8c559f76d57a93ac1e0d6659f1abbe95f92300c06f"
    },
    "domain": {
      "offer": {
        "name": "x402 offer",
        "version": "1",
        "chainId": 1
      },
      "receipt": {
        "name": "x402 receipt",
        "version": "1",
        "chainId": 1
      }
    }
  },
  "signing": {
    "algorithm": "EIP-712 typed data, secp256k1",
    "test_seed_hex": "0x1111111111111111111111111111111111111111111111111111111111111111",
    "address": "0x19E7E376E7C213B7E7e7e46cc70A5dD086DAff2A",
    "unauthorized_test_seed_hex": "0x7777777777777777777777777777777777777777777777777777777777777777",
    "unauthorized_address": "0xAe72A48c1a36bd18Af168541c53037965d26e4A8",
    "note": "Both keys are test keys, published on purpose. Neither has signed a real artifact."
  },
  "types": {
    "Offer": [
      {
        "name": "version",
        "type": "uint256"
      },
      {
        "name": "resourceUrl",
        "type": "string"
      },
      {
        "name": "scheme",
        "type": "string"
      },
      {
        "name": "network",
        "type": "string"
      },
      {
        "name": "asset",
        "type": "string"
      },
      {
        "name": "payTo",
        "type": "string"
      },
      {
        "name": "amount",
        "type": "string"
      },
      {
        "name": "validUntil",
        "type": "uint256"
      }
    ],
    "Receipt": [
      {
        "name": "version",
        "type": "uint256"
      },
      {
        "name": "network",
        "type": "string"
      },
      {
        "name": "resourceUrl",
        "type": "string"
      },
      {
        "name": "payer",
        "type": "string"
      },
      {
        "name": "issuedAt",
        "type": "uint256"
      },
      {
        "name": "transaction",
        "type": "string"
      }
    ]
  },
  "mandated_empty": {
    "note": "The rule that omission is not permitted, stated as hashes rather than as prose. A fixed EIP-712 schema cannot express absence, so the extension signs the optional fields at their empty values. These are the struct hashes of exactly that: an offer whose validUntil is 0, and a receipt whose transaction is the empty string. An implementation that omits the field instead produces no comparable hash at all, because encodeData has nothing to encode for it.",
    "rule": "Omission is NOT permitted. validUntil absent signs as 0; transaction absent signs as the empty string.",
    "offer_validUntil_zero": {
      "message": {
        "version": 1,
        "resourceUrl": "https://api.example.com/premium-data",
        "scheme": "exact",
        "network": "eip155:8453",
        "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
        "payTo": "0x209693Bc6afc0C5328bA36FaF03C514EF312287C",
        "amount": "10000",
        "validUntil": 0
      },
      "structHash": "0xc3ed9ea9eb4ad7ffd1206a4655884382e4d976d00944c3c8fe440dab86917602"
    },
    "receipt_transaction_empty": {
      "message": {
        "version": 1,
        "network": "eip155:8453",
        "resourceUrl": "https://api.example.com/premium-data",
        "payer": "0x857b06519E91e3A54538791bDbb0E22373e36b66",
        "issuedAt": 1703123456,
        "transaction": ""
      },
      "structHash": "0x25ef64528ef742f3d41e9e5d8d4cf50a6305c50655d3a1cfa97de0b54a57dd06"
    },
    "keccak_of_empty_string": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"
  },
  "valid": [
    {
      "name": "offer_valid",
      "structHash": "0x8ed912a662ce39849c16d8749725ce99b712b20d202530ff6f9245c278a93d40",
      "kind": "offer",
      "expect": "accept",
      "note": "Standard offer. validUntil is 2100 so the set never goes stale.",
      "artifact": {
        "format": "eip712",
        "payload": {
          "version": 1,
          "resourceUrl": "https://api.example.com/premium-data",
          "scheme": "exact",
          "network": "eip155:8453",
          "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
          "payTo": "0x209693Bc6afc0C5328bA36FaF03C514EF312287C",
          "amount": "10000",
          "validUntil": 4102444800
        },
        "signature": "0x65147e45d8b827c5fe065e5457b53ad9564261558a268cca377325b9309905e903f925ec512b6b88610c036584df60486882454d2ef3998b5e4c97dec7f767641c",
        "acceptIndex": 0
      }
    },
    {
      "name": "receipt_valid_privacy_minimal",
      "structHash": "0x25ef64528ef742f3d41e9e5d8d4cf50a6305c50655d3a1cfa97de0b54a57dd06",
      "kind": "receipt",
      "expect": "accept",
      "note": "transaction is the mandated empty string, which a verifier must treat as absence.",
      "artifact": {
        "format": "eip712",
        "payload": {
          "version": 1,
          "network": "eip155:8453",
          "resourceUrl": "https://api.example.com/premium-data",
          "payer": "0x857b06519E91e3A54538791bDbb0E22373e36b66",
          "issuedAt": 1703123456,
          "transaction": ""
        },
        "signature": "0x4706839f7698eb73f12a381dcb62fb6d9e6e6717e2af17c056c3f00b8be1cf9f32abb2b57807f2179e5ab8284e2d79b6e37418426f70105c287f8dfae804abbb1c"
      }
    },
    {
      "name": "receipt_valid_with_transaction",
      "structHash": "0xbbc17a1846a7f726a66e9e23e19d8e04a591d5e104ca0a7cffc4666a521480fa",
      "kind": "receipt",
      "expect": "accept",
      "note": "The optional transaction is present, which is the verifiable rather than private choice.",
      "artifact": {
        "format": "eip712",
        "payload": {
          "version": 1,
          "network": "eip155:8453",
          "resourceUrl": "https://api.example.com/premium-data",
          "payer": "0x857b06519E91e3A54538791bDbb0E22373e36b66",
          "issuedAt": 1703123456,
          "transaction": "0xabababababababababababababababababababababababababababababababab"
        },
        "signature": "0x233b1a6ae1a45801376f129251f90480e0ec10eae5fdfac2284f3133fddd0a11683582d3563d4410fcfa227977ee566212b50fb86fcf15676c03784d26e82d4b1b"
      }
    },
    {
      "name": "offer_expired_but_wellformed",
      "structHash": "0x4af478de03815588ea810a6474fbe5cace3263e685f62c54406e922a231346cd",
      "kind": "offer",
      "expect": "accept",
      "note": "The signature is valid and validUntil has passed. Expiry is an enforcement decision for the resource server, not a signature failure. A verifier should report it as expired, not as a bad signature.",
      "artifact": {
        "format": "eip712",
        "payload": {
          "version": 1,
          "resourceUrl": "https://api.example.com/premium-data",
          "scheme": "exact",
          "network": "eip155:8453",
          "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
          "payTo": "0x209693Bc6afc0C5328bA36FaF03C514EF312287C",
          "amount": "10000",
          "validUntil": 1704067200
        },
        "signature": "0x3a9963f2dd372df6ee05c52a5b3f492ee18b2c78e2a01eeba38a0d59e4e9b1430c6be7984866295b2f1645193c0ebd659a2cc81347d6551ecb83e859610fda621c"
      }
    }
  ],
  "invalid": [
    {
      "name": "offer_domain_chain_id_is_payment_network",
      "kind": "offer",
      "expect": "reject",
      "reject_at": "signature",
      "note": "THE trap of this format. Signed with chainId 8453 because the payment settles on Base. The extension hardcodes chainId 1: the payment network already travels in the payload. An implementation that makes this mistake verifies its own artifacts perfectly and nobody else's.",
      "artifact": {
        "format": "eip712",
        "payload": {
          "version": 1,
          "resourceUrl": "https://api.example.com/premium-data",
          "scheme": "exact",
          "network": "eip155:8453",
          "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
          "payTo": "0x209693Bc6afc0C5328bA36FaF03C514EF312287C",
          "amount": "10000",
          "validUntil": 4102444800
        },
        "signature": "0x0fff22e167631ce0d12e0cf9c7d21d20ebc6fda43e8d52e458c92f3d4dbededb430516d811511976848fc2ef2785f924353ad6cdf7904cd51a4c67c34e03a0661b"
      }
    },
    {
      "name": "offer_amount_altered_after_signing",
      "kind": "offer",
      "expect": "reject",
      "reject_at": "signature",
      "note": "Signature over amount 10000, payload says 1.",
      "artifact": {
        "format": "eip712",
        "payload": {
          "version": 1,
          "resourceUrl": "https://api.example.com/premium-data",
          "scheme": "exact",
          "network": "eip155:8453",
          "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
          "payTo": "0x209693Bc6afc0C5328bA36FaF03C514EF312287C",
          "amount": "1",
          "validUntil": 4102444800
        },
        "signature": "0x65147e45d8b827c5fe065e5457b53ad9564261558a268cca377325b9309905e903f925ec512b6b88610c036584df60486882454d2ef3998b5e4c97dec7f767641c"
      }
    },
    {
      "name": "offer_signed_by_unauthorized_key",
      "kind": "offer",
      "expect": "reject",
      "reject_at": "authorization",
      "note": "A genuinely valid signature by a key with no relationship to resourceUrl. This is the attack the extension names: signature validity is not signer authorization. A verifier that returns only a boolean for 'valid' cannot express this and will accept it.",
      "artifact": {
        "format": "eip712",
        "payload": {
          "version": 1,
          "resourceUrl": "https://api.example.com/premium-data",
          "scheme": "exact",
          "network": "eip155:8453",
          "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
          "payTo": "0x209693Bc6afc0C5328bA36FaF03C514EF312287C",
          "amount": "10000",
          "validUntil": 4102444800
        },
        "signature": "0x078a9efd6e46e730ac693b5c248d212340fe346be7c83094f7adddf69b5aca2a213e7ad1093f765ab03bd4c57233076a8a8988c004dda88eba787af815bd0ae01c"
      }
    },
    {
      "name": "offer_optional_field_omitted_not_zeroed",
      "kind": "offer",
      "expect": "reject",
      "reject_at": "schema",
      "note": "validUntil is absent rather than 0. A fixed EIP-712 schema cannot express absence, so the extension mandates the empty value.",
      "artifact": {
        "format": "eip712",
        "payload": {
          "version": 1,
          "resourceUrl": "https://api.example.com/premium-data",
          "scheme": "exact",
          "network": "eip155:8453",
          "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
          "payTo": "0x209693Bc6afc0C5328bA36FaF03C514EF312287C",
          "amount": "10000"
        },
        "signature": "0x65147e45d8b827c5fe065e5457b53ad9564261558a268cca377325b9309905e903f925ec512b6b88610c036584df60486882454d2ef3998b5e4c97dec7f767641c"
      }
    },
    {
      "name": "receipt_optional_field_omitted_not_empty",
      "kind": "receipt",
      "expect": "reject",
      "reject_at": "schema",
      "note": "transaction is absent rather than the empty string. Included because a verifier with no receipt-side schema check passes every offer-only vector.",
      "artifact": {
        "format": "eip712",
        "payload": {
          "version": 1,
          "network": "eip155:8453",
          "resourceUrl": "https://api.example.com/premium-data",
          "payer": "0x857b06519E91e3A54538791bDbb0E22373e36b66",
          "issuedAt": 1703123456
        },
        "signature": "0x4706839f7698eb73f12a381dcb62fb6d9e6e6717e2af17c056c3f00b8be1cf9f32abb2b57807f2179e5ab8284e2d79b6e37418426f70105c287f8dfae804abbb1c"
      }
    },
    {
      "name": "offer_domain_name_wrong_case",
      "kind": "offer",
      "expect": "reject",
      "reject_at": "signature",
      "note": "Signed under 'x402 Offer'. The domain name is exact and case sensitive.",
      "artifact": {
        "format": "eip712",
        "payload": {
          "version": 1,
          "resourceUrl": "https://api.example.com/premium-data",
          "scheme": "exact",
          "network": "eip155:8453",
          "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
          "payTo": "0x209693Bc6afc0C5328bA36FaF03C514EF312287C",
          "amount": "10000",
          "validUntil": 4102444800
        },
        "signature": "0xc18f4dd7128720c8b9923bed9403c14a498a161459038b2668d58dbf5b7338a2654ebdce5220ea7f5d2905d9009d652e5ee0f5c9774ee48828ffe40c52b8b0ca1c"
      }
    },
    {
      "name": "offer_signature_truncated",
      "kind": "offer",
      "expect": "reject",
      "reject_at": "parse",
      "note": "Four bytes short of 65.",
      "artifact": {
        "format": "eip712",
        "payload": {
          "version": 1,
          "resourceUrl": "https://api.example.com/premium-data",
          "scheme": "exact",
          "network": "eip155:8453",
          "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
          "payTo": "0x209693Bc6afc0C5328bA36FaF03C514EF312287C",
          "amount": "10000",
          "validUntil": 4102444800
        },
        "signature": "0x65147e45d8b827c5fe065e5457b53ad9564261558a268cca377325b9309905e903f925ec512b6b88610c036584df60486882454d2ef3998b5e4c97dec7"
      }
    },
    {
      "name": "offer_signature_v_byte_invalid",
      "kind": "offer",
      "expect": "reject",
      "reject_at": "parse",
      "note": "v is 0x07, which is neither 27 nor 28 nor 0 nor 1.",
      "artifact": {
        "format": "eip712",
        "payload": {
          "version": 1,
          "resourceUrl": "https://api.example.com/premium-data",
          "scheme": "exact",
          "network": "eip155:8453",
          "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
          "payTo": "0x209693Bc6afc0C5328bA36FaF03C514EF312287C",
          "amount": "10000",
          "validUntil": 4102444800
        },
        "signature": "0x65147e45d8b827c5fe065e5457b53ad9564261558a268cca377325b9309905e903f925ec512b6b88610c036584df60486882454d2ef3998b5e4c97dec7f7676407"
      }
    },
    {
      "name": "offer_transmits_a_malicious_schema",
      "kind": "offer",
      "expect": "reject",
      "reject_at": "schema",
      "note": "Carries a MALICIOUS types table on the wire, and a signature that is valid under that table and invalid under the canonical one (validUntil declared string instead of uint256). A verifier that takes the schema from the specification computes a different digest and rejects. A verifier that trusts the transmitted schema accepts, and has let the sender choose which bytes were signed.",
      "artifact": {
        "format": "eip712",
        "payload": {
          "version": 1,
          "resourceUrl": "https://api.example.com/premium-data",
          "scheme": "exact",
          "network": "eip155:8453",
          "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
          "payTo": "0x209693Bc6afc0C5328bA36FaF03C514EF312287C",
          "amount": "10000",
          "validUntil": "4102444800"
        },
        "signature": "0x034fdf31705b46174b56d8b3aa5f43882a64b4577a6371e195a95effd8351a18055a56b4626cdca40b605eefb3942aca8a0c7041a28595f9a4363c906b517a061b",
        "types": {
          "Offer": [
            {
              "name": "version",
              "type": "uint256"
            },
            {
              "name": "resourceUrl",
              "type": "string"
            },
            {
              "name": "scheme",
              "type": "string"
            },
            {
              "name": "network",
              "type": "string"
            },
            {
              "name": "asset",
              "type": "string"
            },
            {
              "name": "payTo",
              "type": "string"
            },
            {
              "name": "amount",
              "type": "string"
            },
            {
              "name": "validUntil",
              "type": "string"
            }
          ]
        },
        "primaryType": "Offer",
        "domain": {
          "name": "x402 offer",
          "version": "1",
          "chainId": 1
        }
      }
    }
  ]
}
