Skip to content

Commit

Permalink
Merge pull request #4 from CarmineOptions/add-investor-voting-power-r…
Browse files Browse the repository at this point in the history
…estriction

Adjust voting power calculation
  • Loading branch information
tensojka authored Jun 27, 2024
2 parents 46bd5d2 + 333bd9a commit e05a175
Show file tree
Hide file tree
Showing 10 changed files with 145 additions and 102 deletions.
4 changes: 2 additions & 2 deletions Scarb.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ sort-module-level-items = true

[[tool.snforge.fork]]
name = "MAINNET"
url = "http://34.22.208.73:6060/v0_7"
url = "http://178.32.172.148:6060/v0_7"
block_id.tag = "Latest"

[[tool.snforge.fork]]
name = "SEPOLIA"
url = "http://34.22.208.73:6062/v0_7"
url = "http://178.32.172.148:6062/v0_7"
block_id.tag = "Latest"
1 change: 1 addition & 0 deletions src/carm.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ mod CRMToken {

self.erc20.initializer(name, symbol);
self.erc20._mint(recipient, fixed_supply);
self.ownable.initializer(owner);
}

#[abi(embed_v0)]
Expand Down
2 changes: 1 addition & 1 deletion src/constants.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@ pub const AMM_CLASS_HASH: felt252 =
pub const OPTION_TOKEN_CLASS_HASH: felt252 =
0x07fc0b6ecc96a698cdac8c4ae447816d73bffdd9603faacffc0a8047149d02ed;

pub const UNLOCK_DATE: u64 = 1720915199; // Sat Jul 13 2024 23:59:59 GMT+0000
pub const UNLOCK_DATE: u64 = 1719838800; // Mon Jul 01 2024 13:00:00 GMT+0000
44 changes: 7 additions & 37 deletions src/contract.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ pub mod Governance {
use konoha::airdrop::airdrop as airdrop_component;
use konoha::types::{BlockNumber, VoteStatus, ContractType, PropDetails, CustomProposalConfig};

use starknet::syscalls::deploy_syscall;

use starknet::{ContractAddress, get_contract_address, ClassHash};


Expand Down Expand Up @@ -66,45 +68,13 @@ pub mod Governance {
StakingEvent: staking_component::Event,
}

use starknet::syscalls::deploy_syscall;

#[constructor]
fn constructor(ref self: ContractState,
fn constructor(
ref self: ContractState,
voting_token_class: ClassHash,
floating_token_class: ClassHash,
recipient: ContractAddress) {
// This is not used in production on mainnet, because the governance token is already deployed (and distributed).

let governance_address = get_contract_address();

let mut voting_token_calldata: Array<felt252> = ArrayTrait::new();
voting_token_calldata.append(governance_address.into());
let (voting_token_address, _) = deploy_syscall(
voting_token_class, 42, voting_token_calldata.span(), true
)
.unwrap();
self.governance_token_address.write(voting_token_address);

let mut floating_token_calldata: Array<felt252> = ArrayTrait::new();
floating_token_calldata.append(10000000000000000000); // 10**19, 10 tokens overall
floating_token_calldata.append(0); // high for u256 supply
floating_token_calldata.append(recipient.into());
floating_token_calldata.append(governance_address.into());
let (floating_token_address, _) = deploy_syscall(
floating_token_class, 42, floating_token_calldata.span(), true
)
.unwrap();

let staking = IStakingDispatcher { contract_address: governance_address };
staking.set_floating_token_address(floating_token_address);
let ONE_MONTH: u64 = 2629743; // 30.44 days
let THREE_MONTHS = ONE_MONTH * 3;
let SIX_MONTHS = ONE_MONTH * 6;
let ONE_YEAR: u64 = 31536000; // 365 days
staking.set_curve_point(ONE_MONTH, 100);
staking.set_curve_point(THREE_MONTHS, 120);
staking.set_curve_point(SIX_MONTHS, 160);
staking.set_curve_point(ONE_YEAR, 250);
recipient: ContractAddress
) { // This is not used in production on mainnet, because the governance token is already deployed (and distributed).
}

#[abi(embed_v0)]
Expand Down Expand Up @@ -132,7 +102,7 @@ pub mod Governance {
target: self.amm_address.read().into(),
selector: selector!("upgrade"),
library_call: false
}; // TODO test
};
let upgrade_govtoken = CustomProposalConfig {
target: self.governance_token_address.read().into(),
selector: selector!("upgrade"),
Expand Down
2 changes: 1 addition & 1 deletion src/proposals.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -416,7 +416,7 @@ pub(crate) mod proposals {
let current_timestamp: u64 = get_block_timestamp();

if current_timestamp <= end_timestamp {
return self.check_proposal_passed_express(prop_id).into();
return 0;
}

let gov_token_addr = get_governance_token_address_self();
Expand Down
71 changes: 59 additions & 12 deletions src/staking.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -127,12 +127,32 @@ pub(crate) mod staking {
let arr = array![
0x0583a9d956d65628f806386ab5b12dccd74236a3c6b930ded9cf3c54efc722a1,
0x06717eaf502baac2b6b2c6ee3ac39b34a52e726a73905ed586e757158270a0af,
0x058d2ddce3e4387dc0da7e45c291cb436bb809e00a4c132bcc5758e4574f55c7,
0x05e61dfb8a9863e446981e804a203a7ad3a2d15495c85b79cfd053ec63e9bfb3,
0x04379c63976feaca8019db2c08f7af8e976b11aef7eda9dfe2ef604e76fc99d2,
0x0011d341c6e841426448ff39aa443a6dbb428914e05ba2259463c18308b86233,
0x00d79a15d84f5820310db21f953a0fae92c95e25d93cb983cc0c27fc4c52273c,
0x03d1525605db970fa1724693404f5f64cba8af82ec4aab514e6ebd3dec4838ad,
0x06fd0529AC6d4515dA8E5f7B093e29ac0A546a42FB36C695c8f9D13c5f787f82,
0x04d2FE1Ff7c0181a4F473dCd982402D456385BAE3a0fc38C49C0A99A620d1abe,
0x062c290f0afa1ea2d6b6d11f6f8ffb8e626f796e13be1cf09b84b2edaa083472
0x062c290f0afa1ea2d6b6d11f6f8ffb8e626f796e13be1cf09b84b2edaa083472,
0x01714ab9a05b062e0c09cf635fd469ce664c914ef9d9ff2394928e31707ce9a6,
0x06c59d2244250f2540a2694472e3c31262e887ff02582ef864bf0e76c34e1298,
0x0528f064c43e2d6Ee73bCbfB725bAa293CD31Ea1f1861EA2F80Bc283Ea4Ad728,
0x05105649f42252f79109356e1c8765b7dcdb9bf4a6a68534e7fc962421c7efd2,
0x00777558f1c767126461540d1f10118981d30bd620707e99686bfc9f00ae66f0,
0x06e2c2a5da2e5478b1103d452486afba8378e91f32a124f0712f09edd3ccd923,
0x035e0845154423c485e5216f70496130079b5ddc8ac66e3e316184482788e2a0,
0x0244dda2c6581eb158db225992153c9d49e92c412424daeb83a773fa9822eeef, // team multisig
];
@arr.span()
}

#[inline(always)]
fn get_investor_addresses() -> @Span<felt252> {
let arr = array![
0x05a4523982b437aadd1b5109b6618c46f7b1c42f5f9e7de1a3b84091f87d411b,
0x056d761e1e5d1918dba05de02afdbd8de8da01a63147dce828c9b1fe9227077d, // investor multisig
];
@arr.span()
}
Expand All @@ -150,6 +170,19 @@ pub(crate) mod staking {
}
}

fn is_investor(potential_investor_address: ContractAddress) -> bool {
let potential_address: felt252 = potential_investor_address.into();
let mut investor_addresses = *get_investor_addresses();
loop {
match investor_addresses.pop_front() {
Option::Some(addr) => { if (*addr == potential_address) {
break true;
} },
Option::None(_) => { break false; }
}
}
}

#[embeddable_as(StakingImpl)]
impl Staking<
TContractState, +HasComponent<TContractState>,
Expand Down Expand Up @@ -249,7 +282,7 @@ pub(crate) mod staking {

fn unstake_airdrop(ref self: ComponentState<TContractState>) {
let caller = get_caller_address();
if (is_team(caller)) {
if (is_team(caller) || is_investor(caller)) {
assert(get_block_timestamp() > UNLOCK_DATE, 'tokens not yet unlocked');
}

Expand Down Expand Up @@ -301,9 +334,9 @@ pub(crate) mod staking {
let curr = self.floating_token_address.read();
assert(curr.into() == 0, 'floating token already init');
let default_address: ContractAddress =
0x71cc3fbda6eb62d60c57c84eb995338fcb74a31dfb58e64f88185d1ac8ae8b8
0x051c4b1fe3bf6774b87ad0b15ef5d1472759076e42944fff9b9f641ff13e5bbe
.try_into()
.unwrap(); // TODO fix
.unwrap();
self.floating_token_address.write(default_address);
}

Expand Down Expand Up @@ -339,7 +372,9 @@ pub(crate) mod staking {
self: @ComponentState<TContractState>, address: ContractAddress
) -> u128 {
let nonadjusted_voting_power = self.get_total_voting_power(address);
if (!is_team(address)) {
let is_investor = is_investor(address);
let is_team = is_team(address);
if (!is_investor && !is_team) {
return nonadjusted_voting_power;
}
let total_supply: u128 = IERC20Dispatcher {
Expand All @@ -348,12 +383,18 @@ pub(crate) mod staking {
.total_supply()
.try_into()
.unwrap();
let total_team = self.get_total_team_voting_power(); // 7
let max_team_supply = (total_supply-total_team) / 2; // (8-7) / 2 = 0.5
if (total_team < max_team_supply) {
let total_team = self.get_total_group_voting_power(false);
let total_investor = self.get_total_group_voting_power(true);
let max_group_supply = ((total_supply - total_team) - total_investor) / 2;
let total_group = if is_investor {
total_investor
} else {
total_team
};
if (total_group < max_group_supply) {
return nonadjusted_voting_power;
}
let adj_factor = (TWO_POW_32 * max_team_supply) / total_team;
let adj_factor = (TWO_POW_32 * max_group_supply) / total_group;
(adj_factor * nonadjusted_voting_power) / TWO_POW_32
}
}
Expand Down Expand Up @@ -396,11 +437,17 @@ pub(crate) mod staking {
}
}

fn get_total_team_voting_power(self: @ComponentState<TContractState>) -> u128 {
fn get_total_group_voting_power(
self: @ComponentState<TContractState>, investors: bool
) -> u128 {
let mut total: u128 = 0;
let mut team_addresses = *get_team_addresses();
let mut addresses = if investors {
*get_investor_addresses()
} else {
*get_team_addresses()
};
loop {
match team_addresses.pop_front() {
match addresses.pop_front() {
Option::Some(addr) => {
total += self.get_total_voting_power((*addr).try_into().unwrap());
},
Expand Down
22 changes: 22 additions & 0 deletions src/traits.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -267,3 +267,25 @@ pub trait IOptionToken<TState> {
fn maturity(self: @TState) -> u64;
fn side(self: @TState) -> u8;
}

#[starknet::interface]
pub trait IERC20<TContractState> {
fn name(self: @TContractState) -> felt252;
fn symbol(self: @TContractState) -> felt252;
fn decimals(self: @TContractState) -> u8;
fn totalSupply(self: @TContractState) -> u256;
fn total_supply(self: @TContractState) -> u256;
fn balanceOf(self: @TContractState, account: ContractAddress) -> u256;
fn balance_of(self: @TContractState, account: ContractAddress) -> u256;
fn allowance(self: @TContractState, owner: ContractAddress, spender: ContractAddress) -> u256;
fn transfer(ref self: TContractState, recipient: ContractAddress, amount: u256) -> bool;
fn transferFrom(
ref self: TContractState, sender: ContractAddress, recipient: ContractAddress, amount: u256
) -> bool;
fn transfer_from(
ref self: TContractState, sender: ContractAddress, recipient: ContractAddress, amount: u256
) -> bool;
fn approve(ref self: TContractState, spender: ContractAddress, amount: u256) -> bool;
fn mint(ref self: TContractState, recipient: ContractAddress, amount: u256);
fn burn(ref self: TContractState, recipient: ContractAddress, amount: u256);
}
10 changes: 5 additions & 5 deletions src/vecarm.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ pub trait IVeCRM<TContractState> {

#[starknet::contract]
pub mod VeCRM {
use konoha::traits::IERC20;
use amm_governance::traits::IERC20;
use openzeppelin::access::ownable::OwnableComponent;
use openzeppelin::access::ownable::interface::IOwnableTwoStep;
use openzeppelin::access::ownable::ownable::OwnableComponent::InternalTrait as OwnableInternalTrait;
Expand Down Expand Up @@ -73,12 +73,12 @@ pub mod VeCRM {
#[abi(embed_v0)]
impl VotingToken of IERC20<ContractState> {
// READ
fn name(self: @ContractState) -> ByteArray {
ERC20MetadataImpl::name(self)
fn name(self: @ContractState) -> felt252 {
'vote escrowed Carmine token'
}

fn symbol(self: @ContractState) -> ByteArray {
ERC20MetadataImpl::symbol(self)
fn symbol(self: @ContractState) -> felt252 {
'veCRM'
}

fn decimals(self: @ContractState) -> u8 {
Expand Down
Loading

0 comments on commit e05a175

Please sign in to comment.