defuse_ton_connect/schema/
mod.rs1use core::str;
2use std::borrow::Cow;
3use std::fmt::Debug;
4
5use near_sdk::near;
6use tlb_ton::{MsgAddress, StringError};
7
8#[cfg(feature = "binary")]
9mod binary;
10#[cfg(feature = "cell")]
11mod cell;
12#[cfg(feature = "text")]
13mod text;
14
15pub struct TonConnectPayloadContext<'a> {
16 pub address: MsgAddress,
17 pub domain: Cow<'a, str>,
18 pub timestamp: u64,
19}
20
21impl TonConnectPayloadContext<'_> {
22 #[cfg(any(feature = "binary", feature = "text"))]
24 pub fn create_payload_hash(
25 &self,
26 payload_prefix: &[u8],
27 payload: &[u8],
28 ) -> Result<near_sdk::CryptoHash, StringError> {
29 let domain_len = u32::try_from(self.domain.len())
30 .map_err(|_| tlb_ton::Error::custom("domain: overflow"))?;
31 let payload_len = u32::try_from(payload.len())
32 .map_err(|_| tlb_ton::Error::custom("payload: overflow"))?;
33
34 let bytes = [
35 [0xff, 0xff].as_slice(),
36 b"ton-connect/sign-data/",
37 &self.address.workchain_id.to_be_bytes(),
38 self.address.address.as_ref(),
39 &domain_len.to_be_bytes(),
40 self.domain.as_bytes(),
41 &self.timestamp.to_be_bytes(),
42 payload_prefix,
43 &payload_len.to_be_bytes(),
44 payload,
45 ]
46 .concat();
47
48 Ok(near_sdk::env::sha256_array(&bytes))
49 }
50}
51
52pub trait PayloadSchema {
53 fn hash_with_context(
54 &self,
55 context: TonConnectPayloadContext,
56 ) -> Result<near_sdk::CryptoHash, StringError>;
57}
58
59#[cfg_attr(test, derive(arbitrary::Arbitrary))]
61#[near(serializers = [json])]
62#[serde(tag = "type", rename_all = "snake_case")]
63#[derive(Debug, Clone, PartialEq, Eq)]
64pub enum TonConnectPayloadSchema {
65 #[cfg(feature = "text")]
66 Text(text::TextPayload),
67 #[cfg(feature = "binary")]
68 Binary(binary::BinaryPayload),
69 #[cfg(feature = "cell")]
70 Cell(cell::CellPayload),
71}
72
73impl TonConnectPayloadSchema {
74 #[cfg(feature = "text")]
75 pub fn text(txt: impl Into<String>) -> Self {
76 Self::Text(text::TextPayload { text: txt.into() })
77 }
78
79 #[cfg(feature = "binary")]
80 pub fn binary(bytes: impl Into<Vec<u8>>) -> Self {
81 Self::Binary(binary::BinaryPayload {
82 bytes: bytes.into(),
83 })
84 }
85
86 #[cfg(feature = "cell")]
87 pub const fn cell(schema_crc: u32, cell: tlb_ton::Cell) -> Self {
88 Self::Cell(cell::CellPayload { schema_crc, cell })
89 }
90}
91
92impl PayloadSchema for TonConnectPayloadSchema {
93 fn hash_with_context(
94 &self,
95 context: TonConnectPayloadContext,
96 ) -> Result<near_sdk::CryptoHash, StringError> {
97 match self {
98 #[cfg(feature = "text")]
99 Self::Text(payload) => payload.hash_with_context(context),
100 #[cfg(feature = "binary")]
101 Self::Binary(payload) => payload.hash_with_context(context),
102 #[cfg(feature = "cell")]
103 Self::Cell(payload) => payload.hash_with_context(context),
104 }
105 }
106}