Skip to content

Commit

Permalink
feat: add erc20
Browse files Browse the repository at this point in the history
  • Loading branch information
Th0rgal committed Aug 14, 2023
1 parent 77273fa commit 492fa38
Showing 1 changed file with 232 additions and 0 deletions.
232 changes: 232 additions & 0 deletions src/tests/erc20.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,232 @@
#[starknet::contract]
mod ERC20 {
use integer::BoundedInt;
use openzeppelin::token::erc20::interface::IERC20;
use openzeppelin::token::erc20::interface::IERC20CamelOnly;
use starknet::ContractAddress;
use starknet::get_caller_address;
use zeroable::Zeroable;

#[storage]
struct Storage {
_name: felt252,
_symbol: felt252,
_total_supply: u256,
_balances: LegacyMap<ContractAddress, u256>,
_allowances: LegacyMap<(ContractAddress, ContractAddress), u256>,
}

#[event]
#[derive(Drop, starknet::Event)]
enum Event {
Transfer: Transfer,
Approval: Approval,
}

#[derive(Drop, starknet::Event)]
struct Transfer {
from: ContractAddress,
to: ContractAddress,
value: u256
}

#[derive(Drop, starknet::Event)]
struct Approval {
owner: ContractAddress,
spender: ContractAddress,
value: u256
}

#[constructor]
fn constructor(
ref self: ContractState,
name: felt252,
symbol: felt252,
initial_supply: u256,
recipient: ContractAddress
) {
self.initializer(name, symbol);
self._mint(recipient, initial_supply);
}

//
// External
//

#[external(v0)]
impl ERC20Impl of IERC20<ContractState> {
fn name(self: @ContractState) -> felt252 {
self._name.read()
}

fn symbol(self: @ContractState) -> felt252 {
self._symbol.read()
}

fn decimals(self: @ContractState) -> u8 {
18
}

fn total_supply(self: @ContractState) -> u256 {
self._total_supply.read()
}

fn balance_of(self: @ContractState, account: ContractAddress) -> u256 {
self._balances.read(account)
}

fn allowance(
self: @ContractState, owner: ContractAddress, spender: ContractAddress
) -> u256 {
self._allowances.read((owner, spender))
}

fn transfer(ref self: ContractState, recipient: ContractAddress, amount: u256) -> bool {
let sender = get_caller_address();
self._transfer(sender, recipient, amount);
true
}

fn transfer_from(
ref self: ContractState,
sender: ContractAddress,
recipient: ContractAddress,
amount: u256
) -> bool {
let caller = get_caller_address();
self._spend_allowance(sender, caller, amount);
self._transfer(sender, recipient, amount);
true
}

fn approve(ref self: ContractState, spender: ContractAddress, amount: u256) -> bool {
let caller = get_caller_address();
self._approve(caller, spender, amount);
true
}
}

#[external(v0)]
impl ERC20CamelOnlyImpl of IERC20CamelOnly<ContractState> {
fn totalSupply(self: @ContractState) -> u256 {
ERC20Impl::total_supply(self)
}

fn balanceOf(self: @ContractState, account: ContractAddress) -> u256 {
ERC20Impl::balance_of(self, account)
}

fn transferFrom(
ref self: ContractState,
sender: ContractAddress,
recipient: ContractAddress,
amount: u256
) -> bool {
ERC20Impl::transfer_from(ref self, sender, recipient, amount)
}
}

#[external(v0)]
fn increase_allowance(
ref self: ContractState, spender: ContractAddress, added_value: u256
) -> bool {
self._increase_allowance(spender, added_value)
}

#[external(v0)]
fn increaseAllowance(
ref self: ContractState, spender: ContractAddress, addedValue: u256
) -> bool {
increase_allowance(ref self, spender, addedValue)
}

#[external(v0)]
fn decrease_allowance(
ref self: ContractState, spender: ContractAddress, subtracted_value: u256
) -> bool {
self._decrease_allowance(spender, subtracted_value)
}

#[external(v0)]
fn decreaseAllowance(
ref self: ContractState, spender: ContractAddress, subtractedValue: u256
) -> bool {
decrease_allowance(ref self, spender, subtractedValue)
}

//
// Internal
//

#[generate_trait]
impl InternalImpl of InternalTrait {
fn initializer(ref self: ContractState, name_: felt252, symbol_: felt252) {
self._name.write(name_);
self._symbol.write(symbol_);
}

fn _increase_allowance(
ref self: ContractState, spender: ContractAddress, added_value: u256
) -> bool {
let caller = get_caller_address();
self._approve(caller, spender, self._allowances.read((caller, spender)) + added_value);
true
}

fn _decrease_allowance(
ref self: ContractState, spender: ContractAddress, subtracted_value: u256
) -> bool {
let caller = get_caller_address();
self
._approve(
caller, spender, self._allowances.read((caller, spender)) - subtracted_value
);
true
}

fn _mint(ref self: ContractState, recipient: ContractAddress, amount: u256) {
assert(!recipient.is_zero(), 'ERC20: mint to 0');
self._total_supply.write(self._total_supply.read() + amount);
self._balances.write(recipient, self._balances.read(recipient) + amount);
self.emit(Transfer { from: Zeroable::zero(), to: recipient, value: amount });
}

fn _burn(ref self: ContractState, account: ContractAddress, amount: u256) {
assert(!account.is_zero(), 'ERC20: burn from 0');
self._total_supply.write(self._total_supply.read() - amount);
self._balances.write(account, self._balances.read(account) - amount);
self.emit(Transfer { from: account, to: Zeroable::zero(), value: amount });
}

fn _approve(
ref self: ContractState, owner: ContractAddress, spender: ContractAddress, amount: u256
) {
assert(!owner.is_zero(), 'ERC20: approve from 0');
assert(!spender.is_zero(), 'ERC20: approve to 0');
self._allowances.write((owner, spender), amount);
self.emit(Approval { owner, spender, value: amount });
}

fn _transfer(
ref self: ContractState,
sender: ContractAddress,
recipient: ContractAddress,
amount: u256
) {
assert(!sender.is_zero(), 'ERC20: transfer from 0');
assert(!recipient.is_zero(), 'ERC20: transfer to 0');
self._balances.write(sender, self._balances.read(sender) - amount);
self._balances.write(recipient, self._balances.read(recipient) + amount);
self.emit(Transfer { from: sender, to: recipient, value: amount });
}

fn _spend_allowance(
ref self: ContractState, owner: ContractAddress, spender: ContractAddress, amount: u256
) {
let current_allowance = self._allowances.read((owner, spender));
if current_allowance != BoundedInt::max() {
self._approve(owner, spender, current_allowance - amount);
}
}
}
}

0 comments on commit 492fa38

Please sign in to comment.