Created
June 16, 2023 13:14
-
-
Save codeWhizperer/d7e8a4b8aea2eaf1c3fb6f5610f287f1 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #[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'); | |
| } | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
cool