ab_system_contract_code/
lib.rs1#![no_std]
2
3use ab_contracts_common::env::{Env, MethodContext};
4use ab_contracts_common::{Address, ContractError, MAX_CODE_SIZE};
5use ab_contracts_io_type::trivial_type::TrivialType;
6use ab_contracts_io_type::variable_bytes::VariableBytes;
7use ab_contracts_macros::contract;
8use ab_system_contract_address_allocator::AddressAllocatorExt;
9
10#[derive(Debug, Copy, Clone, TrivialType)]
11#[repr(C)]
12pub struct Code;
13
14#[contract]
15impl Code {
16 #[update]
18 pub fn deploy(
19 #[env] env: &mut Env<'_>,
20 #[input] code: &VariableBytes<MAX_CODE_SIZE>,
21 ) -> Result<Address, ContractError> {
22 let new_contract_address = env.address_allocator_allocate_address(
23 MethodContext::Replace,
24 Address::system_address_allocator(env.shard_index()),
25 )?;
26
27 env.code_store(
28 MethodContext::Replace,
29 env.own_address(),
30 &new_contract_address,
31 code,
32 )?;
33
34 Ok(new_contract_address)
35 }
36
37 #[update]
42 pub fn store(
43 #[env] env: &mut Env<'_>,
44 #[slot] (address, contract_code): (&Address, &mut VariableBytes<MAX_CODE_SIZE>),
45 #[input] new_code: &VariableBytes<MAX_CODE_SIZE>,
46 ) -> Result<(), ContractError> {
47 if !(env.caller() == Address::NULL
51 || env.caller() == env.own_address()
52 || env.caller() == address)
53 {
54 return Err(ContractError::Forbidden);
55 }
56
57 if !contract_code.copy_from(new_code) {
58 return Err(ContractError::BadInput);
59 }
60
61 Ok(())
62 }
63
64 #[view]
66 pub fn read(
67 #[slot] contract_code: &VariableBytes<MAX_CODE_SIZE>,
68 #[output] code: &mut VariableBytes<MAX_CODE_SIZE>,
69 ) -> Result<(), ContractError> {
70 if code.copy_from(contract_code) {
71 Ok(())
72 } else {
73 Err(ContractError::BadInput)
74 }
75 }
76}