defuse_core/payload/
multi.rs1use defuse_crypto::{Payload, SignedPayload};
2use defuse_erc191::SignedErc191Payload;
3use defuse_nep413::SignedNep413Payload;
4use defuse_sep53::SignedSep53Payload;
5use defuse_tip191::SignedTip191Payload;
6use defuse_ton_connect::SignedTonConnectPayload;
7use derive_more::derive::From;
8use near_sdk::{CryptoHash, near, serde::de::DeserializeOwned, serde_json};
9
10use crate::public_key::PublicKey;
11
12use super::{
13 DefusePayload, ExtractDefusePayload, raw::SignedRawEd25519Payload,
14 webauthn::SignedWebAuthnPayload,
15};
16
17#[near(serializers = [json])]
18#[serde(tag = "standard", rename_all = "snake_case")]
19#[derive(Debug, Clone, From)]
20pub enum MultiPayload {
28 Nep413(SignedNep413Payload),
31
32 Erc191(SignedErc191Payload),
35
36 Tip191(SignedTip191Payload),
39
40 RawEd25519(SignedRawEd25519Payload),
43
44 #[serde(rename = "webauthn")]
47 WebAuthn(SignedWebAuthnPayload),
48
49 TonConnect(SignedTonConnectPayload),
52
53 Sep53(SignedSep53Payload),
56}
57
58impl Payload for MultiPayload {
59 #[inline]
64 fn hash(&self) -> CryptoHash {
65 match self {
66 Self::Nep413(payload) => payload.hash(),
67 Self::Erc191(payload) => payload.hash(),
68 Self::Tip191(payload) => payload.hash(),
69 Self::RawEd25519(payload) => payload.hash(),
70 Self::WebAuthn(payload) => payload.hash(),
71 Self::TonConnect(payload) => payload.hash(),
72 Self::Sep53(payload) => payload.hash(),
73 }
74 }
75}
76
77impl SignedPayload for MultiPayload {
78 type PublicKey = PublicKey;
79
80 #[inline]
81 fn verify(&self) -> Option<Self::PublicKey> {
82 match self {
83 Self::Nep413(payload) => payload.verify().map(PublicKey::Ed25519),
84 Self::Erc191(payload) => payload.verify().map(PublicKey::Secp256k1),
85 Self::Tip191(payload) => payload.verify().map(PublicKey::Secp256k1),
86 Self::RawEd25519(payload) => payload.verify().map(PublicKey::Ed25519),
87 Self::WebAuthn(payload) => payload.verify(),
88 Self::TonConnect(payload) => payload.verify().map(PublicKey::Ed25519),
89 Self::Sep53(payload) => payload.verify().map(PublicKey::Ed25519),
90 }
91 }
92}
93
94impl<T> ExtractDefusePayload<T> for MultiPayload
95where
96 T: DeserializeOwned,
97{
98 type Error = serde_json::Error;
99
100 #[inline]
101 fn extract_defuse_payload(self) -> Result<DefusePayload<T>, Self::Error> {
102 match self {
103 Self::Nep413(payload) => payload.extract_defuse_payload(),
104 Self::Erc191(payload) => payload.extract_defuse_payload(),
105 Self::Tip191(payload) => payload.extract_defuse_payload(),
106 Self::RawEd25519(payload) => payload.extract_defuse_payload(),
107 Self::WebAuthn(payload) => payload.extract_defuse_payload(),
108 Self::TonConnect(payload) => payload.extract_defuse_payload(),
109 Self::Sep53(payload) => payload.extract_defuse_payload(),
110 }
111 }
112}
113
114#[cfg(test)]
115mod tests {
116 use near_sdk::bs58;
117
118 use super::*;
119
120 #[test]
121 fn raw_ed25519() {
122 let p: MultiPayload = serde_json::from_str(r#"{"standard":"raw_ed25519","payload":"{\"signer_id\":\"74affa71ab030d400fdfa1bed033dfa6fd3ae34f92d17c046ebe368e80d53751\",\"verifying_contract\":\"intents.near\",\"deadline\":{\"timestamp\":1732035219},\"nonce\":\"XVoKfmScb3G+XqH9ke/fSlJ/3xO59sNhCxhpG821BH8=\",\"intents\":[{\"intent\":\"token_diff\",\"diff\":{\"nep141:base-0x833589fcd6edb6e08f4c7c32d4f71b54bda02913.omft.near\":\"-1000\",\"nep141:eth-0xdac17f958d2ee523a2206206994597c13d831ec7.omft.near\":\"998\"}}]}","public_key":"ed25519:8rVvtHWFr8hasdQGGD5WiQBTyr4iH2ruEPPVfj491RPN","signature":"ed25519:3vtbNQJHZfuV1s5DykzyjkbNLc583hnkrhTz57eDhd966iqzkor6Twgr4Loh2C195SCSEsiGfrd6KcxpjNq9ZbVj"}"#).unwrap();
123 assert_eq!(
124 bs58::encode(p.hash()).into_string(),
125 "8LKE47o44ybZQR9ozLyDnvMDTh4Ao5ipy2mJWsYByG5Q"
126 );
127 assert_eq!(
128 p.verify().unwrap(),
129 "ed25519:8rVvtHWFr8hasdQGGD5WiQBTyr4iH2ruEPPVfj491RPN"
130 .parse()
131 .unwrap()
132 );
133 }
134}