ab_contract_playground/
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_io_type::variable_bytes::VariableBytes;
8use ab_contracts_macros::contract;
9use ab_contracts_standards::fungible::Fungible;
10use core::cmp::Ordering;
11
12#[derive(Debug, Default, Copy, Clone, PartialOrd, PartialEq, TrivialType)]
13#[repr(u8)]
14pub enum LastAction {
15 #[default]
16 None,
17 Mint,
18 Transfer,
19}
20
21#[derive(Debug, Default, Copy, Clone, TrivialType)]
22#[repr(C)]
23pub struct Slot {
24 pub balance: Balance,
25}
26
27#[derive(Debug, Copy, Clone, TrivialType)]
28#[repr(C)]
29pub struct Playground {
30 pub total_supply: Balance,
31 pub owner: Address,
32}
33
34#[contract]
35impl Fungible for Playground {
36 #[update]
37 fn transfer(
38 #[env] env: &mut Env<'_>,
39 #[input] from: &Address,
40 #[input] to: &Address,
41 #[input] amount: &Balance,
42 ) -> Result<(), ContractError> {
43 if !(env.context() == from || env.caller() == from || env.caller() == env.own_address()) {
44 return Err(ContractError::Forbidden);
45 }
46
47 env.playground_transfer(MethodContext::Replace, env.own_address(), from, to, amount)
48 }
49
50 #[view]
51 fn balance(#[env] env: &Env<'_>, #[input] address: &Address) -> Result<Balance, ContractError> {
52 env.playground_balance(env.own_address(), address)
53 }
54}
55
56#[contract]
57impl Playground {
58 #[init]
59 pub fn new(
60 #[slot] (owner_addr, owner): (&Address, &mut MaybeData<Slot>),
61 #[input] total_supply: &Balance,
62 ) -> Self {
63 owner.replace(Slot {
64 balance: *total_supply,
65 });
66 Self {
67 total_supply: *total_supply,
68 owner: *owner_addr,
69 }
70 }
71
72 #[init]
73 pub fn new_result(
74 #[slot] (owner_addr, owner): (&Address, &mut MaybeData<Slot>),
75 #[input] total_supply: &Balance,
76 #[output] result: &mut MaybeData<Self>,
77 ) {
78 owner.replace(Slot {
79 balance: *total_supply,
80 });
81 result.replace(Self {
82 total_supply: *total_supply,
83 owner: *owner_addr,
84 });
85 }
86
87 #[update]
88 pub fn mint(
89 &mut self,
90 #[env] env: &mut Env<'_>,
91 #[tmp] last_action: &mut MaybeData<LastAction>,
92 #[slot] to: &mut MaybeData<Slot>,
93 #[input] &value: &Balance,
94 ) -> Result<(), ContractError> {
95 if env.context() != self.owner && env.caller() != self.owner {
96 return Err(ContractError::Forbidden);
97 }
98
99 if Balance::MAX - value > self.total_supply {
100 return Err(ContractError::BadInput);
101 }
102
103 self.total_supply += value;
104 to.get_mut_or_default().balance += value;
105
106 last_action.replace(LastAction::Mint);
107
108 Ok(())
109 }
110
111 #[view]
112 pub fn balance(#[slot] target: &MaybeData<Slot>) -> Balance {
113 target
114 .get()
115 .map_or_else(Balance::default, |slot| slot.balance)
116 }
117
118 #[view]
119 pub fn balance2(#[slot] target: &MaybeData<Slot>, #[output] balance: &mut MaybeData<Balance>) {
120 balance.replace(
121 target
122 .get()
123 .map_or_else(Balance::default, |slot| slot.balance),
124 );
125 }
126
127 #[view]
128 pub fn balance3(#[slot] target: &MaybeData<Slot>, #[output] result: &mut MaybeData<Balance>) {
129 result.replace(
130 target
131 .get()
132 .map_or_else(Balance::default, |slot| slot.balance),
133 );
134 }
135
136 #[view]
137 pub fn var_bytes(#[output] _out: &mut VariableBytes<1024>) {
138 }
140
141 #[update]
142 pub fn transfer(
143 #[env] env: &mut Env<'_>,
144 #[tmp] last_action: &mut MaybeData<LastAction>,
145 #[slot] (from_address, from): (&Address, &mut MaybeData<Slot>),
146 #[slot] to: &mut MaybeData<Slot>,
147 #[input] &amount: &Balance,
148 ) -> Result<(), ContractError> {
149 if !(env.context() == from_address
150 || env.caller() == from_address
151 || env.caller() == env.own_address())
152 {
153 return Err(ContractError::Forbidden);
154 }
155
156 {
157 let Some(contents) = from.get_mut() else {
158 return Err(ContractError::BadInput);
159 };
160
161 match contents.balance.cmp(&amount) {
162 Ordering::Less => {
163 return Err(ContractError::BadInput);
164 }
165 Ordering::Equal => {
166 from.remove();
168 }
169 Ordering::Greater => {
170 contents.balance -= amount;
171 }
172 }
173 }
174
175 to.get_mut_or_default().balance += amount;
176
177 last_action.replace(LastAction::Transfer);
178
179 Ok(())
180 }
181
182 #[update]
183 pub fn last_action(#[tmp] maybe_last_action: &MaybeData<LastAction>) -> LastAction {
184 maybe_last_action.get().copied().unwrap_or_default()
185 }
186}