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