diff --git a/Scarb.lock b/Scarb.lock index 80ff8492..2958c5b4 100644 --- a/Scarb.lock +++ b/Scarb.lock @@ -8,8 +8,8 @@ source = "git+https://github.com/influenceth/cubit?rev=b459053#b4590530d5aeae9aa [[package]] name = "dojo" -version = "0.3.14" -source = "git+https://github.com/dojoengine/dojo?tag=v0.3.14#d7e9788459f3b2e797b6565f1057c96a6f5f8cc2" +version = "0.3.15" +source = "git+https://github.com/dojoengine/dojo?tag=v0.3.15#cdbaca4121b1642e1a8ca40d6831bad73d28ed26" dependencies = [ "dojo_plugin", ] diff --git a/Scarb.toml b/Scarb.toml index 616ebf28..0ccc804e 100644 --- a/Scarb.toml +++ b/Scarb.toml @@ -10,5 +10,5 @@ authors = ["bal7hazar@proton.me"] [workspace.dependencies] cubit = { git = "https://github.com/influenceth/cubit", rev = "b459053" } -dojo = { git = "https://github.com/dojoengine/dojo", tag = "v0.3.14" } +dojo = { git = "https://github.com/dojoengine/dojo", tag = "v0.3.15" } origami = { path = "crates" } diff --git a/token/src/components/token/erc20_metadata.cairo b/token/src/components/token/erc20_metadata.cairo index f32c662f..69914ffc 100644 --- a/token/src/components/token/erc20_metadata.cairo +++ b/token/src/components/token/erc20_metadata.cairo @@ -11,6 +11,7 @@ struct ERC20MetadataModel { name: felt252, symbol: felt252, decimals: u8, + total_supply: u256, } /// @@ -40,38 +41,53 @@ mod ERC20MetadataComponent { #[storage] struct Storage {} - mod Errors { - // const INITIALIZED: felt252 = 'Initializable: is initialized'; - } - #[embeddable_as(ERC20MetadataImpl)] impl ERC20Metadata< TContractState, +HasComponent, +IWorldProvider > of IERC20Metadata> { - fn name(self: @ComponentState) -> felt252{ - self.get_metadata().name + fn name(self: @ComponentState) -> felt252 { + self.get_metadata().name } - fn symbol(self: @ComponentState) -> felt252{ - self.get_metadata().symbol + fn symbol(self: @ComponentState) -> felt252 { + self.get_metadata().symbol } - fn decimals(self: @ComponentState) -> u8{ - self.get_metadata().decimals + fn decimals(self: @ComponentState) -> u8 { + self.get_metadata().decimals } } #[generate_trait] - impl ERC20MetadataInternalImpl< + impl InternalImpl< TContractState, +HasComponent, +IWorldProvider > of InternalTrait { - fn initialize(ref self: ComponentState, name:felt252, symbol: felt252, decimals: u8) { + fn initialize( + ref self: ComponentState, name: felt252, symbol: felt252, decimals: u8 + ) { set!( self.get_contract().world(), - ERC20MetadataModel { token: get_contract_address(), name, symbol, decimals } + ERC20MetadataModel { + token: get_contract_address(), name, symbol, decimals, total_supply: 0 + } ) } fn get_metadata(self: @ComponentState) -> ERC20MetadataModel { - get!(self.get_contract().world(), get_contract_address(),(ERC20MetadataModel)) + get!(self.get_contract().world(), get_contract_address(), (ERC20MetadataModel)) + } + + fn total_supply(self: @ComponentState) -> u256 { + self.get_metadata().total_supply + } + + // Helper function to update total_supply model + fn update_total_supply( + ref self: ComponentState, subtract: u256, add: u256 + ) { + let mut meta = self.get_metadata(); + // // adding and subtracting is fewer steps than if + meta.total_supply = meta.total_supply - subtract; + meta.total_supply = meta.total_supply + add; + set!(self.get_contract().world(), (meta)); } } } diff --git a/token/src/preset/erc20.cairo b/token/src/preset/erc20.cairo index ad22a92e..6e97dc94 100644 --- a/token/src/preset/erc20.cairo +++ b/token/src/preset/erc20.cairo @@ -8,13 +8,17 @@ mod ERC20 { use zeroable::Zeroable; use token::components::token::erc20_metadata::ERC20MetadataComponent; + use token::components::security::initializable::InitializableComponent; + component!(path: InitializableComponent, storage: initializable, event: InitializableEvent); component!(path: ERC20MetadataComponent, storage: erc20_metadata, event: ERC20MetadataEvent); #[storage] struct Storage { #[substorage(v0)] - erc20_metadata: ERC20MetadataComponent::Storage + initializable: InitializableComponent::Storage, + #[substorage(v0)] + erc20_metadata: ERC20MetadataComponent::Storage, } #[event] @@ -23,7 +27,9 @@ mod ERC20 { Transfer: Transfer, Approval: Approval, #[flat] - ERC20MetadataEvent: ERC20MetadataComponent::Event + InitializableEvent: InitializableComponent::Event, + #[flat] + ERC20MetadataEvent: ERC20MetadataComponent::Event, } #[derive(Copy, Drop, starknet::Event)] @@ -41,6 +47,9 @@ mod ERC20 { } mod Errors { + const ALREADY_INITIALIZED: felt252 = 'ERC20: already initialized'; + const CALLER_IS_NOT_OWNER: felt252 = 'ERC20: caller is not owner'; + const APPROVE_FROM_ZERO: felt252 = 'ERC20: approve from 0'; const APPROVE_TO_ZERO: felt252 = 'ERC20: approve to 0'; const TRANSFER_FROM_ZERO: felt252 = 'ERC20: transfer from 0'; @@ -49,32 +58,39 @@ mod ERC20 { const MINT_TO_ZERO: felt252 = 'ERC20: mint to 0'; } - #[constructor] - fn constructor( + #[abi(embed_v0)] + impl InitializableImpl = + InitializableComponent::InitializableImpl; + + #[abi(embed_v0)] + impl ERC20MetadataImpl = + ERC20MetadataComponent::ERC20MetadataImpl; + + + #[external(v0)] + fn initializer( ref self: ContractState, name: felt252, symbol: felt252, - initial_supply: u256, - recipient: ContractAddress + recipient: ContractAddress, + initial_supply: u256 ) { - self.initializer(name, symbol); - self._mint(recipient, initial_supply); - } - - // - // External - // + assert(!self.initializable.is_initialized(), Errors::ALREADY_INITIALIZED); + assert( + self.world().is_owner(get_caller_address(), get_contract_address().into()), + Errors::CALLER_IS_NOT_OWNER + ); + self.erc20_metadata.initialize(name, symbol, 18); + self._mint(recipient, initial_supply); - #[abi(embed_v0)] - impl ERC20MetadataImpl = - ERC20MetadataComponent::ERC20MetadataImpl; + self.initializable.initialize(); + } #[external(v0)] impl ERC20Impl of interface::IERC20 { fn total_supply(self: @ContractState) -> u256 { - //self.get_meta().total_supply - 0.into() + self.erc20_metadata.get_metadata().total_supply } fn balance_of(self: @ContractState, account: ContractAddress) -> u256 { @@ -118,8 +134,7 @@ mod ERC20 { #[external(v0)] impl ERC20CamelOnlyImpl of interface::IERC20CamelOnly { fn totalSupply(self: @ContractState) -> u256 { - // ERC20Impl::total_supply(self) - 0.into() + ERC20Impl::total_supply(self) } fn balanceOf(self: @ContractState, account: ContractAddress) -> u256 { @@ -170,21 +185,11 @@ mod ERC20 { // Internal // + impl InitializableInternalImpl = InitializableComponent::InternalImpl; + impl ERC20MetadataInternalImpl = ERC20MetadataComponent::InternalImpl; + #[generate_trait] impl WorldInteractionsImpl of WorldInteractionsTrait { - fn get_meta(self: @ContractState) -> ERC20Meta { - get!(self.world(), get_contract_address(), ERC20Meta) - } - - // Helper function to update total_supply model - fn update_total_supply(ref self: ContractState, subtract: u256, add: u256) { - let mut meta = self.get_meta(); - // adding and subtracting is fewer steps than if - meta.total_supply = meta.total_supply - subtract; - meta.total_supply = meta.total_supply + add; - set!(self.world(), (meta)); - } - // Helper function for balance model fn get_balance(self: @ContractState, account: ContractAddress) -> ERC20Balance { get!(self.world(), (get_contract_address(), account), ERC20Balance) @@ -245,21 +250,16 @@ mod ERC20 { #[generate_trait] impl InternalImpl of InternalTrait { - fn initializer(ref self: ContractState, name: felt252, symbol: felt252) { - let meta = ERC20Meta { token: get_contract_address(), name, symbol, total_supply: 0 }; - set!(self.world(), (meta)); - } - fn _mint(ref self: ContractState, recipient: ContractAddress, amount: u256) { assert(!recipient.is_zero(), Errors::MINT_TO_ZERO); - self.update_total_supply(0, amount); + self.erc20_metadata.update_total_supply(0, amount); self.update_balance(recipient, 0, amount); self.emit_event(Transfer { from: Zeroable::zero(), to: recipient, value: amount }); } fn _burn(ref self: ContractState, account: ContractAddress, amount: u256) { assert(!account.is_zero(), Errors::BURN_FROM_ZERO); - self.update_total_supply(amount, 0); + self.erc20_metadata.update_total_supply(amount, 0); self.update_balance(account, amount, 0); self.emit_event(Transfer { from: account, to: Zeroable::zero(), value: amount }); }