Skip to content

Commit

Permalink
Migrate to Cairo 2.3.1 & Components (#26)
Browse files Browse the repository at this point in the history
* Update Scarb to 2.3.0

* Update to Scarb 2.3.1

* Add Scarb.lock

* Refactor airdrop to be its own Component

* WIP

* Fix syntax, use new

* Remove vote_investor as it's Carmine only

* Migrate main contract file

* Finish migration

* Add CI

* Fix scarb version in CI

* Format
  • Loading branch information
tensojka authored Nov 17, 2023
1 parent 8640104 commit ab60119
Show file tree
Hide file tree
Showing 10 changed files with 180 additions and 331 deletions.
2 changes: 1 addition & 1 deletion .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
// "forwardPorts": [],

// Use 'postCreateCommand' to run commands after the container is created.
"postCreateCommand": "curl --proto '=https' --tlsv1.2 -sSf https://docs.swmansion.com/scarb/install.sh | bash -s -- -v 0.6.2",
"postCreateCommand": "curl --proto '=https' --tlsv1.2 -sSf https://docs.swmansion.com/scarb/install.sh | bash -s -- -v 2.3.1",
"customizations": {
"vscode": {
"extensions": [
Expand Down
11 changes: 3 additions & 8 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,16 @@ on:
- '.github/'

env:
LINK: https://github.com/software-mansion/scarb/releases/download/v0.6.2/scarb-v0.6.2-x86_64-unknown-linux-gnu.tar.gz
NAME: scarb-v0.6.2-x86_64-unknown-linux-gnu
SCARB_VERSION: 2.3.1

jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout (GitHub)
uses: actions/checkout@v3
- name: Download binaries
run: curl -L -o $NAME.tar.gz $LINK
- name: Prepare binaries
run: tar -xvf $NAME.tar.gz
- name: Make binaries available
run: echo "./$NAME/bin" >> $GITHUB_PATH
- name: Install Scarb
run: curl --proto '=https' --tlsv1.2 -sSf https://docs.swmansion.com/scarb/install.sh | bash -s -- -v $SCARB_VERSION
- name: Check formatting
run: scarb fmt --check
- name: Build with scarb
Expand Down
6 changes: 6 additions & 0 deletions Scarb.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Code generated by scarb DO NOT EDIT.
version = 1

[[package]]
name = "governance"
version = "0.2.0"
98 changes: 59 additions & 39 deletions src/airdrop.cairo
Original file line number Diff line number Diff line change
@@ -1,65 +1,85 @@
// https://github.com/CarmineOptions/carmine-api/blob/master/carmine-api-airdrop/src/merkle_tree.rs

mod Airdrop {
use starknet::ContractAddress;

#[starknet::interface]
trait IAirdrop<TContractState> {
fn claim(
ref self: TContractState, claimee: ContractAddress, amount: u128, proof: Array::<felt252>
);
}

#[starknet::component]
mod airdrop {
use governance::contract::IGovernance;
use array::ArrayTrait;
use hash::LegacyHash;
use traits::Into;
use starknet::ContractAddress;
use starknet::ContractAddressIntoFelt252;
use starknet::event::EventEmitter;
use starknet::ContractAddress;
//use starknet::event::EventEmitter;
use traits::TryInto;
use option::OptionTrait;

use governance::merkle_tree::MerkleTree;
use governance::merkle_tree::MerkleTreeTrait;

use governance::contract::Governance;
use governance::contract::Governance::ContractState;
use governance::traits::IGovernanceTokenDispatcher;
use governance::traits::IGovernanceTokenDispatcherTrait;
use governance::contract::Governance::{governance_token_address, airdrop_claimed, merkle_root};

fn get_merkle_root() -> felt252 {
let state = Governance::unsafe_new_contract_state();
let root = merkle_root::InternalContractStateTrait::read(@state.merkle_root);
if (root == 0) {
// part of migration, to be removed later
0x6d5f4866e61240e8f14de3d5c994153b1bcbf58603f64fa1a0500074b8c8d38 // airdrop week5-week8, from round_2_composed.csv
} else {
root
}
#[storage]
struct Storage {
airdrop_claimed: LegacyMap::<ContractAddress, u128>,
merkle_root: felt252
}

// Lets claimee claim from merkle tree the amount - claimed_so_far
fn claim(claimee: ContractAddress, amount: u128, proof: Array::<felt252>) {
let mut state = Governance::unsafe_new_contract_state();
#[derive(starknet::Event, Drop)]
#[event]
enum Event {
Claimed: Claimed
}

let mut merkle_tree = MerkleTreeTrait::new();
let amount_felt: felt252 = amount.into();
let leaf = LegacyHash::hash(claimee.into(), amount_felt);
#[derive(starknet::Event, Drop)]
struct Claimed {
address: ContractAddress,
received: u128
}
#[embeddable_as(AirdropImpl)]
impl Airdrop<
TContractState, +HasComponent<TContractState>
> of super::IAirdrop<ComponentState<TContractState>> {
// Lets claimee claim from merkle tree the amount - claimed_so_far
fn claim(
ref self: ComponentState<TContractState>,
claimee: ContractAddress,
amount: u128,
proof: Array::<felt252>
) {
let mut merkle_tree = MerkleTreeTrait::new();
let amount_felt: felt252 = amount.into();
let leaf = LegacyHash::hash(claimee.into(), amount_felt);

let root = merkle_tree.compute_root(leaf, proof.span());
assert(root == get_merkle_root(), 'invalid proof');
let root = merkle_tree.compute_root(leaf, proof.span());
let state = Governance::unsafe_new_contract_state();
let stored_root = self.merkle_root.read();
assert(root == stored_root, 'invalid proof');

let claimed_so_far: u128 = airdrop_claimed::InternalContractStateTrait::read(
@state.airdrop_claimed, claimee
);
assert(claimed_so_far < amount, 'claiming more than eligible for');
let to_mint = amount - claimed_so_far;
let claimed_so_far: u128 = self.airdrop_claimed.read(claimee);
assert(claimed_so_far < amount, 'claiming more than eligible for');
let to_mint = amount - claimed_so_far;

// Mint
let govtoken_addr = governance_token_address::InternalContractStateTrait::read(
@state.governance_token_address
);
IGovernanceTokenDispatcher {
contract_address: govtoken_addr
}.mint(claimee, u256 { high: 0, low: to_mint });
// Mint
let govtoken_addr = state.get_governance_token_address();
IGovernanceTokenDispatcher { contract_address: govtoken_addr }
.mint(claimee, u256 { high: 0, low: to_mint });

// Emit event
state.emit(Governance::Claimed { address: claimee, received: to_mint });
// Write new claimed amt
self.airdrop_claimed.write(claimee, to_mint + claimed_so_far);

// Write new claimed amt
airdrop_claimed::InternalContractStateTrait::write(
ref state.airdrop_claimed, claimee, to_mint + claimed_so_far
);
// Emit event
self.emit(Claimed { address: claimee, received: to_mint });
}
}
}
32 changes: 11 additions & 21 deletions src/contract.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,7 @@ trait IGovernance<TContractState> {

// AIRDROPS

fn claim(
ref self: TContractState, address: ContractAddress, amount: u128, proof: Array::<felt252>
);
// in component

// OPTIONS

Expand All @@ -42,11 +40,17 @@ mod Governance {
use governance::types::ContractType;
use governance::types::PropDetails;
use governance::upgrades::Upgrades;
use governance::airdrop::Airdrop;
use governance::options::Options;
use governance::airdrop::airdrop as airdrop_component;

use starknet::ContractAddress;


component!(path: airdrop_component, storage: airdrop, event: AirdropEvent);

#[abi(embed_v0)]
impl Airdrop = airdrop_component::AirdropImpl<ContractState>;

#[storage]
struct Storage {
proposal_details: LegacyMap::<felt252, PropDetails>,
Expand All @@ -60,10 +64,10 @@ mod Governance {
total_investor_distributed_power: felt252,
governance_token_address: ContractAddress,
amm_address: ContractAddress,
airdrop_claimed: LegacyMap::<ContractAddress, u128>,
delegate_hash: LegacyMap::<ContractAddress, felt252>,
total_delegated_to: LegacyMap::<ContractAddress, u128>,
merkle_root: felt252
#[substorage(v0)]
airdrop: airdrop_component::Storage
}

// PROPOSALS
Expand All @@ -82,18 +86,12 @@ mod Governance {
opinion: VoteStatus
}

#[derive(starknet::Event, Drop)]
struct Claimed {
address: ContractAddress,
received: u128
}

#[derive(starknet::Event, Drop)]
#[event]
enum Event {
Proposed: Proposed,
Voted: Voted,
Claimed: Claimed
AirdropEvent: airdrop_component::Event
}

#[constructor]
Expand Down Expand Up @@ -145,14 +143,6 @@ mod Governance {
Upgrades::apply_passed_proposal(prop_id)
}

// AIRDROPS

fn claim(
ref self: ContractState, address: ContractAddress, amount: u128, proof: Array::<felt252>
) {
Airdrop::claim(address, amount, proof)
}

fn add_0911_1611_options(ref self: ContractState) {
Options::run_add_0911_1611_options()
}
Expand Down
4 changes: 1 addition & 3 deletions src/merkle_tree.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,7 @@ impl MerkleTreeImpl of MerkleTreeTrait {
current_node = LegacyHash::hash(*proof_element, current_node);
}
},
Option::None(()) => {
break current_node;
},
Option::None(()) => { break current_node; },
};
}
}
Expand Down
36 changes: 11 additions & 25 deletions src/options.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// – first generating FutureOption, then generating everything from Pragma data

mod Options {
use governance::contract::IGovernance;
use traits::{Into, TryInto};
use array::{ArrayTrait, SpanTrait};
use option::OptionTrait;
Expand All @@ -26,6 +27,7 @@ mod Options {
use governance::contract::Governance;
use governance::types::OptionType;
use governance::traits::Math64x61_;
use governance::contract::Governance::proposal_initializer_runContractMemberStateTrait;

// 2**61 = 2305843009213693952
const VOLATILITY_28: Math64x61_ = consteval_int!(28 * 2305843009213693952);
Expand Down Expand Up @@ -73,7 +75,7 @@ mod Options {
// TODO use block hash from block_hash syscall as salt // actually doable with the new syscall
let governance_address = get_contract_address();
let state = Governance::unsafe_new_contract_state();
let amm_address = amm_address::InternalContractStateTrait::read(@state.amm_address);
let amm_address = state.get_amm_address();
let proxy_class: felt252 =
0x00eafb0413e759430def79539db681f8a4eb98cf4196fe457077d694c6aeeb82;
let opt_class: felt252 = 0x5ce3a80daeb5b7a766df9b41ca8d9e52b6b0a045a0d2ced72f43d4dd2f93b10;
Expand All @@ -84,9 +86,7 @@ mod Options {
proxy_class, opt_class, governance_address, amm_address, salt, option
);
},
Option::None(()) => {
break ();
},
Option::None(()) => { break (); },
};
}
}
Expand Down Expand Up @@ -131,9 +131,7 @@ mod Options {
proxy_class_hash, opt_class_hash, custom_salt
);

IOptionTokenDispatcher {
contract_address: optoken_long_addr
}
IOptionTokenDispatcher { contract_address: optoken_long_addr }
.initializer(
o.name_long,
'C-OPT',
Expand All @@ -147,9 +145,7 @@ mod Options {
TRADE_SIDE_LONG
);

IAMMDispatcher {
contract_address: amm_address
}
IAMMDispatcher { contract_address: amm_address }
.add_option(
TRADE_SIDE_LONG,
o.maturity,
Expand All @@ -166,9 +162,7 @@ mod Options {
proxy_class_hash, opt_class_hash, custom_salt + 1
);

IOptionTokenDispatcher {
contract_address: optoken_short_addr
}
IOptionTokenDispatcher { contract_address: optoken_short_addr }
.initializer(
o.name_short,
'C-OPT',
Expand All @@ -182,9 +176,7 @@ mod Options {
TRADE_SIDE_SHORT
);

IAMMDispatcher {
contract_address: amm_address
}
IAMMDispatcher { contract_address: amm_address }
.add_option(
TRADE_SIDE_SHORT,
o.maturity,
Expand Down Expand Up @@ -213,15 +205,9 @@ mod Options {

fn run_add_0911_1611_options() {
let mut state = Governance::unsafe_new_contract_state();
assert(
!proposal_initializer_run::InternalContractStateTrait::read(
@state.proposal_initializer_run, 36
),
'prop36 initializer called again'
);
proposal_initializer_run::InternalContractStateTrait::write(
ref state.proposal_initializer_run, 36, true
);
assert(!state.proposal_initializer_run.read(36), 'prop already initialized');

state.proposal_initializer_run.write(36, true);

add_0911_options();
add_1611_options();
Expand Down
Loading

0 comments on commit ab60119

Please sign in to comment.