Skip to content

Commit

Permalink
Merge branch 'main' into 117-camel-case-1155-fork
Browse files Browse the repository at this point in the history
  • Loading branch information
julienbrs authored Aug 28, 2024
2 parents e3866e6 + a0fcddd commit b9f9121
Show file tree
Hide file tree
Showing 7 changed files with 193 additions and 287 deletions.
6 changes: 4 additions & 2 deletions src/components/minter/mint.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,9 @@ mod MintComponent {
}

#[derive(Drop, starknet::Event)]
struct SoldOut {}
struct SoldOut {
sold_out: bool
}

#[derive(Drop, starknet::Event)]
struct Buy {
Expand Down Expand Up @@ -409,7 +411,7 @@ mod MintComponent {
PublicSaleClose { old_value: true, new_value: false }
)
);
self.emit(Event::SoldOut(SoldOut {}));
self.emit(Event::SoldOut(SoldOut { sold_out: true }));
};
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/components/offsetter/interface.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ trait IOffsetHandler<TContractState> {
/// - If one of the carbon values is not enough or vintage status is not right,
/// the function will fail and no carbon will be retired and the function will revert.
fn retire_list_carbon_credits(
ref self: TContractState, vintages: Span<u256>, carbon_values: Span<u256>
ref self: TContractState, vintages: Span<u256>, cc_values: Span<u256>
);

fn claim(ref self: TContractState, amount: u128, timestamp: u128, proof: Array::<felt252>);
Expand Down
8 changes: 3 additions & 5 deletions src/components/offsetter/offset_handler.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -139,13 +139,11 @@ mod OffsetComponent {
}

fn retire_list_carbon_credits(
ref self: ComponentState<TContractState>,
vintages: Span<u256>,
carbon_values: Span<u256>
ref self: ComponentState<TContractState>, vintages: Span<u256>, cc_values: Span<u256>
) {
// [Check] vintages and carbon values are defined
assert(vintages.len() > 0, 'Inputs cannot be empty');
assert(vintages.len() == carbon_values.len(), 'Vintages and Values mismatch');
assert(vintages.len() == cc_values.len(), 'Vintages and Values mismatch');

let mut index: u32 = 0;
loop {
Expand All @@ -154,7 +152,7 @@ mod OffsetComponent {
Option::Some(value) => *value.unbox(),
Option::None => 0,
};
let carbon_amount = match carbon_values.get(index) {
let carbon_amount = match cc_values.get(index) {
Option::Some(value) => *value.unbox(),
Option::None => 0,
};
Expand Down
35 changes: 10 additions & 25 deletions src/contracts/project.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use starknet::{ContractAddress, ClassHash};

#[starknet::interface]
trait IExternal<TContractState> {
// fn mint(ref self: TContractState, to: ContractAddress, token_id: u256, value: u256);
fn mint(ref self: TContractState, to: ContractAddress, token_id: u256, value: u256);
fn burn(ref self: TContractState, from: ContractAddress, token_id: u256, value: u256);
fn batch_mint(
ref self: TContractState, to: ContractAddress, token_ids: Span<u256>, values: Span<u256>
Expand All @@ -29,7 +29,6 @@ trait IExternal<TContractState> {
fn balanceOfBatch(
self: @TContractState, accounts: Span<ContractAddress>, token_ids: Span<u256>
) -> Span<u256>;
fn shares_of(self: @TContractState, account: ContractAddress, token_id: u256) -> u256;
fn safe_transfer_from(
ref self: TContractState,
from: ContractAddress,
Expand Down Expand Up @@ -224,12 +223,12 @@ mod Project {
// Externals
#[abi(embed_v0)]
impl ExternalImpl of super::IExternal<ContractState> {
// fn mint(ref self: ContractState, to: ContractAddress, token_id: u256, value: u256) {
// // [Check] Only Minter can mint
// let isMinter = self.accesscontrol.has_role(MINTER_ROLE, get_caller_address());
// assert(isMinter, 'Only Minter can mint');
// self._mint(to, token_id, value);
// }
fn mint(ref self: ContractState, to: ContractAddress, token_id: u256, value: u256) {
// [Check] Only Minter can mint
let isMinter = self.accesscontrol.has_role(MINTER_ROLE, get_caller_address());
assert(isMinter, 'Only Minter can mint');
self._mint(to, token_id, value);
}

fn burn(ref self: ContractState, from: ContractAddress, token_id: u256, value: u256) {
// [Check] Only Offsetter can burn
Expand All @@ -252,7 +251,6 @@ mod Project {
token_ids: Span<u256>,
values: Span<u256>
) {
// TODO : Check that the caller is the owner of the value he wnt to burn
// [Check] Only Offsetter can burn
let isOffseter = self.accesscontrol.has_role(OFFSETTER_ROLE, get_caller_address());
assert(isOffseter, 'Only Offsetter can batch burn');
Expand Down Expand Up @@ -355,18 +353,6 @@ mod Project {
super::IExternal::balance_of_batch(self, accounts, token_ids)
}

fn shares_of(self: @ContractState, account: ContractAddress, token_id: u256) -> u256 {
let amount_cc_bought = self
.erc1155
.ERC1155_balances
.read((token_id, account)); // expressed in grams
let initial_project_supply = self.vintage.get_initial_project_cc_supply();
if initial_project_supply == 0 {
panic!("Initial project supply is not set");
}
(amount_cc_bought * CC_DECIMALS_MULTIPLIER) / initial_project_supply.into()
}

fn safe_transfer_from(
ref self: ContractState,
from: ContractAddress,
Expand Down Expand Up @@ -473,8 +459,8 @@ mod Project {
.emit(
ERC1155Component::Event::TransferSingle(
ERC1155Component::TransferSingle {
operator: get_contract_address(),
from: get_contract_address(),
operator: get_caller_address(),
from: Zeroable::zero(),
to,
id: token_id,
value: cc_value,
Expand Down Expand Up @@ -575,12 +561,11 @@ mod Project {
) {
let to_send = self.cc_to_internal(value, token_id);
self.erc1155.safe_transfer_from(from, to, token_id, to_send, data);
let cc_value = self.internal_to_cc(value, token_id);
self
.emit(
ERC1155Component::Event::TransferSingle(
ERC1155Component::TransferSingle {
operator: get_caller_address(), from, to, id: token_id, value: cc_value,
operator: get_caller_address(), from, to, id: token_id, value: value,
}
)
);
Expand Down
137 changes: 73 additions & 64 deletions tests/test_mint.cairo
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
use snforge_std::cheatcodes::events::EventSpyAssertionsTrait;
// TODO:
// - check if is_setup is needed
// - refactor project setup into helper function?

// Starknet deps

Expand Down Expand Up @@ -137,7 +134,8 @@ fn test_public_buy() {

start_cheat_caller_address(erc20_address, owner_address);
let erc20 = IERC20Dispatcher { contract_address: erc20_address };
erc20.transfer(user_address, money_amount);
let success = erc20.transfer(user_address, money_amount);
assert(success, 'Transfer failed');

start_cheat_caller_address(erc20_address, user_address);
erc20.approve(minter_address, money_amount);
Expand Down Expand Up @@ -231,7 +229,8 @@ fn test_get_remaining_mintable_cc() {

start_cheat_caller_address(erc20_address, owner_address);
let erc20 = IERC20Dispatcher { contract_address: erc20_address };
erc20.transfer(user_address, amount_to_buy);
let success = erc20.transfer(user_address, amount_to_buy);
assert(success, 'Transfer failed');

start_cheat_caller_address(erc20_address, user_address);
erc20.approve(minter_address, amount_to_buy);
Expand All @@ -251,7 +250,8 @@ fn test_get_remaining_mintable_cc() {
// Mint all the remaining carbon credits
let remaining_mintable_cc = minter.get_remaining_mintable_cc();
start_cheat_caller_address(erc20_address, owner_address);
erc20.transfer(user_address, remaining_mintable_cc);
let success = erc20.transfer(user_address, remaining_mintable_cc);
assert(success, 'Transfer failed');

let remaining_money_to_buy = remaining_mintable_cc
* minter.get_unit_price()
Expand Down Expand Up @@ -328,7 +328,8 @@ fn test_get_min_money_amount_per_tx() {
let amount_to_buy: u256 = 1000;
start_cheat_caller_address(erc20_address, owner_address);
let erc20 = IERC20Dispatcher { contract_address: erc20_address };
erc20.transfer(user_address, amount_to_buy);
let success = erc20.transfer(user_address, amount_to_buy);
assert(success, 'Transfer failed');

start_cheat_caller_address(erc20_address, user_address);
erc20.approve(minter_address, amount_to_buy);
Expand Down Expand Up @@ -379,60 +380,62 @@ fn test_is_sold_out() {
let expected_event_sale_close = MintComponent::Event::PublicSaleClose(
MintComponent::PublicSaleClose { old_value: true, new_value: false }
);
let expected_event_sold_out = MintComponent::Event::SoldOut(MintComponent::SoldOut {});
let expected_event_sold_out = MintComponent::Event::SoldOut(
MintComponent::SoldOut { sold_out: true }
);
spy.assert_emitted(@array![(minter_address, expected_event_sale_close)]);
spy.assert_emitted(@array![(minter_address, expected_event_sold_out)]);
}

// #[test]
// #[should_panic(expected: 'Sale is closed')]
// fn test_public_buy_when_sold_out() {
// let owner_address: ContractAddress = contract_address_const::<'OWNER'>();
// let user_address: ContractAddress = contract_address_const::<'USER'>();
// let project_address = default_setup_and_deploy();
// let erc20_address = deploy_erc20();
// let minter_address = deploy_minter(project_address, erc20_address);

// start_cheat_caller_address(project_address, owner_address);
// let project_contract = IProjectDispatcher { contract_address: project_address };
// project_contract.grant_minter_role(minter_address);
// stop_cheat_caller_address(project_address);

// let minter = IMintDispatcher { contract_address: minter_address };
// let remaining_mintable_cc = minter.get_remaining_mintable_cc();
// buy_utils(owner_address, user_address, minter_address, remaining_mintable_cc);

// let remaining_cc_after_buying_all = minter.get_remaining_mintable_cc();
// assert(remaining_cc_after_buying_all == 0, 'remaining cc wrong value');

// start_cheat_caller_address(erc20_address, user_address);
// buy_utils(owner_address, user_address, minter_address, 1);
// }

// #[test]
// #[should_panic(expected: 'Minting limit reached')]
// fn test_public_buy_exceeds_mint_limit() {
// let owner_address: ContractAddress = contract_address_const::<'OWNER'>();
// let user_address: ContractAddress = contract_address_const::<'USER'>();
// let project_address = default_setup_and_deploy();
// let erc20_address = deploy_erc20();
// let minter_address = deploy_minter(project_address, erc20_address);

// start_cheat_caller_address(project_address, owner_address);
// let project_contract = IProjectDispatcher { contract_address: project_address };
// project_contract.grant_minter_role(minter_address);
// stop_cheat_caller_address(project_address);

// let minter = IMintDispatcher { contract_address: minter_address };
// let remaining_mintable_cc = minter.get_remaining_mintable_cc();
// buy_utils(owner_address, user_address, minter_address, remaining_mintable_cc - 1);

// let remaining_cc_after_partial_buy = minter.get_remaining_mintable_cc();
// assert(remaining_cc_after_partial_buy == 1, 'remaining cc wrong value');

// start_cheat_caller_address(erc20_address, user_address);
// buy_utils(owner_address, user_address, minter_address, 2); // This should cause a panic
// }
#[test]
#[should_panic(expected: 'Sale is closed')]
fn test_public_buy_when_sold_out() {
let owner_address: ContractAddress = contract_address_const::<'OWNER'>();
let user_address: ContractAddress = contract_address_const::<'USER'>();
let project_address = default_setup_and_deploy();
let erc20_address = deploy_erc20();
let minter_address = deploy_minter(project_address, erc20_address);

start_cheat_caller_address(project_address, owner_address);
let project_contract = IProjectDispatcher { contract_address: project_address };
project_contract.grant_minter_role(minter_address);
stop_cheat_caller_address(project_address);

let minter = IMintDispatcher { contract_address: minter_address };
let remaining_mintable_cc = minter.get_remaining_mintable_cc();
buy_utils(owner_address, user_address, minter_address, remaining_mintable_cc);

let remaining_cc_after_buying_all = minter.get_remaining_mintable_cc();
assert(remaining_cc_after_buying_all == 0, 'remaining cc wrong value');

start_cheat_caller_address(erc20_address, user_address);
buy_utils(owner_address, user_address, minter_address, 1);
}

#[test]
#[should_panic(expected: 'Minting limit reached')]
fn test_public_buy_exceeds_mint_limit() {
let owner_address: ContractAddress = contract_address_const::<'OWNER'>();
let user_address: ContractAddress = contract_address_const::<'USER'>();
let project_address = default_setup_and_deploy();
let erc20_address = deploy_erc20();
let minter_address = deploy_minter(project_address, erc20_address);

start_cheat_caller_address(project_address, owner_address);
let project_contract = IProjectDispatcher { contract_address: project_address };
project_contract.grant_minter_role(minter_address);
stop_cheat_caller_address(project_address);

let minter = IMintDispatcher { contract_address: minter_address };
let remaining_mintable_cc = minter.get_remaining_mintable_cc();
buy_utils(owner_address, user_address, minter_address, remaining_mintable_cc - 1);

let remaining_cc_after_partial_buy = minter.get_remaining_mintable_cc();
assert(remaining_cc_after_partial_buy == 1, 'remaining cc wrong value');

start_cheat_caller_address(erc20_address, user_address);
buy_utils(owner_address, user_address, minter_address, 2); // This should cause a panic
}

#[test]
fn test_set_min_money_amount_per_tx() {
Expand Down Expand Up @@ -645,13 +648,15 @@ fn test_withdraw_without_owner_role() {
start_cheat_caller_address(project_address, owner_address);
let project = IProjectDispatcher { contract_address: project_address };
let minter = IMintDispatcher { contract_address: minter_address };
let vintage = IVintageDispatcher { contract_address: project_address };
project.grant_minter_role(minter_address);

start_cheat_caller_address(project_address, minter_address);
let share: u256 = 10 * MULTIPLIER_TONS_TO_MGRAMS / 100; // 10%
buy_utils(owner_address, owner_address, minter_address, share);
let initial_project_supply = vintage.get_initial_project_cc_supply();
let cc_to_mint: u256 = initial_project_supply / 10; // 10% of the initial supply
buy_utils(owner_address, owner_address, minter_address, cc_to_mint);
start_cheat_caller_address(erc20_address, user_address);
buy_utils(owner_address, user_address, minter_address, share);
buy_utils(owner_address, user_address, minter_address, cc_to_mint);

start_cheat_caller_address(minter_address, user_address);
minter.withdraw();
Expand All @@ -678,8 +683,10 @@ fn test_retrieve_amount() {
let minter = IMintDispatcher { contract_address: minter_address };
let second_er20 = IERC20Dispatcher { contract_address: second_erc20_address };

// Transfering incorrect token to minter
second_er20.transfer(minter_address, 1000);
// Transferring incorrect token to minter
let success = second_er20.transfer(minter_address, 1000);
assert(success, 'Transfer failed');

start_cheat_caller_address(second_erc20_address, minter_address);
minter.retrieve_amount(second_erc20_address, owner_address, 1000);
let balance_after = second_er20.balance_of(owner_address);
Expand Down Expand Up @@ -712,8 +719,10 @@ fn test_retrieve_amount_without_owner_role() {
let minter = IMintDispatcher { contract_address: minter_address };
let second_er20 = IERC20Dispatcher { contract_address: second_erc20_address };

// Transfering incorrect token to minter
second_er20.transfer(minter_address, 1000);
// Transferring incorrect token to minter
let success = second_er20.transfer(minter_address, 1000);
assert(success, 'Transfer failed');

start_cheat_caller_address(minter_address, user_address);
start_cheat_caller_address(second_erc20_address, minter_address);
minter.retrieve_amount(second_erc20_address, user_address, 1000);
Expand Down
Loading

0 comments on commit b9f9121

Please sign in to comment.