Skip to main content

r402_evm/
asset.rs

1//! Shared EVM transfer-method and validator constants.
2
3use alloy_primitives::{Address, address};
4use serde::{Deserialize, Serialize};
5
6/// Universal signature verifier for EIP-6492, EIP-1271, and EOA signatures.
7///
8/// Deployed at the same address on every supported EVM chain. The exact and
9/// upto facilitators delegate to this contract via
10/// `Validator6492::isValidSigWithSideEffects`; if the validator is missing on
11/// a particular chain, EIP-6492 / EIP-1271 verification will revert and only
12/// EOA signatures will work. Use the `validator_deployed_on_configured_chains`
13/// integration test to confirm presence on every chain you operate.
14///
15/// This address is **r402-specific** (not currently part of the cross-SDK
16/// canonical-address set). Out-of-tree deployments must mirror the bytecode
17/// to maintain interop.
18pub const VALIDATOR_ADDRESS: Address = address!("0xdAcD51A54883eb67D95FAEb2BBfdC4a9a6BD2a3B");
19
20/// Determines which on-chain mechanism is used for token transfers.
21///
22/// Supported by r402-evm:
23/// - `eip3009` ([`AssetTransferMethod::Eip3009`]): `transferWithAuthorization`
24/// - `permit2` ([`AssetTransferMethod::Permit2`]): Permit2 + `x402Permit2Proxy`
25///
26/// Spec also defines **ERC-7710** (`scheme_exact_evm.md` section 3). That path
27/// is **not implemented** here (and is absent from the official Go/TS mechanism
28/// packages as of the vendored foundation tree). Deserialising
29/// `"assetTransferMethod": "erc7710"` (or any other unknown value) fails with
30/// an explicit unsupported-method error rather than a silent untagged-payload
31/// mis-parse.
32#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
33#[serde(rename_all = "camelCase")]
34pub enum AssetTransferMethod {
35    /// EIP-3009 `transferWithAuthorization`.
36    Eip3009,
37    /// Uniswap Permit2 via `x402Permit2Proxy`.
38    Permit2,
39}
40
41impl<'de> Deserialize<'de> for AssetTransferMethod {
42    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
43    where
44        D: serde::Deserializer<'de>,
45    {
46        let raw = String::deserialize(deserializer)?;
47        match raw.as_str() {
48            "eip3009" => Ok(Self::Eip3009),
49            "permit2" => Ok(Self::Permit2),
50            other => Err(serde::de::Error::custom(format!(
51                "unsupported assetTransferMethod `{other}`: r402-evm implements \
52                 eip3009 and permit2 only (ERC-7710 is not implemented)"
53            ))),
54        }
55    }
56}
57
58#[cfg(test)]
59mod transfer_method_tests {
60    use super::AssetTransferMethod;
61
62    #[test]
63    fn serialises_as_camel_case_wire_strings() {
64        assert_eq!(
65            serde_json::to_string(&AssetTransferMethod::Eip3009).unwrap(),
66            "\"eip3009\""
67        );
68        assert_eq!(
69            serde_json::to_string(&AssetTransferMethod::Permit2).unwrap(),
70            "\"permit2\""
71        );
72    }
73
74    #[test]
75    fn deserialises_supported_methods() {
76        assert_eq!(
77            serde_json::from_str::<AssetTransferMethod>("\"eip3009\"").unwrap(),
78            AssetTransferMethod::Eip3009
79        );
80        assert_eq!(
81            serde_json::from_str::<AssetTransferMethod>("\"permit2\"").unwrap(),
82            AssetTransferMethod::Permit2
83        );
84    }
85
86    #[test]
87    fn rejects_erc7710_with_explicit_message() {
88        let err = serde_json::from_str::<AssetTransferMethod>("\"erc7710\"").unwrap_err();
89        let msg = err.to_string();
90        assert!(
91            msg.contains("unsupported assetTransferMethod `erc7710`"),
92            "unexpected error: {msg}"
93        );
94        assert!(
95            msg.contains("ERC-7710 is not implemented"),
96            "unexpected error: {msg}"
97        );
98    }
99
100    #[test]
101    fn rejects_unknown_method() {
102        let err = serde_json::from_str::<AssetTransferMethod>("\"somethingElse\"").unwrap_err();
103        assert!(err.to_string().contains("unsupported assetTransferMethod"));
104    }
105}