defuse_core/payload/
multi.rs1use derive_more::derive::From;
2use near_sdk::{CryptoHash, serde::de::DeserializeOwned, serde_json};
3use serde::{Deserialize, Serialize};
4use serde_with::serde_as;
5
6use crate::{
7 payload::{
8 Payload, SignedPayload, erc191::SignedErc191Payload, nep413::SignedNep413Payload,
9 sep53::SignedSep53Payload, tip191::SignedTip191Payload,
10 ton_connect::SignedTonConnectPayload,
11 },
12 public_key::PublicKey,
13};
14
15use super::{
16 DefusePayload, ExtractDefusePayload, raw::SignedRawEd25519Payload,
17 webauthn::SignedWebAuthnPayload,
18};
19
20#[serde_as]
21#[cfg_attr(feature = "abi", derive(::schemars::JsonSchema))]
22#[derive(Debug, Clone, Serialize, Deserialize, From)]
23#[serde(tag = "standard", rename_all = "snake_case")]
24pub enum MultiPayload {
32 Nep413(SignedNep413Payload),
35
36 Erc191(SignedErc191Payload),
39
40 Tip191(SignedTip191Payload),
43
44 RawEd25519(SignedRawEd25519Payload),
47
48 #[serde(rename = "webauthn")]
51 WebAuthn(SignedWebAuthnPayload),
52
53 TonConnect(SignedTonConnectPayload),
56
57 Sep53(SignedSep53Payload),
60}
61
62impl Payload for MultiPayload {
63 #[inline]
68 fn hash(&self) -> CryptoHash {
69 match self {
70 Self::Nep413(payload) => payload.hash(),
71 Self::Erc191(payload) => payload.hash(),
72 Self::Tip191(payload) => payload.hash(),
73 Self::RawEd25519(payload) => payload.hash(),
74 Self::WebAuthn(payload) => payload.hash(),
75 Self::TonConnect(payload) => payload.hash(),
76 Self::Sep53(payload) => payload.hash(),
77 }
78 }
79}
80
81impl SignedPayload for MultiPayload {
82 type PublicKey = PublicKey;
83
84 #[inline]
85 fn verify(&self) -> Option<Self::PublicKey> {
86 match self {
87 Self::Nep413(payload) => payload.verify().map(PublicKey::Ed25519),
88 Self::Erc191(payload) => payload.verify().map(PublicKey::Secp256k1),
89 Self::Tip191(payload) => payload.verify().map(PublicKey::Secp256k1),
90 Self::RawEd25519(payload) => payload.verify().map(PublicKey::Ed25519),
91 Self::WebAuthn(payload) => payload.verify(),
92 Self::TonConnect(payload) => payload.verify().map(PublicKey::Ed25519),
93 Self::Sep53(payload) => payload.verify().map(PublicKey::Ed25519),
94 }
95 }
96}
97
98impl<T> ExtractDefusePayload<T> for MultiPayload
99where
100 T: DeserializeOwned,
101{
102 type Error = serde_json::Error;
103
104 #[inline]
105 fn extract_defuse_payload(self) -> Result<DefusePayload<T>, Self::Error> {
106 match self {
107 Self::Nep413(payload) => payload.extract_defuse_payload(),
108 Self::Erc191(payload) => payload.extract_defuse_payload(),
109 Self::Tip191(payload) => payload.extract_defuse_payload(),
110 Self::RawEd25519(payload) => payload.extract_defuse_payload(),
111 Self::WebAuthn(payload) => payload.extract_defuse_payload(),
112 Self::TonConnect(payload) => payload.extract_defuse_payload(),
113 Self::Sep53(payload) => payload.extract_defuse_payload(),
114 }
115 }
116}
117
118#[cfg(test)]
119mod tests {
120 use near_sdk::bs58;
121
122 use super::*;
123
124 #[test]
125 fn raw_ed25519() {
126 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();
127 assert_eq!(
128 bs58::encode(p.hash()).into_string(),
129 "8LKE47o44ybZQR9ozLyDnvMDTh4Ao5ipy2mJWsYByG5Q"
130 );
131 assert_eq!(
132 p.verify().unwrap(),
133 "ed25519:8rVvtHWFr8hasdQGGD5WiQBTyr4iH2ruEPPVfj491RPN"
134 .parse()
135 .unwrap()
136 );
137 }
138}