Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: implementation of token transfer (ICS20) contract #24

Merged
merged 16 commits into from
Jul 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
CONTRACT_SRC=${CONTRACT_SRC:-$(pwd)/contracts/target/dev/starknet_ibc_Transfer.contract_class.json}
RPC_URL=https://starknet-sepolia.public.blastapi.io/rpc/v0_7
ACCOUNT_SRC="${HOME}/.starkli-wallets/deployer/account.json"
KEYSTORE_SRC="${HOME}/.starkli-wallets/deployer/keystore.json"
KEYSTORE_PASS=<KEYSTORE_PASSWORD>

ERC20_CLASS_HASH=""
ICS20_CLASS_HASH=""
CONTRACT_ADDRESS=""
30 changes: 30 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name: Tests
on:
pull_request:
paths:
- .github/workflows/tests.yaml
- contracts/**
- justfile

push:
tags:
- v[0-9]+.*
branches:
- "release/*"
- main

jobs:
test-contracts:
name: Test Cairo Contracts
runs-on: ubuntu-latest
timeout-minutes: 60
steps:
- uses: actions/checkout@v4
- name: Install Scarb
uses: software-mansion/setup-scarb@v1
with:
scarb-version: "2.6.5"
- name: Install Just
uses: extractions/setup-just@v1
- name: Run Tests
run: just test-contracts
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,7 @@ corelib/
target/
**/Cargo.lock

.env

# vscode
.vscode/
3 changes: 3 additions & 0 deletions contracts/Scarb.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ snforge_std = { git = "https://github.com/foundry-rs/starknet-foundry", tag = "
[lib]

[[target.starknet-contract]]
allowed-libfuncs-list.name = "experimental"
sierra = true
casm = false

[tool.fmt]
sort-module-level-items = true
3 changes: 3 additions & 0 deletions contracts/src/apps.cairo
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
pub mod governance;
pub mod mintable;
pub mod transfer;
pub mod transferrable;
2 changes: 2 additions & 0 deletions contracts/src/apps/governance.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pub mod component;
pub mod interface;
30 changes: 30 additions & 0 deletions contracts/src/apps/governance/component.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#[starknet::component]
pub mod IBCGovernanceComponent {
use starknet::ContractAddress;
use starknet::get_caller_address;
use starknet_ibc::apps::governance::interface::IGovernance;

#[storage]
struct Storage {
governor: ContractAddress,
}

#[event]
#[derive(Drop, Debug, starknet::Event)]
pub enum Event {}

#[embeddable_as(Governance)]
pub impl GovernanceImpl<
TContractState, +HasComponent<TContractState>, +Drop<TContractState>
> of IGovernance<ComponentState<TContractState>> {}

#[generate_trait]
pub impl GovernanceInternalImpl<
TContractState, +HasComponent<TContractState>, +Drop<TContractState>
> of GovernanceInternalTrait<TContractState> {
fn initializer(ref self: ComponentState<TContractState>) {
self.governor.write(get_caller_address());
}
}
}

3 changes: 3 additions & 0 deletions contracts/src/apps/governance/interface.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#[starknet::interface]
pub trait IGovernance<TContractState> {}

3 changes: 3 additions & 0 deletions contracts/src/apps/mintable.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pub mod component;
pub mod errors;
pub mod interface;
86 changes: 86 additions & 0 deletions contracts/src/apps/mintable/component.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
#[starknet::component]
pub mod ERC20MintableComponent {
use core::num::traits::Zero;
use openzeppelin::token::erc20::ERC20Component::InternalTrait;
use openzeppelin::token::erc20::ERC20Component;
use openzeppelin::token::erc20::erc20::ERC20Component::Transfer;
use starknet::ContractAddress;
use starknet::get_caller_address;
use starknet_ibc::apps::mintable::errors::MintableErrors;
use starknet_ibc::apps::mintable::interface::IERC20Mintable;

#[storage]
struct Storage {
permission: ContractAddress,
}

#[event]
#[derive(Drop, Debug, starknet::Event)]
pub enum Event {}

#[embeddable_as(ERC20Mintable)]
pub impl ERC20MintableImpl<
TContractState,
+HasComponent<TContractState>,
+Drop<TContractState>,
impl ERC20: ERC20Component::HasComponent<TContractState>,
> of IERC20Mintable<ComponentState<TContractState>> {
fn permissioned_mint(
ref self: ComponentState<TContractState>, recipient: ContractAddress, amount: u256
) {
let permitted_minter = self.permission.read();
assert(permitted_minter == get_caller_address(), MintableErrors::UNAUTHORIZED_MINTER);

self.mint(recipient, amount);
}

fn permissioned_burn(
ref self: ComponentState<TContractState>, account: ContractAddress, amount: u256
) {
let permitted_burner = self.permission.read();
assert(permitted_burner == get_caller_address(), MintableErrors::UNAUTHORIZED_BURNER);
self.burn(account, amount);
}
}

#[generate_trait]
pub impl ERC20MintableInternalImpl<
TContractState,
+HasComponent<TContractState>,
+Drop<TContractState>,
impl ERC20: ERC20Component::HasComponent<TContractState>
> of ERC20MintableInternalTrait<TContractState> {
fn initializer(ref self: ComponentState<TContractState>) {
self.permission.write(get_caller_address());
}

fn mint(
ref self: ComponentState<TContractState>, recipient: ContractAddress, amount: u256
) {
let mut erc20_comp = get_dep_component_mut!(ref self, ERC20);
assert(recipient.is_non_zero(), MintableErrors::MINT_TO_ZERO);

erc20_comp.ERC20_total_supply.write(erc20_comp.ERC20_total_supply.read() + amount);
erc20_comp
.ERC20_balances
.write(recipient, erc20_comp.ERC20_balances.read(recipient) + amount);

erc20_comp.emit(Transfer { from: Zero::zero(), to: recipient, value: amount });
}

fn burn(ref self: ComponentState<TContractState>, account: ContractAddress, amount: u256) {
let mut erc20_comp = get_dep_component_mut!(ref self, ERC20);
assert(account.is_non_zero(), MintableErrors::BURN_FROM_ZERO);

let total_supply = erc20_comp.ERC20_total_supply.read();
assert(total_supply >= amount, MintableErrors::INSUFFICIENT_SUPPLY);
erc20_comp.ERC20_total_supply.write(total_supply - amount);

let balance = erc20_comp.ERC20_balances.read(account);
assert(balance >= amount, MintableErrors::INSUFFICIENT_BALANCE);
erc20_comp.ERC20_balances.write(account, balance - amount);

erc20_comp.emit(Transfer { from: account, to: Zero::zero(), value: amount });
}
}
}
9 changes: 9 additions & 0 deletions contracts/src/apps/mintable/errors.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
pub mod MintableErrors {
pub const UNAUTHORIZED_MINTER: felt252 = 'Unauthorized minter';
pub const UNAUTHORIZED_BURNER: felt252 = 'Unauthorized burner';
pub const BURN_FROM_ZERO: felt252 = 'ERC20: burn from 0';
pub const MINT_TO_ZERO: felt252 = 'ERC20: mint to 0';
pub const INSUFFICIENT_BALANCE: felt252 = 'ERC20: insufficient balance';
pub const INSUFFICIENT_SUPPLY: felt252 = 'ERC20: insufficient supply';
}

7 changes: 7 additions & 0 deletions contracts/src/apps/mintable/interface.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
use starknet::ContractAddress;

#[starknet::interface]
pub trait IERC20Mintable<TContractState> {
fn permissioned_mint(ref self: TContractState, recipient: ContractAddress, amount: u256);
fn permissioned_burn(ref self: TContractState, account: ContractAddress, amount: u256);
}
1 change: 1 addition & 0 deletions contracts/src/apps/transfer.cairo
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub mod component;
pub mod errors;
pub mod interface;
pub mod types;
Loading
Loading