tonlib_core/wallet/versioned/
v3.rs

1use crate::cell::{ArcCell, CellBuilder, CellParser, TonCellError};
2use crate::tlb_types::tlb::TLB;
3use crate::types::TonHash;
4use crate::wallet::versioned::utils::write_up_to_4_msgs;
5
6/// WalletVersion::V3R1 | WalletVersion::V3R2
7#[derive(Debug, PartialEq, Clone)]
8pub struct WalletDataV3 {
9    pub seqno: u32,
10    pub wallet_id: i32,
11    pub public_key: TonHash,
12}
13
14/// https://docs.ton.org/participate/wallets/contracts#wallet-v3
15/// signature is not considered as part of msg body
16/// documentation is not correct about body layout
17#[derive(Debug, PartialEq, Clone)]
18pub struct WalletExtMsgBodyV3 {
19    pub subwallet_id: i32,
20    pub valid_until: u32,
21    pub msg_seqno: u32,
22    pub msgs_modes: Vec<u8>,
23    pub msgs: Vec<ArcCell>,
24}
25
26impl WalletDataV3 {
27    pub fn new(wallet_id: i32, public_key: TonHash) -> Self {
28        Self {
29            seqno: 0,
30            wallet_id,
31            public_key,
32        }
33    }
34}
35impl TLB for WalletDataV3 {
36    fn read_definition(parser: &mut CellParser) -> Result<Self, TonCellError> {
37        Ok(Self {
38            seqno: parser.load_u32(32)?,
39            wallet_id: parser.load_i32(32)?,
40            public_key: parser.load_tonhash()?,
41        })
42    }
43
44    fn write_definition(&self, dst: &mut CellBuilder) -> Result<(), TonCellError> {
45        dst.store_u32(32, self.seqno)?;
46        dst.store_i32(32, self.wallet_id)?;
47        dst.store_tonhash(&self.public_key)?;
48        Ok(())
49    }
50}
51
52impl TLB for WalletExtMsgBodyV3 {
53    fn read_definition(parser: &mut CellParser) -> Result<Self, TonCellError> {
54        let subwallet_id = parser.load_i32(32)?;
55        let valid_until = parser.load_u32(32)?;
56        let msg_seqno = parser.load_u32(32)?;
57        let msgs_cnt = parser.cell.references().len();
58        let mut msgs_modes = Vec::with_capacity(msgs_cnt);
59        let mut msgs = Vec::with_capacity(msgs_cnt);
60        for _ in 0..msgs_cnt {
61            msgs_modes.push(parser.load_u8(8)?);
62            msgs.push(parser.next_reference()?);
63        }
64        Ok(Self {
65            subwallet_id,
66            msg_seqno,
67            valid_until,
68            msgs_modes,
69            msgs,
70        })
71    }
72
73    fn write_definition(&self, dst: &mut CellBuilder) -> Result<(), TonCellError> {
74        dst.store_i32(32, self.subwallet_id)?;
75        dst.store_u32(32, self.valid_until)?;
76        dst.store_u32(32, self.msg_seqno)?;
77        write_up_to_4_msgs(dst, &self.msgs, &self.msgs_modes)?;
78        Ok(())
79    }
80}
81
82#[cfg(test)]
83mod test {
84    use super::*;
85    use crate::cell::Cell;
86    use crate::tlb_types::tlb::TLB;
87    use crate::wallet::versioned::DEFAULT_WALLET_ID;
88
89    #[test]
90    fn test_wallet_data_v3() -> anyhow::Result<()> {
91        // https://tonviewer.com/UQAMY2B4xfQO6m3YpmzfX5Za-Ning4kWKFjPdubbPPV3Ffel
92        let src_boc_hex = "b5ee9c7241010101002a0000500000000129a9a317cbf377c9b73604c70bf73488ddceba14f763baef2ac70f68d1d6032a120149f4b6de3f10";
93        let wallet_data = WalletDataV3::from_boc_hex(src_boc_hex)?;
94        assert_eq!(wallet_data.seqno, 1);
95        assert_eq!(wallet_data.wallet_id, DEFAULT_WALLET_ID);
96        assert_eq!(
97            wallet_data.public_key,
98            TonHash::from_hex("cbf377c9b73604c70bf73488ddceba14f763baef2ac70f68d1d6032a120149f4")?
99        );
100        let serial_boc_hex = wallet_data.to_boc_hex(false)?;
101        let restored = WalletDataV3::from_boc_hex(&serial_boc_hex)?;
102        assert_eq!(wallet_data, restored);
103        Ok(())
104    }
105
106    #[test]
107    fn test_wallet_ext_msg_body_v3() -> anyhow::Result<()> {
108        // https://tonviewer.com/transaction/b4bd316c74b4c99586e07c167979ce4a6e18db31704abd7e85b1cacb065ce66c
109        let body_signed_cell = Cell::from_boc_hex("b5ee9c7201010201008500019a86be376ea96e2f1252377976716a3d252906151feabc8e4b51506405035e45a7b4ff81f783cfe3f86483c822bcbb4f9481804990868bac69caf7af56e30fe70b29a9a317ffffffff000000000301006642007847b4630eb08d9f486fe846d5496878556dfd5a084f82a9a3fb01224e67c84c187a120000000000000000000000000000")?;
110        let mut parser = body_signed_cell.parser();
111        parser.load_bytes(64)?; // signature
112        let body_cell = Cell::read(&mut parser)?;
113
114        let body = WalletExtMsgBodyV3::from_cell(&body_cell)?;
115        assert_eq!(body.subwallet_id, DEFAULT_WALLET_ID);
116        assert_eq!(body.msg_seqno, 0);
117        assert_eq!(body.valid_until, 4294967295);
118        assert_eq!(body.msgs_modes, vec![3]);
119        assert_eq!(body.msgs.len(), 1);
120
121        let serial_cell = body.to_cell()?;
122        assert_eq!(body_cell, serial_cell);
123        Ok(())
124    }
125}