ab_system_contract_state/
lib.rs1#![no_std]
2
3use ab_contracts_common::env::Env;
4use ab_contracts_common::{Address, ContractError};
5use ab_contracts_io_type::trivial_type::TrivialType;
6use ab_contracts_io_type::variable_bytes::VariableBytes;
7use ab_contracts_macros::contract;
8use core::mem::MaybeUninit;
9
10pub const RECOMMENDED_STATE_CAPACITY: u32 = 1024;
12
13#[inline(always)]
15pub fn with_state_buffer<F, R>(f: F) -> R
16where
17 F: FnOnce(&mut VariableBytes<RECOMMENDED_STATE_CAPACITY>) -> R,
18{
19 let mut state_bytes = [MaybeUninit::uninit(); RECOMMENDED_STATE_CAPACITY as usize];
20 let mut state_size = 0;
21 let mut new_state = VariableBytes::from_uninit(&mut state_bytes, &mut state_size);
22 f(&mut new_state)
23}
24
25#[derive(Debug, Copy, Clone, TrivialType)]
26#[repr(C)]
27pub struct State;
28
29#[contract]
30impl State {
31 #[update]
35 pub fn initialize(
36 #[env] env: &mut Env<'_>,
37 #[slot] (address, contract_state): (
38 &Address,
39 &mut VariableBytes<RECOMMENDED_STATE_CAPACITY>,
40 ),
41 #[input] state: &VariableBytes<RECOMMENDED_STATE_CAPACITY>,
42 ) -> Result<(), ContractError> {
43 if !Self::is_empty(contract_state) {
44 return Err(ContractError::Conflict);
45 }
46
47 Self::write(env, (address, contract_state), state)
48 }
49
50 #[update]
54 pub fn write(
55 #[env] env: &mut Env<'_>,
56 #[slot] (address, contract_state): (
59 &Address,
60 &mut VariableBytes<RECOMMENDED_STATE_CAPACITY>,
61 ),
62 #[input] new_state: &VariableBytes<RECOMMENDED_STATE_CAPACITY>,
63 ) -> Result<(), ContractError> {
64 if env.caller() != address {
66 return Err(ContractError::Forbidden);
67 }
68
69 if !contract_state.copy_from(new_state) {
70 return Err(ContractError::BadInput);
71 }
72
73 Ok(())
74 }
75
76 #[view]
78 pub fn read(
79 #[slot] contract_state: &VariableBytes<RECOMMENDED_STATE_CAPACITY>,
80 #[output] state: &mut VariableBytes<RECOMMENDED_STATE_CAPACITY>,
81 ) -> Result<(), ContractError> {
82 if state.copy_from(contract_state) {
83 Ok(())
84 } else {
85 Err(ContractError::BadInput)
86 }
87 }
88
89 #[view]
91 pub fn is_empty(#[slot] contract_state: &VariableBytes<RECOMMENDED_STATE_CAPACITY>) -> bool {
92 contract_state.size() == 0
93 }
94}