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)]
15pub fn initialize_state(env: &mut Env<'_>, public_key: &[u8; 32]) -> Result<(), ContractError> {
18 {
20 let state =
21 env.simple_wallet_base_initialize(Address::SYSTEM_SIMPLE_WALLET_BASE, public_key)?;
22
23 env.state_initialize(
24 MethodContext::Reset,
25 Address::SYSTEM_STATE,
26 &env.own_address(),
27 &VariableBytes::from_buffer(state.as_bytes(), &state.size())
28 .expect("Size of a trivial type matches its bytes; qed"),
29 )
30 }
31}
32
33#[inline(always)]
35pub fn authorize(
38 env: &Env<'_>,
39 header: &TransactionHeader,
40 read_slots: &TxHandlerSlots<'_>,
41 write_slots: &TxHandlerSlots<'_>,
42 payload: &TxHandlerPayload<'_>,
43 seal: &TxHandlerSeal<'_>,
44) -> Result<(), ContractError> {
45 let state = load_current_state(env)?;
46
47 env.simple_wallet_base_authorize(
48 Address::SYSTEM_SIMPLE_WALLET_BASE,
49 &state,
50 header,
51 read_slots,
52 write_slots,
53 payload,
54 seal,
55 )
56}
57
58#[inline(always)]
61pub fn execute(
64 env: &mut Env<'_>,
65 header: &TransactionHeader,
66 read_slots: &TxHandlerSlots<'_>,
67 write_slots: &TxHandlerSlots<'_>,
68 payload: &TxHandlerPayload<'_>,
69 seal: &TxHandlerSeal<'_>,
70) -> Result<(), ContractError> {
71 if env.caller() != Address::NULL {
73 return Err(ContractError::Forbidden);
74 }
75
76 let old_state = load_current_state(env)?;
78
79 env.simple_wallet_base_execute(
80 MethodContext::Replace,
81 Address::SYSTEM_SIMPLE_WALLET_BASE,
82 header,
83 read_slots,
84 write_slots,
85 payload,
86 seal,
87 )?;
88
89 {
92 let new_state =
94 env.simple_wallet_base_increase_nonce(Address::SYSTEM_SIMPLE_WALLET_BASE, &old_state)?;
95 env.state_compare_and_write(
97 MethodContext::Reset,
98 Address::SYSTEM_STATE,
99 &env.own_address(),
100 &VariableBytes::from_buffer(old_state.as_bytes(), &old_state.size())
101 .expect("Size of a trivial type matches its bytes; qed"),
102 &VariableBytes::from_buffer(new_state.as_bytes(), &new_state.size())
103 .expect("Size of a trivial type matches its bytes; qed"),
104 )
105 .map(|_| ())
106 }
107}
108
109#[inline(always)]
111pub fn change_public_key(env: &mut Env<'_>, public_key: &[u8; 32]) -> Result<(), ContractError> {
114 {
116 if !(env.context() == env.own_address()
119 && env.caller() == Address::SYSTEM_SIMPLE_WALLET_BASE)
120 {
121 return Err(ContractError::Forbidden);
122 }
123
124 let old_state = load_current_state(env)?;
126 let new_state = env.simple_wallet_base_change_public_key(
128 Address::SYSTEM_SIMPLE_WALLET_BASE,
129 &old_state,
130 public_key,
131 )?;
132 env.state_write(
134 MethodContext::Reset,
135 Address::SYSTEM_STATE,
136 &env.own_address(),
137 &VariableBytes::from_buffer(new_state.as_bytes(), &new_state.size())
138 .expect("Size of a trivial type matches its bytes; qed"),
139 )
140 }
141}
142
143#[inline(always)]
144fn load_current_state(env: &Env<'_>) -> Result<WalletState, ContractError> {
147 let current_state = {
148 let mut current_state = MaybeUninit::<WalletState>::uninit();
149 let mut current_state_size = 0;
150 env.state_read(
151 Address::SYSTEM_STATE,
152 &env.own_address(),
153 &mut VariableBytes::from_uninit(current_state.as_bytes_mut(), &mut current_state_size)
154 .expect("Size is zero and `WalletState` is smaller than 4 GiB; qed"),
155 )?;
156 if current_state_size != WalletState::SIZE {
157 return Err(ContractError::BadOutput);
158 }
159 unsafe { current_state.assume_init() }
161 };
162
163 Ok(current_state)
164}