psp22/
data.rs

1use crate::errors::PSP22Error;
2use crate::events::{Approval, Transfer};
3use ink::prelude::string::String;
4use ink::{
5    prelude::{vec, vec::Vec},
6    primitives::AccountId,
7    storage::Mapping,
8};
9
10/// Common wrapper type for events emitted during operations that change the
11/// state of PSP22Data struct.
12pub enum PSP22Event {
13    Transfer(Transfer),
14    Approval(Approval),
15}
16
17// Shortcut for Approval PSP22Event constructor.
18fn approval_event(owner: AccountId, spender: AccountId, amount: u128) -> PSP22Event {
19    PSP22Event::Approval(Approval {
20        owner,
21        spender,
22        amount,
23    })
24}
25
26// Shortcut for Transfer PSP22Event constructor.
27fn transfer_event(from: Option<AccountId>, to: Option<AccountId>, value: u128) -> PSP22Event {
28    PSP22Event::Transfer(Transfer { from, to, value })
29}
30
31/// A class implementing the internal logic of a PSP22 token.
32//
33/// Holds the state of all account balances and allowances.
34/// Each method of this class corresponds to one type of transaction
35/// as defined in the PSP22 standard.
36//
37/// Since this code is outside of `ink::contract` macro, the caller's
38/// address cannot be obtained automatically. Because of that, all
39/// the methods that need to know the caller require an additional argument
40/// (compared to transactions defined by the PSP22 standard or the PSP22 trait).
41//
42/// `lib.rs` contains an example implementation of a smart contract using this class.
43#[ink::storage_item]
44#[derive(Debug, Default)]
45pub struct PSP22Data {
46    total_supply: u128,
47    balances: Mapping<AccountId, u128>,
48    allowances: Mapping<(AccountId, AccountId), u128>,
49}
50
51impl PSP22Data {
52    /// Creates a token with `supply` balance, initially held by the `creator` account.
53    pub fn new(supply: u128, creator: AccountId) -> (PSP22Data, Vec<PSP22Event>) {
54        let mut data: PSP22Data = Default::default();
55        let events = data.mint(creator, supply).unwrap();
56        (data, events)
57    }
58
59    pub fn total_supply(&self) -> u128 {
60        self.total_supply
61    }
62
63    pub fn balance_of(&self, owner: AccountId) -> u128 {
64        self.balances.get(owner).unwrap_or_default()
65    }
66
67    pub fn allowance(&self, owner: AccountId, spender: AccountId) -> u128 {
68        self.allowances.get((owner, spender)).unwrap_or_default()
69    }
70
71    /// Transfers `value` tokens from `caller` to `to`.
72    pub fn transfer(
73        &mut self,
74        caller: AccountId,
75        to: AccountId,
76        value: u128,
77    ) -> Result<Vec<PSP22Event>, PSP22Error> {
78        if caller == to || value == 0 {
79            return Ok(vec![]);
80        }
81        let from_balance = self.balance_of(caller);
82        if from_balance < value {
83            return Err(PSP22Error::InsufficientBalance);
84        }
85
86        if from_balance == value {
87            self.balances.remove(caller);
88        } else {
89            self.balances
90                .insert(caller, &(from_balance.saturating_sub(value)));
91        }
92        let to_balance = self.balance_of(to);
93        // Total supply is limited by u128.MAX so no overflow is possible
94        self.balances
95            .insert(to, &(to_balance.saturating_add(value)));
96        Ok(vec![transfer_event(Some(caller), Some(to), value)])
97    }
98
99    /// Transfers `value` tokens from `from` to `to`, but using the allowance
100    /// granted be `from` to `caller.
101    pub fn transfer_from(
102        &mut self,
103        caller: AccountId,
104        from: AccountId,
105        to: AccountId,
106        value: u128,
107    ) -> Result<Vec<PSP22Event>, PSP22Error> {
108        if from == to || value == 0 {
109            return Ok(vec![]);
110        }
111        if caller == from {
112            return self.transfer(caller, to, value);
113        }
114
115        let allowance = self.allowance(from, caller);
116        if allowance < value {
117            return Err(PSP22Error::InsufficientAllowance);
118        }
119        let from_balance = self.balance_of(from);
120        if from_balance < value {
121            return Err(PSP22Error::InsufficientBalance);
122        }
123
124        if allowance == value {
125            self.allowances.remove((from, caller));
126        } else {
127            self.allowances
128                .insert((from, caller), &(allowance.saturating_sub(value)));
129        }
130
131        if from_balance == value {
132            self.balances.remove(from);
133        } else {
134            self.balances
135                .insert(from, &(from_balance.saturating_sub(value)));
136        }
137        let to_balance = self.balance_of(to);
138        // Total supply is limited by u128.MAX so no overflow is possible
139        self.balances
140            .insert(to, &(to_balance.saturating_add(value)));
141        Ok(vec![
142            approval_event(from, caller, allowance.saturating_sub(value)),
143            transfer_event(Some(from), Some(to), value),
144        ])
145    }
146
147    /// Sets a new `value` for allowance granted by `owner` to `spender`.
148    /// Overwrites the previously granted value.
149    pub fn approve(
150        &mut self,
151        owner: AccountId,
152        spender: AccountId,
153        value: u128,
154    ) -> Result<Vec<PSP22Event>, PSP22Error> {
155        if owner == spender {
156            return Ok(vec![]);
157        }
158        if value == 0 {
159            self.allowances.remove((owner, spender));
160        } else {
161            self.allowances.insert((owner, spender), &value);
162        }
163        Ok(vec![approval_event(owner, spender, value)])
164    }
165
166    /// Increases the allowance granted  by `owner` to `spender` by `delta_value`.
167    pub fn increase_allowance(
168        &mut self,
169        owner: AccountId,
170        spender: AccountId,
171        delta_value: u128,
172    ) -> Result<Vec<PSP22Event>, PSP22Error> {
173        if owner == spender || delta_value == 0 {
174            return Ok(vec![]);
175        }
176        let allowance = self.allowance(owner, spender);
177        let amount = allowance.saturating_add(delta_value);
178        self.allowances.insert((owner, spender), &amount);
179        Ok(vec![approval_event(owner, spender, amount)])
180    }
181
182    /// Decreases the allowance granted  by `owner` to `spender` by `delta_value`.
183    pub fn decrease_allowance(
184        &mut self,
185        owner: AccountId,
186        spender: AccountId,
187        delta_value: u128,
188    ) -> Result<Vec<PSP22Event>, PSP22Error> {
189        if owner == spender || delta_value == 0 {
190            return Ok(vec![]);
191        }
192        let allowance = self.allowance(owner, spender);
193        if allowance < delta_value {
194            return Err(PSP22Error::InsufficientAllowance);
195        }
196        let amount = allowance.saturating_sub(delta_value);
197        if amount == 0 {
198            self.allowances.remove((owner, spender));
199        } else {
200            self.allowances.insert((owner, spender), &amount);
201        }
202        Ok(vec![approval_event(owner, spender, amount)])
203    }
204
205    /// Mints a `value` of new tokens to `to` account.
206    pub fn mint(&mut self, to: AccountId, value: u128) -> Result<Vec<PSP22Event>, PSP22Error> {
207        if value == 0 {
208            return Ok(vec![]);
209        }
210        let new_supply = self
211            .total_supply
212            .checked_add(value)
213            .ok_or(PSP22Error::Custom(String::from(
214                "Max PSP22 supply exceeded. Max supply limited to 2^128-1.",
215            )))?;
216        self.total_supply = new_supply;
217        let new_balance = self.balance_of(to).saturating_add(value);
218        self.balances.insert(to, &new_balance);
219        Ok(vec![transfer_event(None, Some(to), value)])
220    }
221
222    /// Burns `value` tokens from `from` account.
223    pub fn burn(&mut self, from: AccountId, value: u128) -> Result<Vec<PSP22Event>, PSP22Error> {
224        if value == 0 {
225            return Ok(vec![]);
226        }
227        let balance = self.balance_of(from);
228        if balance < value {
229            return Err(PSP22Error::InsufficientBalance);
230        }
231        if balance == value {
232            self.balances.remove(from);
233        } else {
234            self.balances.insert(from, &(balance.saturating_sub(value)));
235        }
236        self.total_supply = self.total_supply.saturating_sub(value);
237        Ok(vec![transfer_event(Some(from), None, value)])
238    }
239}