use odra::{Variable, types::Address, contract_env, Mapping, execution_error, U256};
#[odra::module]
pub struct ERC20 {
name: Variable<String>,
symbol: Variable<String>,
decimals: Variable<u8>,
total_supply: Variable<U256>,
balances: Mapping<Address, U256>,
allowed: Mapping<(Address, Address), U256>
}
#[odra::module]
impl ERC20 {
#[odra(init)]
pub fn init(&mut self, name: String, symbol: String, decimals: u8, total_supply: U256) {
self.name.set(name);
self.symbol.set(symbol);
self.decimals.set(decimals);
self.total_supply.set(total_supply);
self.balances.set(&contract_env::caller(), total_supply);
}
pub fn total_supply(&self) -> U256 {
self.total_supply.get_or_default()
}
pub fn balance_of(&self, owner: Address) -> U256 {
self.balances.get_or_default(&owner)
}
pub fn transfer(&mut self, to: Address, value: U256) {
let from = contract_env::caller();
let from_balance = self.balances.get_or_default(&from);
let to_balance = self.balances.get_or_default(&to);
if from_balance < value {
contract_env::revert(Error::InsufficientBalance);
}
self.balances.set(&from, from_balance - value);
self.balances.set(&to, to_balance + value);
}
pub fn transfer_from(&mut self, from: Address, to: Address, value: U256) {
let caller = contract_env::caller();
let from_balance = self.balances.get_or_default(&from);
let to_balance = self.balances.get_or_default(&to);
let allowed = self.allowed.get_or_default(&(from, caller));
if from_balance < value {
contract_env::revert(Error::InsufficientBalance);
}
if allowed < value {
contract_env::revert(Error::InsufficientAllowance);
}
self.balances.set(&from, from_balance - value);
self.balances.set(&to, to_balance + value);
self.allowed.set(&(from, caller), allowed - value);
}
pub fn approve(&mut self, spender: Address, value: U256) {
let owner = contract_env::caller();
self.allowed.set(&(owner, spender), value);
}
pub fn allowance(&self, owner: Address, spender: Address) -> U256 {
self.allowed.get_or_default(&(owner, spender))
}
}
execution_error! {
pub enum Error {
InsufficientBalance => 1,
InsufficientAllowance => 2,
}
}