ab_system_contract_native_token/
lib.rs1#![no_std]
2
3use ab_contracts_common::env::{Env, MethodContext};
4use ab_contracts_common::{Address, Balance, ContractError};
5use ab_contracts_io_type::maybe_data::MaybeData;
6use ab_contracts_io_type::trivial_type::TrivialType;
7use ab_contracts_macros::contract;
8use ab_contracts_standards::fungible::Fungible;
9use core::cmp::Ordering;
10
11#[derive(Debug, Default, Copy, Clone, TrivialType)]
12#[repr(C)]
13pub struct Slot {
14 pub balance: Balance,
15}
16
17#[derive(Debug, Copy, Clone, TrivialType)]
18#[repr(C)]
19pub struct NativeToken {}
20
21#[contract]
22impl Fungible for NativeToken {
23 #[update]
24 fn transfer(
25 #[env] env: &mut Env<'_>,
26 #[input] from: &Address,
27 #[input] to: &Address,
28 #[input] amount: &Balance,
29 ) -> Result<(), ContractError> {
30 if !(env.context() == from
31 || env.caller() == from
32 || env.caller() == env.own_address()
33 || env.caller() == Address::NULL)
34 {
35 return Err(ContractError::Forbidden);
36 }
37
38 env.native_token_transfer(MethodContext::Replace, env.own_address(), from, to, amount)
39 }
40
41 #[view]
42 fn balance(#[env] env: &Env<'_>, #[input] address: &Address) -> Result<Balance, ContractError> {
43 env.native_token_balance(env.own_address(), address)
44 }
45}
46
47#[contract]
48impl NativeToken {
49 #[update]
53 pub fn initialize(
54 #[env] env: &mut Env<'_>,
55 #[slot] (own_address, own_balance): (&Address, &mut MaybeData<Slot>),
56 #[input] &max_issuance: &Balance,
57 ) -> Result<Self, ContractError> {
58 if env.caller() != Address::NULL {
60 return Err(ContractError::Forbidden);
61 }
62
63 if own_address != env.own_address() {
64 return Err(ContractError::BadInput);
65 }
66
67 if own_balance.get().is_some() {
68 return Err(ContractError::Conflict);
69 }
70
71 own_balance.replace(Slot {
72 balance: max_issuance,
73 });
74
75 Ok(Self {})
76 }
77
78 #[view]
79 pub fn balance(#[slot] target: &MaybeData<Slot>) -> Balance {
80 target
81 .get()
82 .map_or_else(Balance::default, |slot| slot.balance)
83 }
84
85 #[update]
86 pub fn transfer(
87 #[env] env: &mut Env<'_>,
88 #[slot] (from_address, from): (&Address, &mut MaybeData<Slot>),
89 #[slot] to: &mut MaybeData<Slot>,
90 #[input] &amount: &Balance,
91 ) -> Result<(), ContractError> {
92 if !(env.context() == from_address
93 || env.caller() == from_address
94 || env.caller() == env.own_address()
95 || env.caller() == Address::NULL)
96 {
97 return Err(ContractError::Forbidden);
98 }
99
100 {
101 let Some(contents) = from.get_mut() else {
102 return Err(ContractError::BadInput);
103 };
104
105 match contents.balance.cmp(&amount) {
106 Ordering::Less => {
107 return Err(ContractError::BadInput);
108 }
109 Ordering::Equal => {
110 from.remove();
112 }
113 Ordering::Greater => {
114 contents.balance -= amount;
115 }
116 }
117 }
118
119 to.get_mut_or_default().balance += amount;
120
121 Ok(())
122 }
123}