1use core::fmt::Display;
2
3use defuse_crypto::{CryptoHash, Curve, Ed25519, Payload, SignedPayload, serde::AsCurve};
4use defuse_near_utils::UnwrapOrPanicError;
5use defuse_nep461::{OffchainMessage, SignedMessageNep};
6use defuse_serde_utils::base64::Base64;
7use impl_tools::autoimpl;
8use near_sdk::{borsh, env, near};
9use serde_with::serde_as;
10
11#[near(serializers = [borsh, json])]
13#[serde(rename_all = "camelCase")]
14#[derive(Debug, Clone)]
15pub struct Nep413Payload {
16 pub message: String,
17
18 #[serde_as(as = "Base64")]
19 pub nonce: [u8; 32],
20
21 pub recipient: String,
22
23 #[serde(default, skip_serializing_if = "Option::is_none")]
24 pub callback_url: Option<String>,
25}
26
27impl SignedMessageNep for Nep413Payload {
28 const NEP_NUMBER: u32 = 413;
29}
30
31impl Nep413Payload {
32 #[inline]
33 pub fn new(message: String) -> Self {
34 Self {
35 message,
36 nonce: Default::default(),
37 recipient: String::new(),
38 callback_url: None,
39 }
40 }
41
42 #[must_use]
43 #[inline]
44 pub const fn with_nonce(mut self, nonce: [u8; 32]) -> Self {
45 self.nonce = nonce;
46 self
47 }
48
49 #[must_use]
50 #[inline]
51 pub fn with_recipient<S>(mut self, recipient: S) -> Self
52 where
53 S: Display,
54 {
55 self.recipient = recipient.to_string();
56 self
57 }
58
59 #[must_use]
60 #[inline]
61 pub fn with_callback_url(mut self, callback_url: String) -> Self {
62 self.callback_url = Some(callback_url);
63 self
64 }
65
66 #[inline]
67 pub fn prehash(&self) -> Vec<u8> {
68 borsh::to_vec(&(Self::OFFCHAIN_PREFIX_TAG, self)).unwrap_or_panic_display()
69 }
70}
71
72impl Payload for Nep413Payload {
73 #[inline]
74 fn hash(&self) -> CryptoHash {
75 env::sha256_array(self.prehash())
76 }
77}
78
79#[near(serializers = [json])]
80#[autoimpl(Deref using self.payload)]
81#[derive(Debug, Clone)]
82pub struct SignedNep413Payload {
83 pub payload: Nep413Payload,
84
85 #[serde_as(as = "AsCurve<Ed25519>")]
86 pub public_key: <Ed25519 as Curve>::PublicKey,
87 #[serde_as(as = "AsCurve<Ed25519>")]
88 pub signature: <Ed25519 as Curve>::Signature,
89}
90
91impl Payload for SignedNep413Payload {
92 #[inline]
93 fn hash(&self) -> CryptoHash {
94 self.payload.hash()
95 }
96}
97
98impl SignedPayload for SignedNep413Payload {
99 type PublicKey = <Ed25519 as Curve>::PublicKey;
100
101 #[inline]
102 fn verify(&self) -> Option<Self::PublicKey> {
103 Ed25519::verify(&self.signature, &self.hash(), &self.public_key)
104 }
105}