ab_system_contract_simple_wallet_base/
utils.rs1use crate::{SimpleWalletBaseExt, WalletState};
2use ab_contracts_common::ContractError;
3use ab_contracts_common::env::{Env, MethodContext};
4use ab_contracts_standards::tx_handler::{TxHandlerPayload, TxHandlerSeal, TxHandlerSlots};
5use ab_core_primitives::address::Address;
6use ab_core_primitives::transaction::TransactionHeader;
7use ab_io_type::IoType;
8use ab_io_type::trivial_type::TrivialType;
9use ab_io_type::variable_bytes::VariableBytes;
10use ab_system_contract_state::StateExt;
11use core::mem::MaybeUninit;
12
13#[inline(always)]
15#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
16pub fn initialize_state(env: &mut Env<'_>, public_key: &[u8; 32]) -> Result<(), ContractError> {
17 {
19 let state =
20 env.simple_wallet_base_initialize(Address::SYSTEM_SIMPLE_WALLET_BASE, public_key)?;
21
22 env.state_initialize(
23 MethodContext::Reset,
24 Address::SYSTEM_STATE,
25 &env.own_address(),
26 &VariableBytes::from_buffer(state.as_bytes(), &state.size())
27 .expect("Size of a trivial type matches its bytes; qed"),
28 )
29 }
30}
31
32#[inline(always)]
34#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
35pub fn authorize(
36 env: &Env<'_>,
37 header: &TransactionHeader,
38 read_slots: &TxHandlerSlots,
39 write_slots: &TxHandlerSlots,
40 payload: &TxHandlerPayload,
41 seal: &TxHandlerSeal,
42) -> Result<(), ContractError> {
43 let state = load_current_state(env)?;
44
45 env.simple_wallet_base_authorize(
46 Address::SYSTEM_SIMPLE_WALLET_BASE,
47 &state,
48 header,
49 read_slots,
50 write_slots,
51 payload,
52 seal,
53 )
54}
55
56#[inline(always)]
59#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
60pub fn execute(
61 env: &mut Env<'_>,
62 header: &TransactionHeader,
63 read_slots: &TxHandlerSlots,
64 write_slots: &TxHandlerSlots,
65 payload: &TxHandlerPayload,
66 seal: &TxHandlerSeal,
67) -> Result<(), ContractError> {
68 if env.caller() != Address::NULL {
70 return Err(ContractError::Forbidden);
71 }
72
73 let old_state = load_current_state(env)?;
75
76 env.simple_wallet_base_execute(
77 MethodContext::Replace,
78 Address::SYSTEM_SIMPLE_WALLET_BASE,
79 header,
80 read_slots,
81 write_slots,
82 payload,
83 seal,
84 )?;
85
86 {
89 let new_state =
91 env.simple_wallet_base_increase_nonce(Address::SYSTEM_SIMPLE_WALLET_BASE, &old_state)?;
92 env.state_compare_and_write(
94 MethodContext::Reset,
95 Address::SYSTEM_STATE,
96 &env.own_address(),
97 &VariableBytes::from_buffer(old_state.as_bytes(), &old_state.size())
98 .expect("Size of a trivial type matches its bytes; qed"),
99 &VariableBytes::from_buffer(new_state.as_bytes(), &new_state.size())
100 .expect("Size of a trivial type matches its bytes; qed"),
101 )
102 .map(|_| ())
103 }
104}
105
106#[inline(always)]
108#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
109pub fn change_public_key(env: &mut Env<'_>, public_key: &[u8; 32]) -> Result<(), ContractError> {
110 {
112 if !(env.context() == env.own_address()
115 && env.caller() == Address::SYSTEM_SIMPLE_WALLET_BASE)
116 {
117 return Err(ContractError::Forbidden);
118 }
119
120 let old_state = load_current_state(env)?;
122 let new_state = env.simple_wallet_base_change_public_key(
124 Address::SYSTEM_SIMPLE_WALLET_BASE,
125 &old_state,
126 public_key,
127 )?;
128 env.state_write(
130 MethodContext::Reset,
131 Address::SYSTEM_STATE,
132 &env.own_address(),
133 &VariableBytes::from_buffer(new_state.as_bytes(), &new_state.size())
134 .expect("Size of a trivial type matches its bytes; qed"),
135 )
136 }
137}
138
139#[inline(always)]
140#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
141fn load_current_state(env: &Env<'_>) -> Result<WalletState, ContractError> {
142 let current_state = {
143 let mut current_state = MaybeUninit::<WalletState>::uninit();
144 let mut current_state_size = 0;
145 env.state_read(
146 Address::SYSTEM_STATE,
147 &env.own_address(),
148 &mut VariableBytes::from_uninit(current_state.as_bytes_mut(), &mut current_state_size)
149 .expect("Size is zero and `WalletState` is smaller than 4 GiB; qed"),
150 )?;
151 if current_state_size != WalletState::SIZE {
152 return Err(ContractError::BadOutput);
153 }
154 unsafe { current_state.assume_init() }
156 };
157
158 Ok(current_state)
159}