defuse_core/payload/
multi.rs1use defuse_crypto::{Payload, PublicKey, 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 super::{
11 DefusePayload, ExtractDefusePayload, raw::SignedRawEd25519Payload,
12 webauthn::SignedWebAuthnPayload,
13};
14
15#[near(serializers = [json])]
16#[serde(tag = "standard", rename_all = "snake_case")]
17#[derive(Debug, Clone, From)]
18pub enum MultiPayload {
26 Nep413(SignedNep413Payload),
29
30 Erc191(SignedErc191Payload),
33
34 Tip191(SignedTip191Payload),
37
38 RawEd25519(SignedRawEd25519Payload),
41
42 #[serde(rename = "webauthn")]
45 WebAuthn(SignedWebAuthnPayload),
46
47 TonConnect(SignedTonConnectPayload),
50
51 Sep53(SignedSep53Payload),
54}
55
56impl Payload for MultiPayload {
57 #[inline]
62 fn hash(&self) -> CryptoHash {
63 match self {
64 Self::Nep413(payload) => payload.hash(),
65 Self::Erc191(payload) => payload.hash(),
66 Self::Tip191(payload) => payload.hash(),
67 Self::RawEd25519(payload) => payload.hash(),
68 Self::WebAuthn(payload) => payload.hash(),
69 Self::TonConnect(payload) => payload.hash(),
70 Self::Sep53(payload) => payload.hash(),
71 }
72 }
73}
74
75impl SignedPayload for MultiPayload {
76 type PublicKey = PublicKey;
77
78 #[inline]
79 fn verify(&self) -> Option<Self::PublicKey> {
80 match self {
81 Self::Nep413(payload) => payload.verify().map(PublicKey::Ed25519),
82 Self::Erc191(payload) => payload.verify().map(PublicKey::Secp256k1),
83 Self::Tip191(payload) => payload.verify().map(PublicKey::Secp256k1),
84 Self::RawEd25519(payload) => payload.verify().map(PublicKey::Ed25519),
85 Self::WebAuthn(payload) => payload.verify(),
86 Self::TonConnect(payload) => payload.verify().map(PublicKey::Ed25519),
87 Self::Sep53(payload) => payload.verify().map(PublicKey::Ed25519),
88 }
89 }
90}
91
92impl<T> ExtractDefusePayload<T> for MultiPayload
93where
94 T: DeserializeOwned,
95{
96 type Error = serde_json::Error;
97
98 #[inline]
99 fn extract_defuse_payload(self) -> Result<DefusePayload<T>, Self::Error> {
100 match self {
101 Self::Nep413(payload) => payload.extract_defuse_payload(),
102 Self::Erc191(payload) => payload.extract_defuse_payload(),
103 Self::Tip191(payload) => payload.extract_defuse_payload(),
104 Self::RawEd25519(payload) => payload.extract_defuse_payload(),
105 Self::WebAuthn(payload) => payload.extract_defuse_payload(),
106 Self::TonConnect(payload) => payload.extract_defuse_payload(),
107 Self::Sep53(payload) => payload.extract_defuse_payload(),
108 }
109 }
110}
111
112#[cfg(test)]
113mod tests {
114 use near_sdk::bs58;
115
116 use super::*;
117
118 #[test]
119 fn raw_ed25519() {
120 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();
121 assert_eq!(
122 bs58::encode(p.hash()).into_string(),
123 "8LKE47o44ybZQR9ozLyDnvMDTh4Ao5ipy2mJWsYByG5Q"
124 );
125 assert_eq!(
126 p.verify().unwrap(),
127 "ed25519:8rVvtHWFr8hasdQGGD5WiQBTyr4iH2ruEPPVfj491RPN"
128 .parse()
129 .unwrap()
130 );
131 }
132}