From 556eccc9000db269afefad3b93095a05d76d8022 Mon Sep 17 00:00:00 2001 From: the-first-elder Date: Mon, 27 May 2024 16:47:45 +0100 Subject: [PATCH 1/9] added erc20 unit test --- listings/applications/erc20/src/lib.cairo | 2 +- listings/applications/erc20/src/tests.cairo | 335 +++++++++++++++++++- listings/applications/erc20/src/token.cairo | 28 +- 3 files changed, 349 insertions(+), 16 deletions(-) diff --git a/listings/applications/erc20/src/lib.cairo b/listings/applications/erc20/src/lib.cairo index 4ab2be17..51c78654 100644 --- a/listings/applications/erc20/src/lib.cairo +++ b/listings/applications/erc20/src/lib.cairo @@ -1,4 +1,4 @@ -mod token; +pub mod token; #[cfg(test)] mod tests; diff --git a/listings/applications/erc20/src/tests.cairo b/listings/applications/erc20/src/tests.cairo index 361dba07..05d83e69 100644 --- a/listings/applications/erc20/src/tests.cairo +++ b/listings/applications/erc20/src/tests.cairo @@ -1,2 +1,335 @@ -mod tests { // TODO +mod tests { + use super::super::token::{ + erc20, IERC20Dispatcher, IERC20DispatcherTrait, erc20::{Event, Transfer, Approval} + }; + + use starknet::{ + ContractAddress, SyscallResultTrait, syscalls::deploy_syscall, get_caller_address, + contract_address_const + }; + + use starknet::testing::{set_contract_address, set_account_contract_address}; + + + fn deploy() -> (IERC20Dispatcher, ContractAddress) { + let recipient: ContractAddress = contract_address_const::<'recipient'>(); + + let token_name: felt252 = 'myToken'; + let decimals: felt252 = 18; + let initial_supply: felt252 = 100000; + let symbols: felt252 = 'mtk'; + + let (contract_address, _) = deploy_syscall( + erc20::TEST_CLASS_HASH.try_into().unwrap(), + recipient.into(), + array![recipient.into(), token_name, decimals, initial_supply, symbols].span(), + false + ) + .unwrap_syscall(); + + (IERC20Dispatcher { contract_address }, contract_address) + } + + fn recipient_address() -> ContractAddress { + let recipient: ContractAddress = contract_address_const::<'recipient'>(); + + recipient + } + + fn spender_address() -> ContractAddress { + let spender = contract_address_const::<'spender'>(); + spender + } + + fn zero_address() -> ContractAddress { + get_caller_address() + } + + #[test] + #[should_panic] + fn test_deploy_when_recipient_is_address_zero() { + let recipient: ContractAddress = zero_address(); + + let token_name: felt252 = 'myToken'; + let decimals: felt252 = 18; + let initial_supply: felt252 = 100000; + let symbols: felt252 = 'mtk'; + + let (contract_address, _) = deploy_syscall( + erc20::TEST_CLASS_HASH.try_into().unwrap(), + recipient.into(), + array![recipient.into(), token_name, decimals, initial_supply, symbols].span(), + false + ) + .unwrap_syscall(); + } + #[test] + fn test_deploy_success() { + let recipient = recipient_address(); + let (_, contract_address) = deploy(); + assert_eq!( + starknet::testing::pop_log(contract_address), + Option::Some( + Event::Transfer(Transfer { from: zero_address(), to: recipient, value: 100000 }) + ) + ); + } + + + #[test] + fn test_get_name() { + let (dispatcher, _) = deploy(); + let name = dispatcher.get_name(); + assert(name == 'myToken', 'wrong token name'); + } + + #[test] + fn test_get_symbol() { + let (dispatcher, _) = deploy(); + assert(dispatcher.get_symbol() == 'mtk', 'wrong symbol'); + } + + #[test] + fn test_get_decimals() { + let (dispatcher, _) = deploy(); + assert(dispatcher.get_decimals() == 18, 'wrong decimals'); + } + + #[test] + fn test_total_supply() { + let (dispatcher, _) = deploy(); + assert(dispatcher.get_total_supply() == 100000, 'wrong total supply'); + } + + #[test] + fn test_balance_of_recipient_deployed() { + let recipient = recipient_address(); + let (dispatcher, _) = deploy(); + assert(dispatcher.balance_of(recipient) == 100000, 'incorrect balance of recipient'); + } + + #[test] + fn test_allowance_without_approval() { + let caller = contract_address_const::<'caller'>(); + let spender = spender_address(); + let (dispatcher, _) = deploy(); + set_contract_address(caller); + assert(dispatcher.allowance(caller, spender) == 0, 'incorrect allowance') + } + + #[test] + fn test_allowance_after_approval() { + let caller = contract_address_const::<'caller'>(); + let spender = spender_address(); + let (dispatcher, _) = deploy(); + set_contract_address(caller); + dispatcher.approve(spender, 100); + assert(dispatcher.allowance(caller, spender) == 100, 'incorrect allowance') + } + + #[test] + #[should_panic] + fn test_approval_spender_is_address_zero() { + let spender: ContractAddress = zero_address(); + + let (dispatcher, _) = deploy(); + dispatcher.approve(spender, 100); + } + + #[test] + fn test_approval_success() { + let recipient = recipient_address(); + let spender = spender_address(); + let value = 100; + + let (dispatcher, contract_address) = deploy(); + let caller = contract_address_const::<'caller'>(); + set_contract_address(caller); + dispatcher.approve(spender, value); + set_contract_address(contract_address); + + // Notice the order: the first event emitted is the first to be popped. + /// ANCHOR: test_events + assert_eq!( + starknet::testing::pop_log(contract_address), + Option::Some( + Event::Transfer(Transfer { from: zero_address(), to: recipient, value: 100000 }) + ) + ); + + assert_eq!( + starknet::testing::pop_log(contract_address), + Option::Some(Event::Approval(Approval { owner: caller, spender, value })) + ); + } + + #[test] + #[should_panic] + fn test_should_increase_allowance_with_spender_zero_address() { + let spender = zero_address(); + let (dispatcher, _) = deploy(); + dispatcher.increase_allowance(spender, 100); + } + + #[test] + fn test_should_increase_allowance() { + let caller = contract_address_const::<'caller'>(); + let recipient = recipient_address(); + let spender = spender_address(); + let (dispatcher, contract_address) = deploy(); + set_contract_address(caller); + dispatcher.approve(spender, 100); + assert(dispatcher.allowance(caller, spender) == 100, 'incorrect allowance'); + set_contract_address(caller); + dispatcher.increase_allowance(spender, 100); + assert(dispatcher.allowance(caller, spender) == 200, 'incorrect increased allowance'); + + // emits one transfer event and two approval events + + assert_eq!( + starknet::testing::pop_log(contract_address), + Option::Some( + Event::Transfer(Transfer { from: zero_address(), to: recipient, value: 100000 }) + ) + ); + + assert_eq!( + starknet::testing::pop_log(contract_address), + Option::Some(Event::Approval(Approval { owner: caller, spender, value: 100 })) + ); + + assert_eq!( + starknet::testing::pop_log(contract_address), + Option::Some(Event::Approval(Approval { owner: caller, spender, value: 200 })) + ); + } + + #[test] + #[should_panic] + fn test_should_decrease_allowance_with_spender_zero_address() { + let spender = zero_address(); + let (dispatcher, _) = deploy(); + dispatcher.decrease_allowance(spender, 100); + } + + #[test] + fn test_should_decrease_allowance() { + let caller = contract_address_const::<'caller'>(); + let recipient = recipient_address(); + let spender = spender_address(); + let (dispatcher, contract_address) = deploy(); + set_contract_address(caller); + dispatcher.approve(spender, 100); + assert(dispatcher.allowance(caller, spender) == 100, 'incorrect allowance'); + + set_contract_address(caller); + dispatcher.decrease_allowance(spender, 90); + assert(dispatcher.allowance(caller, spender) == 10, 'incorrect decreased allowance'); + + // emits one transfer event and two approval events + + assert_eq!( + starknet::testing::pop_log(contract_address), + Option::Some( + Event::Transfer(Transfer { from: zero_address(), to: recipient, value: 100000 }) + ) + ); + + assert_eq!( + starknet::testing::pop_log(contract_address), + Option::Some(Event::Approval(Approval { owner: caller, spender, value: 100 })) + ); + + assert_eq!( + starknet::testing::pop_log(contract_address), + Option::Some(Event::Approval(Approval { owner: caller, spender, value: 10 })) + ); + } + + #[test] + #[should_panic] + fn test_transfer_when_sender_is_address_zero() { + let reciever = spender_address(); + let (dispatcher, _) = deploy(); + dispatcher.transfer(reciever, 100); + } + + #[test] + #[should_panic] + fn test_transfer_when_recipient_is_address_zero() { + let caller = contract_address_const::<'caller'>(); + let reciever = zero_address(); + let (dispatcher, _) = deploy(); + set_contract_address(caller); + dispatcher.transfer(reciever, 100); + } + + #[test] + fn test_transfer_success() { + let caller = recipient_address(); + let reciever = contract_address_const::<'receiver'>(); + let recipient = recipient_address(); + let (dispatcher, contract_address) = deploy(); + set_contract_address(caller); + dispatcher.transfer(reciever, 100); + assert_eq!(dispatcher.balance_of(reciever), 100); + + // emits two transfer events + assert_eq!( + starknet::testing::pop_log(contract_address), + Option::Some( + Event::Transfer(Transfer { from: zero_address(), to: recipient, value: 100000 }) + ) + ); + + assert_eq!( + starknet::testing::pop_log(contract_address), + Option::Some(Event::Transfer(Transfer { from: caller, to: reciever, value: 100 })) + ); + } + + + #[test] + #[should_panic] + fn test_transferFrom_when_sender_is_address_zero() { + let sender = zero_address(); + let reciever = spender_address(); + let (dispatcher, _) = deploy(); + dispatcher.transfer_from(sender, reciever, 100); + } + + #[test] + #[should_panic] + fn test_transferFrom_when_recipient_is_address_zero() { + let caller = contract_address_const::<'caller'>(); + let reciever = zero_address(); + let (dispatcher, _) = deploy(); + set_contract_address(caller); + dispatcher.transfer_from(caller, reciever, 100); + } + + #[test] + fn test_transferFrom_success() { + let caller = recipient_address(); + let reciever = contract_address_const::<'receiver'>(); + let recipient = recipient_address(); + let (dispatcher, contract_address) = deploy(); + set_contract_address(caller); + dispatcher.transfer_from(caller, reciever, 100); + assert_eq!(dispatcher.balance_of(reciever), 100); + + // emits two transfer events + + assert_eq!( + starknet::testing::pop_log(contract_address), + Option::Some( + Event::Transfer(Transfer { from: zero_address(), to: recipient, value: 100000 }) + ) + ); + + assert_eq!( + starknet::testing::pop_log(contract_address), + Option::Some(Event::Transfer(Transfer { from: caller, to: reciever, value: 100 })) + ); + } } diff --git a/listings/applications/erc20/src/token.cairo b/listings/applications/erc20/src/token.cairo index da9f19a8..eb794ed8 100644 --- a/listings/applications/erc20/src/token.cairo +++ b/listings/applications/erc20/src/token.cairo @@ -2,7 +2,7 @@ use starknet::ContractAddress; // ANCHOR: interface #[starknet::interface] -trait IERC20 { +pub trait IERC20 { fn get_name(self: @TContractState) -> felt252; fn get_symbol(self: @TContractState) -> felt252; fn get_decimals(self: @TContractState) -> u8; @@ -28,7 +28,7 @@ trait IERC20 { // ANCHOR: erc20 #[starknet::contract] -mod erc20 { +pub mod erc20 { use core::num::traits::Zero; use starknet::get_caller_address; use starknet::contract_address_const; @@ -45,22 +45,22 @@ mod erc20 { } #[event] - #[derive(Drop, starknet::Event)] - enum Event { + #[derive(Copy, Drop, Debug, PartialEq, starknet::Event)] + pub enum Event { Transfer: Transfer, Approval: Approval, } - #[derive(Drop, starknet::Event)] - struct Transfer { - from: ContractAddress, - to: ContractAddress, - value: felt252, + #[derive(Copy, Drop, Debug, PartialEq, starknet::Event)] + pub struct Transfer { + pub from: ContractAddress, + pub to: ContractAddress, + pub value: felt252, } - #[derive(Drop, starknet::Event)] - struct Approval { - owner: ContractAddress, - spender: ContractAddress, - value: felt252, + #[derive(Copy, Drop, Debug, PartialEq, starknet::Event)] + pub struct Approval { + pub owner: ContractAddress, + pub spender: ContractAddress, + pub value: felt252, } mod Errors { From b3a1449522b1b80d9f0d1e4a89fa3626e4842968 Mon Sep 17 00:00:00 2001 From: the-first-elder Date: Mon, 27 May 2024 23:35:05 +0100 Subject: [PATCH 2/9] added test against custom errors --- listings/applications/erc20/src/tests.cairo | 40 ++++++++++++++++----- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/listings/applications/erc20/src/tests.cairo b/listings/applications/erc20/src/tests.cairo index 05d83e69..679601a3 100644 --- a/listings/applications/erc20/src/tests.cairo +++ b/listings/applications/erc20/src/tests.cairo @@ -46,7 +46,8 @@ mod tests { } #[test] - #[should_panic] + #[available_gas(2000000)] + #[should_panic(expected : ('ERC20: mint to 0', 'CONSTRUCTOR_FAILED'))] fn test_deploy_when_recipient_is_address_zero() { let recipient: ContractAddress = zero_address(); @@ -64,6 +65,7 @@ mod tests { .unwrap_syscall(); } #[test] + #[available_gas(2000000)] fn test_deploy_success() { let recipient = recipient_address(); let (_, contract_address) = deploy(); @@ -77,6 +79,7 @@ mod tests { #[test] + #[available_gas(2000000)] fn test_get_name() { let (dispatcher, _) = deploy(); let name = dispatcher.get_name(); @@ -84,24 +87,28 @@ mod tests { } #[test] + #[available_gas(2000000)] fn test_get_symbol() { let (dispatcher, _) = deploy(); assert(dispatcher.get_symbol() == 'mtk', 'wrong symbol'); } #[test] + #[available_gas(2000000)] fn test_get_decimals() { let (dispatcher, _) = deploy(); assert(dispatcher.get_decimals() == 18, 'wrong decimals'); } #[test] + #[available_gas(2000000)] fn test_total_supply() { let (dispatcher, _) = deploy(); assert(dispatcher.get_total_supply() == 100000, 'wrong total supply'); } #[test] + #[available_gas(2000000)] fn test_balance_of_recipient_deployed() { let recipient = recipient_address(); let (dispatcher, _) = deploy(); @@ -109,6 +116,7 @@ mod tests { } #[test] + #[available_gas(2000000)] fn test_allowance_without_approval() { let caller = contract_address_const::<'caller'>(); let spender = spender_address(); @@ -118,6 +126,7 @@ mod tests { } #[test] + #[available_gas(2000000)] fn test_allowance_after_approval() { let caller = contract_address_const::<'caller'>(); let spender = spender_address(); @@ -128,7 +137,8 @@ mod tests { } #[test] - #[should_panic] + #[available_gas(2000000)] + #[should_panic(expected:('ERC20: approve to 0','ENTRYPOINT_FAILED'))] fn test_approval_spender_is_address_zero() { let spender: ContractAddress = zero_address(); @@ -137,6 +147,7 @@ mod tests { } #[test] + #[available_gas(2000000)] fn test_approval_success() { let recipient = recipient_address(); let spender = spender_address(); @@ -164,7 +175,8 @@ mod tests { } #[test] - #[should_panic] + #[available_gas(2000000)] + #[should_panic(expected:('ERC20: approve to 0','ENTRYPOINT_FAILED'))] fn test_should_increase_allowance_with_spender_zero_address() { let spender = zero_address(); let (dispatcher, _) = deploy(); @@ -172,6 +184,7 @@ mod tests { } #[test] + #[available_gas(2000000)] fn test_should_increase_allowance() { let caller = contract_address_const::<'caller'>(); let recipient = recipient_address(); @@ -205,7 +218,8 @@ mod tests { } #[test] - #[should_panic] + #[available_gas(2000000)] + #[should_panic (expected:('ERC20: approve to 0','ENTRYPOINT_FAILED'))] fn test_should_decrease_allowance_with_spender_zero_address() { let spender = zero_address(); let (dispatcher, _) = deploy(); @@ -213,6 +227,7 @@ mod tests { } #[test] + #[available_gas(2000000)] fn test_should_decrease_allowance() { let caller = contract_address_const::<'caller'>(); let recipient = recipient_address(); @@ -247,7 +262,8 @@ mod tests { } #[test] - #[should_panic] + #[available_gas(2000000)] + #[should_panic (expected:('ERC20: transfer from 0','ENTRYPOINT_FAILED'))] fn test_transfer_when_sender_is_address_zero() { let reciever = spender_address(); let (dispatcher, _) = deploy(); @@ -255,7 +271,9 @@ mod tests { } #[test] - #[should_panic] + #[available_gas(2000000)] + #[should_panic (expected:('ERC20: transfer to 0','ENTRYPOINT_FAILED'))] + #[should_panic ] fn test_transfer_when_recipient_is_address_zero() { let caller = contract_address_const::<'caller'>(); let reciever = zero_address(); @@ -265,6 +283,7 @@ mod tests { } #[test] + #[available_gas(2000000)] fn test_transfer_success() { let caller = recipient_address(); let reciever = contract_address_const::<'receiver'>(); @@ -290,7 +309,9 @@ mod tests { #[test] - #[should_panic] + #[available_gas(2000000)] + #[should_panic (expected:('ERC20: transfer from 0','ENTRYPOINT_FAILED'))] + #[should_panic ] fn test_transferFrom_when_sender_is_address_zero() { let sender = zero_address(); let reciever = spender_address(); @@ -299,7 +320,9 @@ mod tests { } #[test] - #[should_panic] + #[available_gas(2000000)] + #[should_panic (expected:('ERC20: transfer to 0','ENTRYPOINT_FAILED'))] + #[should_panic ] fn test_transferFrom_when_recipient_is_address_zero() { let caller = contract_address_const::<'caller'>(); let reciever = zero_address(); @@ -309,6 +332,7 @@ mod tests { } #[test] + #[available_gas(2000000)] fn test_transferFrom_success() { let caller = recipient_address(); let reciever = contract_address_const::<'receiver'>(); From 8ee155e2612e4fd20110f3d866896b54535381f0 Mon Sep 17 00:00:00 2001 From: the-first-elder Date: Mon, 27 May 2024 23:35:45 +0100 Subject: [PATCH 3/9] formated --- listings/applications/erc20/src/tests.cairo | 22 ++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/listings/applications/erc20/src/tests.cairo b/listings/applications/erc20/src/tests.cairo index 679601a3..feb26fce 100644 --- a/listings/applications/erc20/src/tests.cairo +++ b/listings/applications/erc20/src/tests.cairo @@ -47,7 +47,7 @@ mod tests { #[test] #[available_gas(2000000)] - #[should_panic(expected : ('ERC20: mint to 0', 'CONSTRUCTOR_FAILED'))] + #[should_panic(expected: ('ERC20: mint to 0', 'CONSTRUCTOR_FAILED'))] fn test_deploy_when_recipient_is_address_zero() { let recipient: ContractAddress = zero_address(); @@ -138,7 +138,7 @@ mod tests { #[test] #[available_gas(2000000)] - #[should_panic(expected:('ERC20: approve to 0','ENTRYPOINT_FAILED'))] + #[should_panic(expected: ('ERC20: approve to 0', 'ENTRYPOINT_FAILED'))] fn test_approval_spender_is_address_zero() { let spender: ContractAddress = zero_address(); @@ -176,7 +176,7 @@ mod tests { #[test] #[available_gas(2000000)] - #[should_panic(expected:('ERC20: approve to 0','ENTRYPOINT_FAILED'))] + #[should_panic(expected: ('ERC20: approve to 0', 'ENTRYPOINT_FAILED'))] fn test_should_increase_allowance_with_spender_zero_address() { let spender = zero_address(); let (dispatcher, _) = deploy(); @@ -219,7 +219,7 @@ mod tests { #[test] #[available_gas(2000000)] - #[should_panic (expected:('ERC20: approve to 0','ENTRYPOINT_FAILED'))] + #[should_panic(expected: ('ERC20: approve to 0', 'ENTRYPOINT_FAILED'))] fn test_should_decrease_allowance_with_spender_zero_address() { let spender = zero_address(); let (dispatcher, _) = deploy(); @@ -263,7 +263,7 @@ mod tests { #[test] #[available_gas(2000000)] - #[should_panic (expected:('ERC20: transfer from 0','ENTRYPOINT_FAILED'))] + #[should_panic(expected: ('ERC20: transfer from 0', 'ENTRYPOINT_FAILED'))] fn test_transfer_when_sender_is_address_zero() { let reciever = spender_address(); let (dispatcher, _) = deploy(); @@ -272,8 +272,8 @@ mod tests { #[test] #[available_gas(2000000)] - #[should_panic (expected:('ERC20: transfer to 0','ENTRYPOINT_FAILED'))] - #[should_panic ] + #[should_panic(expected: ('ERC20: transfer to 0', 'ENTRYPOINT_FAILED'))] + #[should_panic] fn test_transfer_when_recipient_is_address_zero() { let caller = contract_address_const::<'caller'>(); let reciever = zero_address(); @@ -310,8 +310,8 @@ mod tests { #[test] #[available_gas(2000000)] - #[should_panic (expected:('ERC20: transfer from 0','ENTRYPOINT_FAILED'))] - #[should_panic ] + #[should_panic(expected: ('ERC20: transfer from 0', 'ENTRYPOINT_FAILED'))] + #[should_panic] fn test_transferFrom_when_sender_is_address_zero() { let sender = zero_address(); let reciever = spender_address(); @@ -321,8 +321,8 @@ mod tests { #[test] #[available_gas(2000000)] - #[should_panic (expected:('ERC20: transfer to 0','ENTRYPOINT_FAILED'))] - #[should_panic ] + #[should_panic(expected: ('ERC20: transfer to 0', 'ENTRYPOINT_FAILED'))] + #[should_panic] fn test_transferFrom_when_recipient_is_address_zero() { let caller = contract_address_const::<'caller'>(); let reciever = zero_address(); From 7462520104ebbfac84ffea5421776f5a96fb1419 Mon Sep 17 00:00:00 2001 From: the-first-elder Date: Tue, 28 May 2024 11:24:27 +0100 Subject: [PATCH 4/9] made requested changes and moved test to contract module --- listings/applications/erc20/src/lib.cairo | 2 +- listings/applications/erc20/src/tests.cairo | 360 +------------------- listings/applications/erc20/src/token.cairo | 340 ++++++++++++++++++ 3 files changed, 342 insertions(+), 360 deletions(-) diff --git a/listings/applications/erc20/src/lib.cairo b/listings/applications/erc20/src/lib.cairo index 51c78654..4ab2be17 100644 --- a/listings/applications/erc20/src/lib.cairo +++ b/listings/applications/erc20/src/lib.cairo @@ -1,4 +1,4 @@ -pub mod token; +mod token; #[cfg(test)] mod tests; diff --git a/listings/applications/erc20/src/tests.cairo b/listings/applications/erc20/src/tests.cairo index feb26fce..26c0e3f7 100644 --- a/listings/applications/erc20/src/tests.cairo +++ b/listings/applications/erc20/src/tests.cairo @@ -1,359 +1 @@ -mod tests { - use super::super::token::{ - erc20, IERC20Dispatcher, IERC20DispatcherTrait, erc20::{Event, Transfer, Approval} - }; - - use starknet::{ - ContractAddress, SyscallResultTrait, syscalls::deploy_syscall, get_caller_address, - contract_address_const - }; - - use starknet::testing::{set_contract_address, set_account_contract_address}; - - - fn deploy() -> (IERC20Dispatcher, ContractAddress) { - let recipient: ContractAddress = contract_address_const::<'recipient'>(); - - let token_name: felt252 = 'myToken'; - let decimals: felt252 = 18; - let initial_supply: felt252 = 100000; - let symbols: felt252 = 'mtk'; - - let (contract_address, _) = deploy_syscall( - erc20::TEST_CLASS_HASH.try_into().unwrap(), - recipient.into(), - array![recipient.into(), token_name, decimals, initial_supply, symbols].span(), - false - ) - .unwrap_syscall(); - - (IERC20Dispatcher { contract_address }, contract_address) - } - - fn recipient_address() -> ContractAddress { - let recipient: ContractAddress = contract_address_const::<'recipient'>(); - - recipient - } - - fn spender_address() -> ContractAddress { - let spender = contract_address_const::<'spender'>(); - spender - } - - fn zero_address() -> ContractAddress { - get_caller_address() - } - - #[test] - #[available_gas(2000000)] - #[should_panic(expected: ('ERC20: mint to 0', 'CONSTRUCTOR_FAILED'))] - fn test_deploy_when_recipient_is_address_zero() { - let recipient: ContractAddress = zero_address(); - - let token_name: felt252 = 'myToken'; - let decimals: felt252 = 18; - let initial_supply: felt252 = 100000; - let symbols: felt252 = 'mtk'; - - let (contract_address, _) = deploy_syscall( - erc20::TEST_CLASS_HASH.try_into().unwrap(), - recipient.into(), - array![recipient.into(), token_name, decimals, initial_supply, symbols].span(), - false - ) - .unwrap_syscall(); - } - #[test] - #[available_gas(2000000)] - fn test_deploy_success() { - let recipient = recipient_address(); - let (_, contract_address) = deploy(); - assert_eq!( - starknet::testing::pop_log(contract_address), - Option::Some( - Event::Transfer(Transfer { from: zero_address(), to: recipient, value: 100000 }) - ) - ); - } - - - #[test] - #[available_gas(2000000)] - fn test_get_name() { - let (dispatcher, _) = deploy(); - let name = dispatcher.get_name(); - assert(name == 'myToken', 'wrong token name'); - } - - #[test] - #[available_gas(2000000)] - fn test_get_symbol() { - let (dispatcher, _) = deploy(); - assert(dispatcher.get_symbol() == 'mtk', 'wrong symbol'); - } - - #[test] - #[available_gas(2000000)] - fn test_get_decimals() { - let (dispatcher, _) = deploy(); - assert(dispatcher.get_decimals() == 18, 'wrong decimals'); - } - - #[test] - #[available_gas(2000000)] - fn test_total_supply() { - let (dispatcher, _) = deploy(); - assert(dispatcher.get_total_supply() == 100000, 'wrong total supply'); - } - - #[test] - #[available_gas(2000000)] - fn test_balance_of_recipient_deployed() { - let recipient = recipient_address(); - let (dispatcher, _) = deploy(); - assert(dispatcher.balance_of(recipient) == 100000, 'incorrect balance of recipient'); - } - - #[test] - #[available_gas(2000000)] - fn test_allowance_without_approval() { - let caller = contract_address_const::<'caller'>(); - let spender = spender_address(); - let (dispatcher, _) = deploy(); - set_contract_address(caller); - assert(dispatcher.allowance(caller, spender) == 0, 'incorrect allowance') - } - - #[test] - #[available_gas(2000000)] - fn test_allowance_after_approval() { - let caller = contract_address_const::<'caller'>(); - let spender = spender_address(); - let (dispatcher, _) = deploy(); - set_contract_address(caller); - dispatcher.approve(spender, 100); - assert(dispatcher.allowance(caller, spender) == 100, 'incorrect allowance') - } - - #[test] - #[available_gas(2000000)] - #[should_panic(expected: ('ERC20: approve to 0', 'ENTRYPOINT_FAILED'))] - fn test_approval_spender_is_address_zero() { - let spender: ContractAddress = zero_address(); - - let (dispatcher, _) = deploy(); - dispatcher.approve(spender, 100); - } - - #[test] - #[available_gas(2000000)] - fn test_approval_success() { - let recipient = recipient_address(); - let spender = spender_address(); - let value = 100; - - let (dispatcher, contract_address) = deploy(); - let caller = contract_address_const::<'caller'>(); - set_contract_address(caller); - dispatcher.approve(spender, value); - set_contract_address(contract_address); - - // Notice the order: the first event emitted is the first to be popped. - /// ANCHOR: test_events - assert_eq!( - starknet::testing::pop_log(contract_address), - Option::Some( - Event::Transfer(Transfer { from: zero_address(), to: recipient, value: 100000 }) - ) - ); - - assert_eq!( - starknet::testing::pop_log(contract_address), - Option::Some(Event::Approval(Approval { owner: caller, spender, value })) - ); - } - - #[test] - #[available_gas(2000000)] - #[should_panic(expected: ('ERC20: approve to 0', 'ENTRYPOINT_FAILED'))] - fn test_should_increase_allowance_with_spender_zero_address() { - let spender = zero_address(); - let (dispatcher, _) = deploy(); - dispatcher.increase_allowance(spender, 100); - } - - #[test] - #[available_gas(2000000)] - fn test_should_increase_allowance() { - let caller = contract_address_const::<'caller'>(); - let recipient = recipient_address(); - let spender = spender_address(); - let (dispatcher, contract_address) = deploy(); - set_contract_address(caller); - dispatcher.approve(spender, 100); - assert(dispatcher.allowance(caller, spender) == 100, 'incorrect allowance'); - set_contract_address(caller); - dispatcher.increase_allowance(spender, 100); - assert(dispatcher.allowance(caller, spender) == 200, 'incorrect increased allowance'); - - // emits one transfer event and two approval events - - assert_eq!( - starknet::testing::pop_log(contract_address), - Option::Some( - Event::Transfer(Transfer { from: zero_address(), to: recipient, value: 100000 }) - ) - ); - - assert_eq!( - starknet::testing::pop_log(contract_address), - Option::Some(Event::Approval(Approval { owner: caller, spender, value: 100 })) - ); - - assert_eq!( - starknet::testing::pop_log(contract_address), - Option::Some(Event::Approval(Approval { owner: caller, spender, value: 200 })) - ); - } - - #[test] - #[available_gas(2000000)] - #[should_panic(expected: ('ERC20: approve to 0', 'ENTRYPOINT_FAILED'))] - fn test_should_decrease_allowance_with_spender_zero_address() { - let spender = zero_address(); - let (dispatcher, _) = deploy(); - dispatcher.decrease_allowance(spender, 100); - } - - #[test] - #[available_gas(2000000)] - fn test_should_decrease_allowance() { - let caller = contract_address_const::<'caller'>(); - let recipient = recipient_address(); - let spender = spender_address(); - let (dispatcher, contract_address) = deploy(); - set_contract_address(caller); - dispatcher.approve(spender, 100); - assert(dispatcher.allowance(caller, spender) == 100, 'incorrect allowance'); - - set_contract_address(caller); - dispatcher.decrease_allowance(spender, 90); - assert(dispatcher.allowance(caller, spender) == 10, 'incorrect decreased allowance'); - - // emits one transfer event and two approval events - - assert_eq!( - starknet::testing::pop_log(contract_address), - Option::Some( - Event::Transfer(Transfer { from: zero_address(), to: recipient, value: 100000 }) - ) - ); - - assert_eq!( - starknet::testing::pop_log(contract_address), - Option::Some(Event::Approval(Approval { owner: caller, spender, value: 100 })) - ); - - assert_eq!( - starknet::testing::pop_log(contract_address), - Option::Some(Event::Approval(Approval { owner: caller, spender, value: 10 })) - ); - } - - #[test] - #[available_gas(2000000)] - #[should_panic(expected: ('ERC20: transfer from 0', 'ENTRYPOINT_FAILED'))] - fn test_transfer_when_sender_is_address_zero() { - let reciever = spender_address(); - let (dispatcher, _) = deploy(); - dispatcher.transfer(reciever, 100); - } - - #[test] - #[available_gas(2000000)] - #[should_panic(expected: ('ERC20: transfer to 0', 'ENTRYPOINT_FAILED'))] - #[should_panic] - fn test_transfer_when_recipient_is_address_zero() { - let caller = contract_address_const::<'caller'>(); - let reciever = zero_address(); - let (dispatcher, _) = deploy(); - set_contract_address(caller); - dispatcher.transfer(reciever, 100); - } - - #[test] - #[available_gas(2000000)] - fn test_transfer_success() { - let caller = recipient_address(); - let reciever = contract_address_const::<'receiver'>(); - let recipient = recipient_address(); - let (dispatcher, contract_address) = deploy(); - set_contract_address(caller); - dispatcher.transfer(reciever, 100); - assert_eq!(dispatcher.balance_of(reciever), 100); - - // emits two transfer events - assert_eq!( - starknet::testing::pop_log(contract_address), - Option::Some( - Event::Transfer(Transfer { from: zero_address(), to: recipient, value: 100000 }) - ) - ); - - assert_eq!( - starknet::testing::pop_log(contract_address), - Option::Some(Event::Transfer(Transfer { from: caller, to: reciever, value: 100 })) - ); - } - - - #[test] - #[available_gas(2000000)] - #[should_panic(expected: ('ERC20: transfer from 0', 'ENTRYPOINT_FAILED'))] - #[should_panic] - fn test_transferFrom_when_sender_is_address_zero() { - let sender = zero_address(); - let reciever = spender_address(); - let (dispatcher, _) = deploy(); - dispatcher.transfer_from(sender, reciever, 100); - } - - #[test] - #[available_gas(2000000)] - #[should_panic(expected: ('ERC20: transfer to 0', 'ENTRYPOINT_FAILED'))] - #[should_panic] - fn test_transferFrom_when_recipient_is_address_zero() { - let caller = contract_address_const::<'caller'>(); - let reciever = zero_address(); - let (dispatcher, _) = deploy(); - set_contract_address(caller); - dispatcher.transfer_from(caller, reciever, 100); - } - - #[test] - #[available_gas(2000000)] - fn test_transferFrom_success() { - let caller = recipient_address(); - let reciever = contract_address_const::<'receiver'>(); - let recipient = recipient_address(); - let (dispatcher, contract_address) = deploy(); - set_contract_address(caller); - dispatcher.transfer_from(caller, reciever, 100); - assert_eq!(dispatcher.balance_of(reciever), 100); - - // emits two transfer events - - assert_eq!( - starknet::testing::pop_log(contract_address), - Option::Some( - Event::Transfer(Transfer { from: zero_address(), to: recipient, value: 100000 }) - ) - ); - - assert_eq!( - starknet::testing::pop_log(contract_address), - Option::Some(Event::Transfer(Transfer { from: caller, to: reciever, value: 100 })) - ); - } -} +mod tests {} diff --git a/listings/applications/erc20/src/token.cairo b/listings/applications/erc20/src/token.cairo index eb794ed8..9e05d4c9 100644 --- a/listings/applications/erc20/src/token.cairo +++ b/listings/applications/erc20/src/token.cairo @@ -212,4 +212,344 @@ pub mod erc20 { } // ANCHOR_END: erc20 +#[cfg(test)] +mod tests { + use super::{erc20, IERC20Dispatcher, IERC20DispatcherTrait, erc20::{Event, Transfer, Approval}}; + use starknet::{ + ContractAddress, SyscallResultTrait, syscalls::deploy_syscall, get_caller_address, + contract_address_const + }; + + use starknet::testing::{set_contract_address, set_account_contract_address}; + + const token_name: felt252 = 'myToken'; + const decimals: u8 = 18; + const initial_supply: felt252 = 100000; + const symbols: felt252 = 'mtk'; + + fn deploy() -> (IERC20Dispatcher, ContractAddress) { + let recipient: ContractAddress = contract_address_const::<'initialzed_recipient'>(); + + let (contract_address, _) = deploy_syscall( + erc20::TEST_CLASS_HASH.try_into().unwrap(), + recipient.into(), + array![recipient.into(), token_name, decimals.into(), initial_supply, symbols].span(), + false + ) + .unwrap_syscall(); + + (IERC20Dispatcher { contract_address }, contract_address) + } + + + #[test] + #[should_panic(expected: ('ERC20: mint to 0', 'CONSTRUCTOR_FAILED'))] + fn test_deploy_when_recipient_is_address_zero() { + let recipient: ContractAddress = get_caller_address(); + + let (contract_address, _) = deploy_syscall( + erc20::TEST_CLASS_HASH.try_into().unwrap(), + recipient.into(), + array![recipient.into(), token_name, decimals.into(), initial_supply, symbols].span(), + false + ) + .unwrap_syscall(); + } + #[test] + fn test_deploy_success() { + let recipient = contract_address_const::<'initialzed_recipient'>(); + let (_, contract_address) = deploy(); + assert_eq!( + starknet::testing::pop_log(contract_address), + Option::Some( + Event::Transfer( + Transfer { from: get_caller_address(), to: recipient, value: initial_supply } + ) + ) + ); + } + + + #[test] + fn test_get_name() { + let (dispatcher, _) = deploy(); + let name = dispatcher.get_name(); + assert(name == token_name, 'wrong token name'); + } + + #[test] + fn test_get_symbol() { + let (dispatcher, _) = deploy(); + assert(dispatcher.get_symbol() == symbols, 'wrong symbol'); + } + + #[test] + fn test_get_decimals() { + let (dispatcher, _) = deploy(); + assert(dispatcher.get_decimals() == decimals, 'wrong decimals'); + } + + #[test] + fn test_total_supply() { + let (dispatcher, _) = deploy(); + assert(dispatcher.get_total_supply() == initial_supply, 'wrong total supply'); + } + + #[test] + fn test_balance_of_recipient_deployed() { + let recipient = contract_address_const::<'initialzed_recipient'>(); + let (dispatcher, _) = deploy(); + assert( + dispatcher.balance_of(recipient) == initial_supply, 'incorrect balance of recipient' + ); + } + + #[test] + fn test_allowance_without_approval() { + let caller = contract_address_const::<'caller'>(); + let spender = contract_address_const::<'spender'>(); + let (dispatcher, _) = deploy(); + set_contract_address(caller); + assert(dispatcher.allowance(caller, spender) == 0, 'incorrect allowance') + } + + #[test] + fn test_allowance_after_approval() { + let caller = contract_address_const::<'caller'>(); + let spender = contract_address_const::<'spender'>(); + let (dispatcher, _) = deploy(); + let amount = 100; + set_contract_address(caller); + dispatcher.approve(spender, amount); + assert(dispatcher.allowance(caller, spender) == amount, 'incorrect allowance') + } + + #[test] + #[should_panic(expected: ('ERC20: approve to 0', 'ENTRYPOINT_FAILED'))] + fn test_approval_spender_is_address_zero() { + let spender: ContractAddress = get_caller_address(); + let amount = 100; + let (dispatcher, _) = deploy(); + dispatcher.approve(spender, amount); + } + + #[test] + fn test_approval_success() { + let recipient = contract_address_const::<'initialzed_recipient'>(); + let spender = contract_address_const::<'spender'>(); + let value = 100; + let (dispatcher, contract_address) = deploy(); + let caller = contract_address_const::<'caller'>(); + set_contract_address(caller); + dispatcher.approve(spender, value); + set_contract_address(contract_address); + + assert_eq!( + starknet::testing::pop_log(contract_address), + Option::Some( + Event::Transfer( + Transfer { from: get_caller_address(), to: recipient, value: initial_supply } + ) + ) + ); + + assert_eq!( + starknet::testing::pop_log(contract_address), + Option::Some(Event::Approval(Approval { owner: caller, spender, value })) + ); + } + + #[test] + #[should_panic(expected: ('ERC20: approve to 0', 'ENTRYPOINT_FAILED'))] + fn test_should_increase_allowance_with_spender_zero_address() { + let spender = get_caller_address(); + let amount = 100; + let (dispatcher, _) = deploy(); + dispatcher.increase_allowance(spender, amount); + } + + #[test] + fn test_should_increase_allowance() { + let caller = contract_address_const::<'caller'>(); + let recipient = contract_address_const::<'initialzed_recipient'>(); + let spender = contract_address_const::<'spender'>(); + let amount = 100; + let (dispatcher, contract_address) = deploy(); + set_contract_address(caller); + dispatcher.approve(spender, amount); + assert(dispatcher.allowance(caller, spender) == amount, 'incorrect allowance'); + set_contract_address(caller); + dispatcher.increase_allowance(spender, 100); + assert( + dispatcher.allowance(caller, spender) == amount + 100, 'incorrect increased allowance' + ); + + // emits one transfer event and two approval events + + assert_eq!( + starknet::testing::pop_log(contract_address), + Option::Some( + Event::Transfer( + Transfer { from: get_caller_address(), to: recipient, value: initial_supply } + ) + ) + ); + + assert_eq!( + starknet::testing::pop_log(contract_address), + Option::Some(Event::Approval(Approval { owner: caller, spender, value: amount })) + ); + + assert_eq!( + starknet::testing::pop_log(contract_address), + Option::Some(Event::Approval(Approval { owner: caller, spender, value: amount + 100 })) + ); + } + + #[test] + #[should_panic(expected: ('ERC20: approve to 0', 'ENTRYPOINT_FAILED'))] + fn test_should_decrease_allowance_with_spender_zero_address() { + let spender = get_caller_address(); + let amount = 100; + let (dispatcher, _) = deploy(); + dispatcher.decrease_allowance(spender, amount); + } + + #[test] + fn test_should_decrease_allowance() { + let caller = contract_address_const::<'caller'>(); + let recipient = contract_address_const::<'initialzed_recipient'>(); + let spender = contract_address_const::<'spender'>(); + let amount = 100; + let (dispatcher, contract_address) = deploy(); + set_contract_address(caller); + dispatcher.approve(spender, amount); + assert(dispatcher.allowance(caller, spender) == amount, 'incorrect allowance'); + + set_contract_address(caller); + dispatcher.decrease_allowance(spender, 90); + assert( + dispatcher.allowance(caller, spender) == amount - 90, 'incorrect decreased allowance' + ); + + // emits one transfer event and two approval events + + assert_eq!( + starknet::testing::pop_log(contract_address), + Option::Some( + Event::Transfer( + Transfer { from: get_caller_address(), to: recipient, value: initial_supply } + ) + ) + ); + + assert_eq!( + starknet::testing::pop_log(contract_address), + Option::Some(Event::Approval(Approval { owner: caller, spender, value: amount })) + ); + + assert_eq!( + starknet::testing::pop_log(contract_address), + Option::Some(Event::Approval(Approval { owner: caller, spender, value: amount - 90 })) + ); + } + + #[test] + #[should_panic(expected: ('ERC20: transfer from 0', 'ENTRYPOINT_FAILED'))] + fn test_transfer_when_sender_is_address_zero() { + let reciever = contract_address_const::<'spender'>(); + let amount = 100; + let (dispatcher, _) = deploy(); + dispatcher.transfer(reciever, amount); + } + + #[test] + #[should_panic(expected: ('ERC20: transfer to 0', 'ENTRYPOINT_FAILED'))] + #[should_panic] + fn test_transfer_when_recipient_is_address_zero() { + let caller = contract_address_const::<'caller'>(); + let reciever = get_caller_address(); + let amount = 100; + let (dispatcher, _) = deploy(); + set_contract_address(caller); + dispatcher.transfer(reciever, amount); + } + + #[test] + fn test_transfer_success() { + let caller = contract_address_const::<'initialzed_recipient'>(); + let reciever = contract_address_const::<'receiver'>(); + let amount = 100; + let (dispatcher, contract_address) = deploy(); + set_contract_address(caller); + dispatcher.transfer(reciever, amount); + assert_eq!(dispatcher.balance_of(reciever), amount); + + // emits two transfer events + assert_eq!( + starknet::testing::pop_log(contract_address), + Option::Some( + Event::Transfer( + Transfer { from: get_caller_address(), to: caller, value: initial_supply } + ) + ) + ); + + assert_eq!( + starknet::testing::pop_log(contract_address), + Option::Some(Event::Transfer(Transfer { from: caller, to: reciever, value: amount })) + ); + } + + + #[test] + #[should_panic(expected: ('ERC20: transfer from 0', 'ENTRYPOINT_FAILED'))] + #[should_panic] + fn test_transferFrom_when_sender_is_address_zero() { + let sender = get_caller_address(); + let amount = 100; + let reciever = contract_address_const::<'spender'>(); + let (dispatcher, _) = deploy(); + dispatcher.transfer_from(sender, reciever, amount); + } + + #[test] + #[should_panic(expected: ('ERC20: transfer to 0', 'ENTRYPOINT_FAILED'))] + #[should_panic] + fn test_transferFrom_when_recipient_is_address_zero() { + let caller = contract_address_const::<'caller'>(); + let reciever = get_caller_address(); + let amount = 100; + let (dispatcher, _) = deploy(); + set_contract_address(caller); + dispatcher.transfer_from(caller, reciever, amount); + } + + #[test] + fn test_transferFrom_success() { + let caller = contract_address_const::<'initialzed_recipient'>(); + let reciever = contract_address_const::<'receiver'>(); + let amount = 100; + let (dispatcher, contract_address) = deploy(); + set_contract_address(caller); + dispatcher.transfer_from(caller, reciever, amount); + assert_eq!(dispatcher.balance_of(reciever), amount); + + // emits two transfer events + + assert_eq!( + starknet::testing::pop_log(contract_address), + Option::Some( + Event::Transfer( + Transfer { from: get_caller_address(), to: caller, value: initial_supply } + ) + ) + ); + + assert_eq!( + starknet::testing::pop_log(contract_address), + Option::Some(Event::Transfer(Transfer { from: caller, to: reciever, value: amount })) + ); + } +} From 4cc0c413beaa8ee976ceb322b96d354025a9be54 Mon Sep 17 00:00:00 2001 From: the-first-elder Date: Tue, 28 May 2024 17:52:26 +0100 Subject: [PATCH 5/9] fixed zero address --- listings/applications/erc20/src/token.cairo | 31 ++++++++++----------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/listings/applications/erc20/src/token.cairo b/listings/applications/erc20/src/token.cairo index 9e05d4c9..13066c29 100644 --- a/listings/applications/erc20/src/token.cairo +++ b/listings/applications/erc20/src/token.cairo @@ -220,6 +220,7 @@ mod tests { ContractAddress, SyscallResultTrait, syscalls::deploy_syscall, get_caller_address, contract_address_const }; + use core::num::traits::Zero; use starknet::testing::{set_contract_address, set_account_contract_address}; @@ -246,7 +247,7 @@ mod tests { #[test] #[should_panic(expected: ('ERC20: mint to 0', 'CONSTRUCTOR_FAILED'))] fn test_deploy_when_recipient_is_address_zero() { - let recipient: ContractAddress = get_caller_address(); + let recipient: ContractAddress = Zero::zero(); let (contract_address, _) = deploy_syscall( erc20::TEST_CLASS_HASH.try_into().unwrap(), @@ -264,7 +265,7 @@ mod tests { starknet::testing::pop_log(contract_address), Option::Some( Event::Transfer( - Transfer { from: get_caller_address(), to: recipient, value: initial_supply } + Transfer { from: Zero::zero(), to: recipient, value: initial_supply } ) ) ); @@ -328,7 +329,7 @@ mod tests { #[test] #[should_panic(expected: ('ERC20: approve to 0', 'ENTRYPOINT_FAILED'))] fn test_approval_spender_is_address_zero() { - let spender: ContractAddress = get_caller_address(); + let spender: ContractAddress = Zero::zero(); let amount = 100; let (dispatcher, _) = deploy(); dispatcher.approve(spender, amount); @@ -349,7 +350,7 @@ mod tests { starknet::testing::pop_log(contract_address), Option::Some( Event::Transfer( - Transfer { from: get_caller_address(), to: recipient, value: initial_supply } + Transfer { from: Zero::zero(), to: recipient, value: initial_supply } ) ) ); @@ -363,7 +364,7 @@ mod tests { #[test] #[should_panic(expected: ('ERC20: approve to 0', 'ENTRYPOINT_FAILED'))] fn test_should_increase_allowance_with_spender_zero_address() { - let spender = get_caller_address(); + let spender = Zero::zero(); let amount = 100; let (dispatcher, _) = deploy(); dispatcher.increase_allowance(spender, amount); @@ -391,7 +392,7 @@ mod tests { starknet::testing::pop_log(contract_address), Option::Some( Event::Transfer( - Transfer { from: get_caller_address(), to: recipient, value: initial_supply } + Transfer { from: Zero::zero(), to: recipient, value: initial_supply } ) ) ); @@ -410,7 +411,7 @@ mod tests { #[test] #[should_panic(expected: ('ERC20: approve to 0', 'ENTRYPOINT_FAILED'))] fn test_should_decrease_allowance_with_spender_zero_address() { - let spender = get_caller_address(); + let spender = Zero::zero(); let amount = 100; let (dispatcher, _) = deploy(); dispatcher.decrease_allowance(spender, amount); @@ -439,7 +440,7 @@ mod tests { starknet::testing::pop_log(contract_address), Option::Some( Event::Transfer( - Transfer { from: get_caller_address(), to: recipient, value: initial_supply } + Transfer { from: Zero::zero(), to: recipient, value: initial_supply } ) ) ); @@ -469,7 +470,7 @@ mod tests { #[should_panic] fn test_transfer_when_recipient_is_address_zero() { let caller = contract_address_const::<'caller'>(); - let reciever = get_caller_address(); + let reciever = Zero::zero(); let amount = 100; let (dispatcher, _) = deploy(); set_contract_address(caller); @@ -490,9 +491,7 @@ mod tests { assert_eq!( starknet::testing::pop_log(contract_address), Option::Some( - Event::Transfer( - Transfer { from: get_caller_address(), to: caller, value: initial_supply } - ) + Event::Transfer(Transfer { from: Zero::zero(), to: caller, value: initial_supply }) ) ); @@ -507,7 +506,7 @@ mod tests { #[should_panic(expected: ('ERC20: transfer from 0', 'ENTRYPOINT_FAILED'))] #[should_panic] fn test_transferFrom_when_sender_is_address_zero() { - let sender = get_caller_address(); + let sender = Zero::zero(); let amount = 100; let reciever = contract_address_const::<'spender'>(); let (dispatcher, _) = deploy(); @@ -519,7 +518,7 @@ mod tests { #[should_panic] fn test_transferFrom_when_recipient_is_address_zero() { let caller = contract_address_const::<'caller'>(); - let reciever = get_caller_address(); + let reciever = Zero::zero(); let amount = 100; let (dispatcher, _) = deploy(); set_contract_address(caller); @@ -541,9 +540,7 @@ mod tests { assert_eq!( starknet::testing::pop_log(contract_address), Option::Some( - Event::Transfer( - Transfer { from: get_caller_address(), to: caller, value: initial_supply } - ) + Event::Transfer(Transfer { from: Zero::zero(), to: caller, value: initial_supply }) ) ); From 57aeb625b490562591fc0b85a8b1ba37ac533623 Mon Sep 17 00:00:00 2001 From: julio4 Date: Thu, 30 May 2024 12:15:39 +0900 Subject: [PATCH 6/9] chore: Remove unused test files --- listings/applications/erc20/src/lib.cairo | 3 --- listings/applications/erc20/src/tests.cairo | 1 - listings/applications/erc20/src/token.cairo | 2 +- 3 files changed, 1 insertion(+), 5 deletions(-) delete mode 100644 listings/applications/erc20/src/tests.cairo diff --git a/listings/applications/erc20/src/lib.cairo b/listings/applications/erc20/src/lib.cairo index 4ab2be17..40d3ff58 100644 --- a/listings/applications/erc20/src/lib.cairo +++ b/listings/applications/erc20/src/lib.cairo @@ -1,4 +1 @@ mod token; - -#[cfg(test)] -mod tests; diff --git a/listings/applications/erc20/src/tests.cairo b/listings/applications/erc20/src/tests.cairo deleted file mode 100644 index 26c0e3f7..00000000 --- a/listings/applications/erc20/src/tests.cairo +++ /dev/null @@ -1 +0,0 @@ -mod tests {} diff --git a/listings/applications/erc20/src/token.cairo b/listings/applications/erc20/src/token.cairo index 13066c29..51660642 100644 --- a/listings/applications/erc20/src/token.cairo +++ b/listings/applications/erc20/src/token.cairo @@ -249,7 +249,7 @@ mod tests { fn test_deploy_when_recipient_is_address_zero() { let recipient: ContractAddress = Zero::zero(); - let (contract_address, _) = deploy_syscall( + let (_contract_address, _) = deploy_syscall( erc20::TEST_CLASS_HASH.try_into().unwrap(), recipient.into(), array![recipient.into(), token_name, decimals.into(), initial_supply, symbols].span(), From 844d62ec0b48827685b3eac3314cc8f4ca1b9993 Mon Sep 17 00:00:00 2001 From: OkoliEvans Date: Mon, 27 May 2024 17:45:11 +0100 Subject: [PATCH 7/9] final push --- Scarb.lock | 4 ++ .../library_calls/.gitignore | 1 + .../library_calls/Scarb.toml | 14 ++++++ .../library_calls/src/lib.cairo | 4 ++ .../library_calls/src/library_call.cairo | 50 +++++++++++++++++++ .../library_calls/src/tests.cairo | 25 ++++++++++ src/ch02/library_calls.md | 16 ++++++ 7 files changed, 114 insertions(+) create mode 100644 listings/advanced-concepts/library_calls/.gitignore create mode 100644 listings/advanced-concepts/library_calls/Scarb.toml create mode 100644 listings/advanced-concepts/library_calls/src/lib.cairo create mode 100644 listings/advanced-concepts/library_calls/src/library_call.cairo create mode 100644 listings/advanced-concepts/library_calls/src/tests.cairo create mode 100644 src/ch02/library_calls.md diff --git a/Scarb.lock b/Scarb.lock index 60e669e4..7dab0bb1 100644 --- a/Scarb.lock +++ b/Scarb.lock @@ -80,6 +80,10 @@ version = "0.1.0" name = "interfaces_traits" version = "0.1.0" +[[package]] +name = "library_calls" +version = "0.1.0" + [[package]] name = "mappings" version = "0.1.0" diff --git a/listings/advanced-concepts/library_calls/.gitignore b/listings/advanced-concepts/library_calls/.gitignore new file mode 100644 index 00000000..eb5a316c --- /dev/null +++ b/listings/advanced-concepts/library_calls/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/advanced-concepts/library_calls/Scarb.toml b/listings/advanced-concepts/library_calls/Scarb.toml new file mode 100644 index 00000000..0ea12255 --- /dev/null +++ b/listings/advanced-concepts/library_calls/Scarb.toml @@ -0,0 +1,14 @@ +[package] +name = "library_calls" +version.workspace = true +edition = "2023_11" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest.html + +[dependencies] +starknet.workspace = true + +[scripts] +test.workspace = true + +[[target.starknet-contract]] \ No newline at end of file diff --git a/listings/advanced-concepts/library_calls/src/lib.cairo b/listings/advanced-concepts/library_calls/src/lib.cairo new file mode 100644 index 00000000..60ee240e --- /dev/null +++ b/listings/advanced-concepts/library_calls/src/lib.cairo @@ -0,0 +1,4 @@ +mod library_call; + +#[cfg(test)] +mod tests; diff --git a/listings/advanced-concepts/library_calls/src/library_call.cairo b/listings/advanced-concepts/library_calls/src/library_call.cairo new file mode 100644 index 00000000..f2a19857 --- /dev/null +++ b/listings/advanced-concepts/library_calls/src/library_call.cairo @@ -0,0 +1,50 @@ +// ANCHOR: library_dispatcher +#[starknet::interface] +pub trait IMathUtils { + fn add(ref self: T, x: u32, y: u32) -> u32; + fn set_class_hash(ref self: T, class_hash: starknet::ClassHash); +} + +// contract A +#[starknet::contract] +pub mod MathUtils { + #[storage] + struct Storage {} + + #[abi(embed_v0)] + impl ImathUtilsImpl of super::IMathUtils { + fn add(ref self: ContractState, x: u32, y: u32) -> u32 { + x + y + } + + fn set_class_hash(ref self: ContractState, class_hash: starknet::ClassHash) {} + } +} + + +// contract B to make library call to contract A +#[starknet::contract] +pub mod MathUtilsLibraryCall { + use starknet::{class_hash::class_hash_const, ContractAddress}; + use super::{IMathUtilsDispatcherTrait, IMathUtilsLibraryDispatcher}; + + #[storage] + struct Storage { + value: u32, + lib_class_hash: starknet::ClassHash, + } + + #[abi(embed_v0)] + impl MathUtils of super::IMathUtils { + fn add(ref self: ContractState, x: u32, y: u32) -> u32 { + IMathUtilsLibraryDispatcher { class_hash: self.lib_class_hash.read() }.add(x, y) + } + + #[abi(embed_v0)] + fn set_class_hash(ref self: ContractState, class_hash: starknet::ClassHash) { + self.lib_class_hash.write(class_hash); + } + } +} +// ANCHOR_END: library_dispatcher + diff --git a/listings/advanced-concepts/library_calls/src/tests.cairo b/listings/advanced-concepts/library_calls/src/tests.cairo new file mode 100644 index 00000000..1b9ecdf0 --- /dev/null +++ b/listings/advanced-concepts/library_calls/src/tests.cairo @@ -0,0 +1,25 @@ +mod tests { + use starknet::syscalls::{deploy_syscall}; + use starknet::SyscallResultTrait; + use library_calls::library_call::{ + MathUtils, MathUtilsLibraryCall, IMathUtilsDispatcher, IMathUtilsDispatcherTrait + }; + + #[test] + #[available_gas(20000000)] + fn test_library_dispatcher() { + let math_utils_class_hash: starknet::ClassHash = MathUtils::TEST_CLASS_HASH + .try_into() + .unwrap(); + let mut calldata: Array = array![]; + let (address, _) = deploy_syscall( + MathUtilsLibraryCall::TEST_CLASS_HASH.try_into().unwrap(), 0, calldata.span(), false + ) + .unwrap_syscall(); + let mut contract = IMathUtilsDispatcher { contract_address: address }; + + contract.set_class_hash(math_utils_class_hash); + let mut result = contract.add(30, 5); + assert_eq!(result, 35, "Wrong result"); + } +} diff --git a/src/ch02/library_calls.md b/src/ch02/library_calls.md new file mode 100644 index 00000000..85813bba --- /dev/null +++ b/src/ch02/library_calls.md @@ -0,0 +1,16 @@ +# Library Dispatcher + +External calls can be made on Starknet by two means: Contract dispatchers or Library dispatchers. Dispatchers are automatically created and exported by the compiler when a contract interface is defined. + +With Contract dispatcher we are calling an already deployed contract (with associated state), therefore contract address is passed to the dispatcher to make the call. However, with library dispatcher we are simply making function calls to declared contract **classes** (stateless). + +Contract dispatcher call is synonymous to external calls in Solidity, while library dispatcher call is synonymous to delegate call. + +For further reading: [Cairo book](https://book.cairo-lang.org/ch15-02-contract-dispatchers-library-dispatchers-and-system-calls.html?highlight=library%20dispatchers#library-dispatcher). + +```rust +{{#rustdoc_include ../../listings/advanced-concepts/library_calls/src/library_call.cairo:library_dispatcher}} +``` + + + From 7a7bc0878177bc2f08771c4c5e3de1cef6844e64 Mon Sep 17 00:00:00 2001 From: OkoliEvans Date: Tue, 28 May 2024 17:52:01 +0100 Subject: [PATCH 8/9] updated the Summary.md --- src/SUMMARY.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/SUMMARY.md b/src/SUMMARY.md index c237c3d7..a02b5802 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -71,3 +71,4 @@ Summary - [List](./ch02/list.md) - [Plugins](./ch02/plugins.md) - [Signature Verification](./ch02/signature_verification.md) +- [Library Calls](./ch02/library_calls.md) From a7796a72043549264d5d5957627d2bbab2527e35 Mon Sep 17 00:00:00 2001 From: julio4 Date: Thu, 30 May 2024 13:32:00 +0900 Subject: [PATCH 9/9] fix: fmt and minor edit --- .../advanced-concepts/library_calls/src/library_call.cairo | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/listings/advanced-concepts/library_calls/src/library_call.cairo b/listings/advanced-concepts/library_calls/src/library_call.cairo index f2a19857..a9f7cd56 100644 --- a/listings/advanced-concepts/library_calls/src/library_call.cairo +++ b/listings/advanced-concepts/library_calls/src/library_call.cairo @@ -22,7 +22,7 @@ pub mod MathUtils { } -// contract B to make library call to contract A +// contract B to make library call to the class of contract A #[starknet::contract] pub mod MathUtilsLibraryCall { use starknet::{class_hash::class_hash_const, ContractAddress}; @@ -48,3 +48,4 @@ pub mod MathUtilsLibraryCall { } // ANCHOR_END: library_dispatcher +