1#![cfg_attr(not(feature = "std"), no_std, no_main)]
2
3mod traits;
4
5pub use psp22::{PSP22Error, PSP22};
7
8pub use traits::{WrappedAZERO, MAINNET, TESTNET};
9
10#[ink::contract]
11mod wazero {
12 use crate::WrappedAZERO;
13 use ink::prelude::{string::String, vec::Vec};
14 use psp22::{PSP22Data, PSP22Error, PSP22Event, PSP22Metadata, PSP22};
15
16 #[ink(event)]
17 pub struct Approval {
18 #[ink(topic)]
19 owner: AccountId,
20 #[ink(topic)]
21 spender: AccountId,
22 amount: u128,
23 }
24
25 #[ink(event)]
26 pub struct Transfer {
27 #[ink(topic)]
28 from: Option<AccountId>,
29 #[ink(topic)]
30 to: Option<AccountId>,
31 value: u128,
32 }
33
34 #[ink(storage)]
35 #[derive(Default)]
36 pub struct Wazero {
37 data: PSP22Data,
38 }
39
40 impl Wazero {
41 #[ink(constructor)]
42 pub fn new() -> Self {
43 Self::default()
44 }
45
46 fn emit_events(&self, events: Vec<PSP22Event>) {
47 for event in events {
48 match event {
49 PSP22Event::Transfer { from, to, value } => {
50 self.env().emit_event(Transfer { from, to, value })
51 }
52 PSP22Event::Approval {
53 owner,
54 spender,
55 amount,
56 } => self.env().emit_event(Approval {
57 owner,
58 spender,
59 amount,
60 }),
61 }
62 }
63 }
64 }
65
66 impl WrappedAZERO for Wazero {
67 #[ink(message, payable)]
68 fn deposit(&mut self) -> Result<(), PSP22Error> {
69 let events = self
70 .data
71 .mint(self.env().caller(), self.env().transferred_value())?;
72 self.emit_events(events);
73 Ok(())
74 }
75
76 #[ink(message)]
77 fn withdraw(&mut self, value: u128) -> Result<(), PSP22Error> {
78 let caller = self.env().caller();
79 let events = self.data.burn(caller, value)?;
80 self.env()
81 .transfer(caller, value)
82 .map_err(|_| PSP22Error::Custom(String::from("Wrapped AZERO: withdraw failed")))?;
83 self.emit_events(events);
84 Ok(())
85 }
86 }
87
88 impl PSP22Metadata for Wazero {
89 #[ink(message)]
90 fn token_name(&self) -> Option<String> {
91 Some(String::from("Wrapped AZERO"))
92 }
93
94 #[ink(message)]
95 fn token_symbol(&self) -> Option<String> {
96 Some(String::from("wAZERO"))
97 }
98
99 #[ink(message)]
100 fn token_decimals(&self) -> u8 {
101 12
102 }
103 }
104
105 impl PSP22 for Wazero {
106 #[ink(message)]
107 fn total_supply(&self) -> u128 {
108 self.data.total_supply()
109 }
110
111 #[ink(message)]
112 fn balance_of(&self, owner: AccountId) -> u128 {
113 self.data.balance_of(owner)
114 }
115
116 #[ink(message)]
117 fn allowance(&self, owner: AccountId, spender: AccountId) -> u128 {
118 self.data.allowance(owner, spender)
119 }
120
121 #[ink(message)]
122 fn transfer(
123 &mut self,
124 to: AccountId,
125 value: u128,
126 _data: Vec<u8>,
127 ) -> Result<(), PSP22Error> {
128 let events = self.data.transfer(self.env().caller(), to, value)?;
129 self.emit_events(events);
130 Ok(())
131 }
132
133 #[ink(message)]
134 fn transfer_from(
135 &mut self,
136 from: AccountId,
137 to: AccountId,
138 value: u128,
139 _data: Vec<u8>,
140 ) -> Result<(), PSP22Error> {
141 let events = self
142 .data
143 .transfer_from(self.env().caller(), from, to, value)?;
144 self.emit_events(events);
145 Ok(())
146 }
147
148 #[ink(message)]
149 fn approve(&mut self, spender: AccountId, value: u128) -> Result<(), PSP22Error> {
150 let events = self.data.approve(self.env().caller(), spender, value)?;
151 self.emit_events(events);
152 Ok(())
153 }
154
155 #[ink(message)]
156 fn increase_allowance(
157 &mut self,
158 spender: AccountId,
159 delta_value: u128,
160 ) -> Result<(), PSP22Error> {
161 let events = self
162 .data
163 .increase_allowance(self.env().caller(), spender, delta_value)?;
164 self.emit_events(events);
165 Ok(())
166 }
167
168 #[ink(message)]
169 fn decrease_allowance(
170 &mut self,
171 spender: AccountId,
172 delta_value: u128,
173 ) -> Result<(), PSP22Error> {
174 let events = self
175 .data
176 .decrease_allowance(self.env().caller(), spender, delta_value)?;
177 self.emit_events(events);
178 Ok(())
179 }
180 }
181
182 #[cfg(test)]
183 mod tests {
184 use super::*;
185 use ink::env::{test::*, DefaultEnvironment as E};
186
187 psp22::tests!(Wazero, crate::wazero::tests::init_psp22_supply);
188
189 #[ink::test]
190 fn constructor_works() {
191 let contract = Wazero::new();
192 assert_eq!(contract.total_supply(), 0);
193 }
194
195 #[ink::test]
196 fn metadata_is_correct() {
197 let contract = Wazero::new();
198 assert_eq!(contract.token_name(), Some(String::from("Wrapped AZERO")));
199 assert_eq!(contract.token_symbol(), Some(String::from("wAZERO")));
200 assert_eq!(contract.token_decimals(), 12);
201 }
202
203 #[ink::test]
204 fn deposit_works() {
205 let mut contract = Wazero::new();
206 let amount = 100;
207 let alice = default_accounts::<E>().alice;
208 set_caller::<E>(alice);
209 set_value_transferred::<E>(amount);
210
211 assert_eq!(contract.total_supply(), 0);
212 assert_eq!(contract.balance_of(alice), 0);
213
214 assert!(contract.deposit().is_ok());
215
216 assert_eq!(contract.total_supply(), amount);
217 assert_eq!(contract.balance_of(alice), amount);
218 }
219
220 #[ink::test]
221 fn deposit_emits_event() {
222 let mut contract = Wazero::new();
223 let amount = 100;
224 let alice = default_accounts::<E>().alice;
225 set_caller::<E>(alice);
226 set_value_transferred::<E>(amount);
227
228 assert!(contract.deposit().is_ok());
229
230 let events = decode_events();
231 assert_eq!(events.len(), 1);
232 assert_transfer(&events[0], None, Some(alice), amount);
233 }
234
235 #[ink::test]
236 fn deposit_of_0_emits_no_event() {
237 let mut contract = Wazero::new();
238 let alice = default_accounts::<E>().alice;
239 set_caller::<E>(alice);
240
241 assert!(contract.deposit().is_ok());
242
243 let events = decode_events();
244 assert_eq!(events.len(), 0);
245 }
246
247 #[ink::test]
248 fn multiple_deposit_works_and_emits_events() {
249 let mut contract = Wazero::new();
250 let amount = 100;
251 let acc = default_accounts::<E>();
252 let (alice, bob) = (acc.alice, acc.bob);
253
254 assert_eq!(contract.total_supply(), 0);
255 assert_eq!(contract.balance_of(alice), 0);
256 assert_eq!(contract.balance_of(bob), 0);
257
258 set_caller::<E>(alice);
259 set_value_transferred::<E>(amount);
260 assert!(contract.deposit().is_ok());
261
262 assert_eq!(contract.total_supply(), amount);
263 assert_eq!(contract.balance_of(alice), amount);
264 assert_eq!(contract.balance_of(bob), 0);
265
266 set_caller::<E>(bob);
267 set_value_transferred::<E>(2 * amount);
268 assert!(contract.deposit().is_ok());
269
270 assert_eq!(contract.total_supply(), 3 * amount);
271 assert_eq!(contract.balance_of(alice), amount);
272 assert_eq!(contract.balance_of(bob), 2 * amount);
273
274 let events = decode_events();
275 assert_eq!(events.len(), 2);
276 assert_transfer(&events[0], None, Some(alice), amount);
277 assert_transfer(&events[1], None, Some(bob), 2 * amount);
278 }
279
280 #[ink::test]
281 fn withdraw_works() {
282 let (supply, amount) = (1000, 100);
283 let alice = default_accounts::<E>().alice;
284 set_caller::<E>(alice);
285 let mut contract = init_psp22_supply(supply);
286
287 assert_eq!(contract.total_supply(), supply);
288 assert_eq!(contract.balance_of(alice), supply);
289
290 let old_native = get_account_balance::<E>(alice).unwrap();
291 assert!(contract.withdraw(amount).is_ok());
292 let new_native = get_account_balance::<E>(alice).unwrap();
293
294 assert_eq!(contract.total_supply(), supply - amount);
295 assert_eq!(contract.balance_of(alice), supply - amount);
296 assert_eq!(new_native - old_native, amount);
297 }
298
299 #[ink::test]
300 fn withdraw_emits_event() {
301 let (supply, amount) = (1000, 100);
302 let alice = default_accounts::<E>().alice;
303 set_caller::<E>(alice);
304 let mut contract = init_psp22_supply(supply);
305
306 assert!(contract.withdraw(amount).is_ok());
307
308 let events = decode_events();
309 assert_eq!(events.len(), 2);
310 assert_transfer(&events[0], None, Some(alice), supply);
311 assert_transfer(&events[1], Some(alice), None, amount);
312 }
313
314 #[ink::test]
315 fn withdraw_of_0_emits_no_event() {
316 let amount = 100;
317 let alice = default_accounts::<E>().alice;
318 set_caller::<E>(alice);
319 let mut contract = init_psp22_supply(amount);
320
321 assert!(contract.withdraw(0).is_ok());
322 let events = decode_events();
323 assert_eq!(events.len(), 1);
324 assert_transfer(&events[0], None, Some(alice), amount);
325 }
326
327 #[ink::test]
328 fn withdraw_too_much_fails() {
329 let amount = 100;
330 let alice = default_accounts::<E>().alice;
331 set_caller::<E>(alice);
332 let mut contract = init_psp22_supply(amount);
333 assert_eq!(
334 contract.withdraw(amount + 1),
335 Err(PSP22Error::InsufficientBalance)
336 );
337 }
338
339 #[ink::test]
340 fn multiple_withdraw_works_and_emits_events() {
341 let (initial, a, b) = (1000, 100, 10);
342 let alice = default_accounts::<E>().alice;
343 let bob = default_accounts::<E>().bob;
344 set_caller::<E>(alice);
345 set_callee::<E>(default_accounts::<E>().charlie);
346 let mut contract = init_psp22_supply(2 * initial);
347
348 assert!(contract.transfer(bob, initial, vec![]).is_ok());
349
350 let old_alice = get_account_balance::<E>(alice).unwrap();
351 let old_bob = get_account_balance::<E>(bob).unwrap();
352
353 assert!(contract.withdraw(a).is_ok());
354 set_caller::<E>(bob);
355 assert!(contract.withdraw(b).is_ok());
356
357 let new_alice = get_account_balance::<E>(alice).unwrap();
358 let new_bob = get_account_balance::<E>(bob).unwrap();
359
360 assert_eq!(contract.total_supply(), 2 * initial - a - b);
361 assert_eq!(contract.balance_of(alice), initial - a);
362 assert_eq!(contract.balance_of(bob), initial - b);
363 assert_eq!(new_alice - old_alice, a);
364 assert_eq!(new_bob - old_bob, b);
365
366 let events = decode_events();
367 assert_eq!(events.len(), 4);
368 assert_transfer(&events[0], None, Some(alice), 2 * initial);
369 assert_transfer(&events[1], Some(alice), Some(bob), initial);
370 assert_transfer(&events[2], Some(alice), None, a);
371 assert_transfer(&events[3], Some(bob), None, b);
372 }
373
374 type Event = <Wazero as ink::reflect::ContractEventBase>::Type;
377
378 fn init_psp22_supply(amount: u128) -> Wazero {
380 let mut contract = Wazero::new();
381 set_value_transferred::<E>(amount);
382 contract.deposit().unwrap();
383 contract
384 }
385
386 fn decode_events() -> Vec<Event> {
388 recorded_events()
389 .map(|e| <Event as scale::Decode>::decode(&mut &e.data[..]).unwrap())
390 .collect()
391 }
392
393 fn assert_transfer(
395 event: &Event,
396 from_: Option<AccountId>,
397 to_: Option<AccountId>,
398 value_: u128,
399 ) {
400 if let Event::Transfer(Transfer { from, to, value }) = event {
401 assert_eq!(*from, from_, "Transfer event: 'from' mismatch");
402 assert_eq!(*to, to_, "Transfer event: 'to' mismatch");
403 assert_eq!(*value, value_, "Transfer event: 'value' mismatch");
404 } else {
405 panic!("Event is not Transfer")
406 }
407 }
408 }
409}