Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use Mapping in trait-erc20 Example #1086

Merged
merged 1 commit into from
Dec 16, 2021
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 61 additions & 28 deletions examples/trait-erc20/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,11 @@ use ink_lang as ink;
mod erc20 {
use ink_lang as ink;
use ink_storage::{
collections::HashMap as StorageHashMap,
lazy::Lazy,
lazy::{
Lazy,
Mapping,
},
traits::SpreadAllocate,
};

/// The ERC-20 error types.
Expand Down Expand Up @@ -59,14 +62,15 @@ mod erc20 {

/// A simple ERC-20 contract.
#[ink(storage)]
#[derive(SpreadAllocate)]
pub struct Erc20 {
/// Total token supply.
total_supply: Lazy<Balance>,
/// Mapping from owner to number of owned token.
balances: StorageHashMap<AccountId, Balance>,
balances: Mapping<AccountId, Balance>,
/// Mapping of the token amount which an account is allowed to withdraw
/// from another account.
allowances: StorageHashMap<(AccountId, AccountId), Balance>,
allowances: Mapping<(AccountId, AccountId), Balance>,
}

/// Event emitted when a token transfer occurs.
Expand Down Expand Up @@ -96,20 +100,21 @@ mod erc20 {
/// Creates a new ERC-20 contract with the specified initial supply.
#[ink(constructor)]
pub fn new(initial_supply: Balance) -> Self {
ink_lang::codegen::initialize_contract(|contract| {
Self::new_init(contract, initial_supply)
})
}

/// Default initializes the ERC-20 contract with the specified initial supply.
fn new_init(&mut self, initial_supply: Balance) {
let caller = Self::env().caller();
let mut balances = StorageHashMap::new();
balances.insert(caller, initial_supply);
let instance = Self {
total_supply: Lazy::new(initial_supply),
balances,
allowances: StorageHashMap::new(),
};
self.balances.insert(&caller, &initial_supply);
Lazy::set(&mut self.total_supply, initial_supply);
Self::env().emit_event(Transfer {
from: None,
to: Some(caller),
value: initial_supply,
});
instance
}
}

Expand All @@ -125,15 +130,15 @@ mod erc20 {
/// Returns `0` if the account is non-existent.
#[ink(message)]
fn balance_of(&self, owner: AccountId) -> Balance {
self.balances.get(&owner).copied().unwrap_or(0)
self.balance_of_impl(&owner)
}

/// Returns the amount which `spender` is still allowed to withdraw from `owner`.
///
/// Returns `0` if no allowance has been set `0`.
/// Returns `0` if no allowance has been set.
#[ink(message)]
fn allowance(&self, owner: AccountId, spender: AccountId) -> Balance {
self.allowances.get(&(owner, spender)).copied().unwrap_or(0)
self.allowance_impl(&owner, &spender)
}

/// Transfers `value` amount of tokens from the caller's account to account `to`.
Expand All @@ -147,7 +152,7 @@ mod erc20 {
#[ink(message)]
fn transfer(&mut self, to: AccountId, value: Balance) -> Result<()> {
let from = self.env().caller();
self.transfer_from_to(from, to, value)
self.transfer_from_to(&from, &to, value)
}

/// Allows `spender` to withdraw from the caller's account multiple times, up to
Expand All @@ -159,7 +164,7 @@ mod erc20 {
#[ink(message)]
fn approve(&mut self, spender: AccountId, value: Balance) -> Result<()> {
let owner = self.env().caller();
self.allowances.insert((owner, spender), value);
self.allowances.insert((&owner, &spender), &value);
self.env().emit_event(Approval {
owner,
spender,
Expand Down Expand Up @@ -190,18 +195,45 @@ mod erc20 {
value: Balance,
) -> Result<()> {
let caller = self.env().caller();
let allowance = self.allowance(from, caller);
let allowance = self.allowance_impl(&from, &caller);
if allowance < value {
return Err(Error::InsufficientAllowance)
}
self.transfer_from_to(from, to, value)?;
self.allowances.insert((from, caller), allowance - value);
self.transfer_from_to(&from, &to, value)?;
self.allowances
.insert((&from, &caller), &(allowance - value));
Ok(())
}
}

#[ink(impl)]
impl Erc20 {
/// Returns the account balance for the specified `owner`.
///
/// Returns `0` if the account is non-existent.
///
/// # Note
///
/// Prefer to call this method over `balance_of` since this
/// works using references which are more efficient in Wasm.
#[inline]
fn balance_of_impl(&self, owner: &AccountId) -> Balance {
self.balances.get(owner).unwrap_or_default()
}

/// Returns the amount which `spender` is still allowed to withdraw from `owner`.
///
/// Returns `0` if no allowance has been set.
///
/// # Note
///
/// Prefer to call this method over `allowance` since this
/// works using references which are more efficient in Wasm.
#[inline]
fn allowance_impl(&self, owner: &AccountId, spender: &AccountId) -> Balance {
self.allowances.get((owner, spender)).unwrap_or_default()
}

/// Transfers `value` amount of tokens from the caller's account to account `to`.
///
/// On success a `Transfer` event is emitted.
Expand All @@ -212,20 +244,21 @@ mod erc20 {
/// the caller's account balance.
fn transfer_from_to(
&mut self,
from: AccountId,
to: AccountId,
from: &AccountId,
to: &AccountId,
value: Balance,
) -> Result<()> {
let from_balance = self.balance_of(from);
let from_balance = self.balance_of_impl(from);
if from_balance < value {
return Err(Error::InsufficientBalance)
}
self.balances.insert(from, from_balance - value);
let to_balance = self.balance_of(to);
self.balances.insert(to, to_balance + value);

self.balances.insert(from, &(from_balance - value));
let to_balance = self.balance_of_impl(to);
self.balances.insert(to, &(to_balance + value));
self.env().emit_event(Transfer {
from: Some(from),
to: Some(to),
from: Some(*from),
to: Some(*to),
value,
});
Ok(())
Expand Down