diff --git a/transaction_restriction_logic/.gitignore b/transaction_restriction_logic/.gitignore new file mode 100644 index 0000000..4096f8b --- /dev/null +++ b/transaction_restriction_logic/.gitignore @@ -0,0 +1,5 @@ +target +.snfoundry_cache/ +snfoundry_trace/ +coverage/ +profile/ diff --git a/transaction_restriction_logic/Scarb.lock b/transaction_restriction_logic/Scarb.lock new file mode 100644 index 0000000..f367ac6 --- /dev/null +++ b/transaction_restriction_logic/Scarb.lock @@ -0,0 +1,24 @@ +# Code generated by scarb DO NOT EDIT. +version = 1 + +[[package]] +name = "snforge_scarb_plugin" +version = "0.59.0" +source = "registry+https://scarbs.xyz/" +checksum = "sha256:871fba677c03b66a1bf40815dac0ab1b385eb1b9be6e6c3cf2ad9788eeb2b6bb" + +[[package]] +name = "snforge_std" +version = "0.59.0" +source = "registry+https://scarbs.xyz/" +checksum = "sha256:3620924fa08bd2d740b2b5b01ef86c8dab3d4b9c2206387c8dbdc8d2ec15133e" +dependencies = [ + "snforge_scarb_plugin", +] + +[[package]] +name = "transaction_restriction_logic" +version = "0.1.0" +dependencies = [ + "snforge_std", +] diff --git a/transaction_restriction_logic/Scarb.toml b/transaction_restriction_logic/Scarb.toml new file mode 100644 index 0000000..007e54a --- /dev/null +++ b/transaction_restriction_logic/Scarb.toml @@ -0,0 +1,52 @@ +[package] +name = "transaction_restriction_logic" +version = "0.1.0" +edition = "2024_07" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest.html + +[dependencies] +starknet = "2.17.0" + +[dev-dependencies] +snforge_std = "0.59.0" +assert_macros = "2.17.0" + +[[target.starknet-contract]] +sierra = true + +[scripts] +test = "snforge test" + +[tool.scarb] +allow-prebuilt-plugins = ["snforge_std"] + +# Visit https://foundry-rs.github.io/starknet-foundry/appendix/scarb-toml.html for more information + +# [tool.snforge] # Define `snforge` tool section +# exit_first = true # Stop tests execution immediately upon the first failure +# fuzzer_runs = 1234 # Number of runs of the random fuzzer +# fuzzer_seed = 1111 # Seed for the random fuzzer + +# [[tool.snforge.fork]] # Used for fork testing +# name = "SOME_NAME" # Fork name +# url = "http://your.rpc.url" # Url of the RPC provider +# block_id.tag = "latest" # Block to fork from (block tag) + +# [[tool.snforge.fork]] +# name = "SOME_SECOND_NAME" +# url = "http://your.second.rpc.url" +# block_id.number = "123" # Block to fork from (block number) + +# [[tool.snforge.fork]] +# name = "SOME_THIRD_NAME" +# url = "http://your.third.rpc.url" +# block_id.hash = "0x123" # Block to fork from (block hash) + +# [profile.dev.cairo] # Configure Cairo compiler +# unstable-add-statements-code-locations-debug-info = true # Should be used if you want to use coverage +# unstable-add-statements-functions-debug-info = true # Should be used if you want to use coverage/profiler +# inlining-strategy = "avoid" # Should be used if you want to use coverage + +# [features] # Used for conditional compilation +# enable_for_tests = [] # Feature name and list of other features that should be enabled with it diff --git a/transaction_restriction_logic/snfoundry.toml b/transaction_restriction_logic/snfoundry.toml new file mode 100644 index 0000000..686c2ab --- /dev/null +++ b/transaction_restriction_logic/snfoundry.toml @@ -0,0 +1,11 @@ +# Visit https://foundry-rs.github.io/starknet-foundry/appendix/snfoundry-toml.html +# and https://foundry-rs.github.io/starknet-foundry/projects/configuration.html for more information + +# [sncast.default] # Define a profile name +# url = "https://api.zan.top/public/starknet-sepolia/rpc/v0_10" # Url of the RPC provider +# accounts-file = "../account-file" # Path to the file with the account data +# account = "mainuser" # Account from `accounts_file` or default account file that will be used for the transactions +# keystore = "~/keystore" # Path to the keystore file +# wait-params = { timeout = 300, retry-interval = 10 } # Wait for submitted transaction parameters +# block-explorer = "Voyager" # Block explorer service used to display links to transaction details +# show-explorer-links = true # Print links pointing to pages with transaction details in the chosen block explorer diff --git a/transaction_restriction_logic/src/lib.cairo b/transaction_restriction_logic/src/lib.cairo new file mode 100644 index 0000000..938bc38 --- /dev/null +++ b/transaction_restriction_logic/src/lib.cairo @@ -0,0 +1,203 @@ +// /// Interface representing `HelloContract`. +// /// This interface allows modification and retrieval of the contract balance. +// #[starknet::interface] +// pub trait IHelloStarknet { +// /// Increase contract balance. +// fn increase_balance(ref self: TContractState, amount: u256); +// /// Retrieve contract balance. +// fn get_balance(self: @TContractState) -> u256; +// } + +// /// Simple contract for managing balance. +// #[starknet::contract] +// mod HelloStarknet { +// use starknet::storage::{StoragePointerReadAccess, StoragePointerWriteAccess}; + +// #[storage] +// struct Storage { +// balance: u256, +// } + +// #[abi(embed_v0)] +// impl HelloStarknetImpl of super::IHelloStarknet { +// fn increase_balance(ref self: ContractState, amount: u256) { +// assert(amount != 0, 'Amount cannot be 0'); +// self.balance.write(self.balance.read() + amount); +// } + +// fn get_balance(self: @ContractState) -> u256 { +// self.balance.read() +// } +// } +// } + +use starknet::ContractAddress; + +#[starknet::interface] +pub trait IERCOToken { + fn get_name(self: @TContractState) -> felt252; + fn get_symbol(self: @TContractState) -> felt252; + fn get_decimals(self: @TContractState) -> u8; + fn get_total_supply(self: @TContractState) -> u256; + fn balance_of(self: @TContractState, address: ContractAddress) -> u256; + fn allowance(self: @TContractState, owner: ContractAddress, spender: ContractAddress) -> u256; + fn transfer(ref self: TContractState, recipient: ContractAddress, amount: u256); + fn transferFrom(ref self: TContractState, sender: ContractAddress, recipient: ContractAddress, amount: u256); + fn approve(ref self: TContractState, spender: ContractAddress, amount: u256); + fn increase_allowance(ref self: TContractState, spender: ContractAddress, added_value: u256); + fn decrease_allowance(ref self: TContractState, spender: ContractAddress, subtracted_value: u256); + fn revoke_spender(ref self: TContractState, spender: ContractAddress); + fn burn(ref self: TContractState, user:ContractAddress, amount: u256); + fn only_admin(self: @TContractState); +} + +#[starknet::contract] +pub mod erc20 { + use starknet::storage::StoragePathEntry; + use core::num::traits::Zero; + use starknet::{get_caller_address, contract_address_const}; + use super::ContractAddress; + use starknet::storage::{Map, StorageMapReadAccess, StorageMapWriteAccess, StoragePointerReadAccess, StoragePointerWriteAccess}; + use super::IERCOToken; + + #[storage] + pub struct Storage{ + name: felt252, + symbol: felt252, + decimals: u8, + max_limit: u256, + balances: Map, + allowances: Map<(ContractAddress, ContractAddress), u256>, + admin: ContractAddress + } + + // #[event] + // #[derive(Copy, Drop, PartialEq, starknet::Event)] + // pub enum Event { + + // } + + #[constructor] + fn constructor(ref self: ContractState, name: felt252, decimals: u8, initial_supply: u256, symbol: felt252, admin: ContractAddress) { + self.name.write(name); + self.symbol.write(symbol); + self.decimals.write(decimals); + self.max_limit.write(initial_supply); + self.admin.write(admin) + } + + #[abi(embed_v0)] + impl IER20Impl of IERCOToken{ + fn get_name(self: @ContractState) -> felt252 { + self.name.read() + } + + fn get_symbol(self: @ContractState) -> felt252{ + self.symbol.read() + } + + fn get_decimals(self: @ContractState) -> u8 { + self.decimals.read() + } + + fn get_total_supply(self: @ContractState) -> u256 { + self.max_limit.read() + } + + fn balance_of(self: @ContractState, address: ContractAddress) -> u256 { + self.balances.read(address) + } + + fn allowance(self: @ContractState, owner: ContractAddress, spender: ContractAddress) -> u256 { + self.allowances.read((owner, spender)) + } + + fn transfer(ref self: ContractState, recipient: ContractAddress, amount: u256) { + let sender = get_caller_address(); + self._transfer(sender, recipient, amount) + } + + fn transferFrom(ref self: ContractState, sender: ContractAddress, recipient: ContractAddress, amount: u256) { + let caller = get_caller_address(); + self.spend_allowance(sender, caller, amount); + self._transfer(sender, recipient, amount); + } + + fn approve(ref self: ContractState, spender: ContractAddress, amount: u256) { + let caller = get_caller_address(); + self.approve_helper(caller, spender, amount); + } + + fn increase_allowance( + ref self: ContractState, spender: ContractAddress, added_value: u256, + ) { + let caller = get_caller_address(); + self + .approve_helper( + caller, spender, self.allowances.read((caller, spender)) + added_value, + ); + } + + fn decrease_allowance( + ref self: ContractState, spender: ContractAddress, subtracted_value: u256, + ) { + let caller = get_caller_address(); + self + .approve_helper( + caller, spender, self.allowances.read((caller, spender)) - subtracted_value, + ); + } + + fn revoke_spender(ref self: ContractState, spender: ContractAddress) { + let owner = get_caller_address(); + assert(spender.is_non_zero(), 'Zero address'); + + self.allowances.entry((owner, spender)).write(0); + } + + fn burn(ref self: ContractState, user: ContractAddress, amount: u256) { + self.only_admin(); + + assert(amount > 0, 'Invalid amount'); + let balance = self.balances.read(user); + assert(balance >= amount, 'Insufficient balance'); + + self.balances.write(user, balance - amount); + + let supply = self.max_limit.read(); + + self.max_limit.write(supply - amount); + } + + fn only_admin(self: @ContractState) { + let caller = get_caller_address(); + + assert( + caller == self.admin.read(), + 'Only admin' + ); + } + + + } + + #[generate_trait] + impl InternalImpl of InternalTrait{ + fn _transfer(ref self: ContractState, sender: ContractAddress, recipient: ContractAddress, amount: u256) { + assert(sender.is_non_zero(), 'Transfer from zero'); + assert(recipient.is_non_zero(), 'Transfer to zero'); + self.balances.write(sender, self.balances.read(sender) - amount); + self.balances.write(recipient, self.balances.read(recipient) + amount); + } + + fn spend_allowance(ref self: ContractState, owner: ContractAddress, spender: ContractAddress, amount: u256) { + let allowance = self.allowances.read((owner, spender)); + self.allowances.write((owner, spender), allowance - amount); + } + + fn approve_helper(ref self: ContractState, owner: ContractAddress, spender: ContractAddress, amount: u256) { + assert(spender.is_non_zero(), 'Approval to zero'); + self.allowances.write((owner, spender), amount); + } + } +} \ No newline at end of file diff --git a/transaction_restriction_logic/tests/test_contract.cairo b/transaction_restriction_logic/tests/test_contract.cairo new file mode 100644 index 0000000..e69de29