Skip to content

Instantly share code, notes, and snippets.

@codeWhizperer
Created June 16, 2023 13:14
Show Gist options
  • Select an option

  • Save codeWhizperer/d7e8a4b8aea2eaf1c3fb6f5610f287f1 to your computer and use it in GitHub Desktop.

Select an option

Save codeWhizperer/d7e8a4b8aea2eaf1c3fb6f5610f287f1 to your computer and use it in GitHub Desktop.
#[contract]
mod ERC20{
////////////////
// LIBRARY IMPORTS
//////////////
use starknet::ContractAddress;
use zeroable::Zeroable;
use starknet::contract_address_const;
use integer::BoundedInt;
use starknet::get_caller_address;
////////////////
/// STATE VARIABLES
/////////////////
struct Storage{
_name:felt252,
_symbol:felt252,
_decimal:u8,
_total_supply: u256,
_balances: LegacyMap::<ContractAddress, u256>,
_allowance: LegacyMap::<(ContractAddress, ContractAddress), u256>
}
///////////
/// EVENTS
//////////
#[event]
fn Transfer(from:ContractAddress, to:ContractAddress, amount:u256){}
#[event]
fn Approval(owner:ContractAddress, spender:ContractAddress, amount:u256){}
#[constructor]
fn constructor(name:felt252, symbol:felt252, decimal:u8){
_name::write(name);
_symbol::write(symbol);
_decimal::write(decimal);
}
// /////////////
// /// view functions
// ////////////
#[view]
fn get_name() -> felt252{
return _name::read();
}
#[view]
fn get_symbol() -> felt252{
return _symbol::read();
}
#[view]
fn get_decimal() -> u8 {
return _decimal::read();
}
#[view]
fn get_total_supply() -> u256{
return _total_supply::read();
}
#[view]
fn balance_of(account: ContractAddress)-> u256{
return _balances::read(account);
}
#[view]
fn get_allowance(owner:ContractAddress, spender:ContractAddress) -> u256{
return _allowance::read((owner,spender));
}
////////////////
/// external functions
///////////////
#[external]
fn mint(recipient:ContractAddress, amount: u256) {
assert(!recipient.is_zero(), 'ERC20: address_zero');
// read prev total supply
let prev_total_supply = _total_supply::read();
// read prev recipient balance
let prev_recipient_balance = _balances::read(recipient);
// update total_supply
_total_supply::write(prev_total_supply + amount);
// update user balance
_balances::write(recipient, prev_recipient_balance + amount);
Transfer(Zeroable::zero(), recipient, amount);
}
#[external]
fn transfer_from(from:ContractAddress, to:ContractAddress, amount:u256) -> bool{
let msgSender = get_caller_address();
// _spend_allowance
_spend_allowance(from, msgSender, amount);
//_transfer
_transfer(from, to, amount);
return true;
}
#[external]
fn transfer(from:ContractAddress, to:ContractAddress, amount:u256) -> bool{
assert(!to.is_zero(), 'Address_zero');
_transfer(from, to, amount);
return true;
}
#[internal]
fn burn(account:ContractAddress, amount:u256) {
assert(!account.is_zero(), 'ERC20: address_zero');
_total_supply::write(_total_supply::read() - amount);
_balances::write(account, _balances::read(account) - amount);
Transfer(Zeroable::zero(), account, amount);
}
#[internal]
fn _transfer(from:ContractAddress, to:ContractAddress, amount:u256){
assert(!from.is_zero(), 'ERC20: address_zero');
assert(!to.is_zero(), 'ERC20: address_zero');
// alice send bob
_balances::write(from, _balances::read(from) - amount);
_balances::write(to, _balances::read(to) + amount);
}
#[internal]
fn _approve(owner:ContractAddress, spender:ContractAddress, amount:u256) {
assert(!owner.is_zero(), 'ERC20: address_zero');
assert(!spender.is_zero(), 'ERC20: address_zero');
_allowance::write((owner, spender), amount);
Approval(owner, spender, amount);
}
// #[external]
// fn
#[internal]
fn _spend_allowance(owner:ContractAddress, spender:ContractAddress, amount:u256){
let current_allowance = _allowance::read((owner, spender));
if current_allowance != BoundedInt::max(){
_approve(owner, spender, current_allowance - amount);
}
}
}
//////////////////////
Test
//////////////////
use simple_contract::contract::ERC20;
use array::ArrayTrait;
use result::ResultTrait;
use traits::Into;
const name:felt252 = 'ERC20';
const symbol:felt252 = 'ERCT';
const account:felt252 = 01001111;
fn __set__up () -> felt252{
let mut calldata = ArrayTrait::new();
calldata.append(name);
calldata.append(symbol);
calldata.append(18);
let address = deploy_contract('simple_contract', @calldata).unwrap();
return address;
}
#[test]
fn test_constructor(){
let deployment_address = __set__up();
let name = call(deployment_address, 'get_name', @ArrayTrait::new()).unwrap();
let symbol = call(deployment_address, 'get_symbol', @ArrayTrait::new()).unwrap();
assert(*name.at(0_u32) == 'ERC20', 'invalid name');
assert(*symbol.at(0_u32) == 'ERCT', 'invalid symbol');
}
#[test]
fn test_mint(){
let deployment_address = __set__up();
let mut calldata = ArrayTrait::new();
let mint_amount = u256 {high: 20, low: 0};
calldata.append(account);
calldata.append(mint_amount.high.into());
calldata.append(mint_amount.low.into());
invoke(deployment_address, 'mint', @calldata).unwrap();
let mut calldata2 = ArrayTrait::new();
calldata2.append(account);
let retdata = call(deployment_address, 'balance_of',@calldata2).unwrap();
assert(*retdata.at(0_u32) != 0, 'amount_is_zero');
}
@TEMHITHORPHE

Copy link
Copy Markdown

cool

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment