Skip to content

Commit

Permalink
Add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
tensojka committed Feb 6, 2024
1 parent a82be39 commit 2d1514e
Show file tree
Hide file tree
Showing 13 changed files with 358 additions and 10 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 2.4.0",
"postCreateCommand": "curl --proto '=https' --tlsv1.2 -sSf https://docs.swmansion.com/scarb/install.sh | bash -s -- -v 2.4.1",
"customizations": {
"vscode": {
"extensions": [
Expand Down
6 changes: 6 additions & 0 deletions Scarb.lock
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,15 @@ name = "governance"
version = "0.2.0"
dependencies = [
"cubit",
"openzeppelin",
"snforge_std",
]

[[package]]
name = "openzeppelin"
version = "0.8.1"
source = "git+https://github.com/OpenZeppelin/cairo-contracts.git?tag=v0.8.1#eb2d32161e2fe4df54feb08e4dcdd154fa30fd0a"

[[package]]
name = "snforge_std"
version = "0.14.0"
Expand Down
10 changes: 7 additions & 3 deletions Scarb.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,27 @@
name = "governance"
description = "A flexible monolithic governance contract, developed for use with Carmine Options AMM"
version = "0.2.0"
cairo-version = "2.4.0"
cairo-version = "2.4.1"

# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest

[dependencies]
cubit = { git = "https://github.com/akhercha/cubit.git", branch = "chore/cairo_upgrade" }
openzeppelin = { git = "https://github.com/OpenZeppelin/cairo-contracts.git", tag = "v0.8.1" }
starknet = ">=1.3.0"
snforge_std = { git = "https://github.com/foundry-rs/starknet-foundry.git", commit = "a1caebbfffd00e612c09ed89da006f6c48a92fd9"}

[[target.starknet-contract]]

[scripts]
test = "snforge test"

[[tool.snforge.fork]]
name = "MAINNET"
url = "http://34.22.208.73:6060/"
url = "https://free-rpc.nethermind.io/mainnet-juno"
block_id.tag = "Latest"

[[tool.snforge.fork]]
name = "GOERLI"
url = "https://limited-rpc.nethermind.io/goerli-juno"
block_id.tag = "Latest"
block_id.tag = "Latest"
3 changes: 3 additions & 0 deletions src/contract.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ trait IGovernance<TContractState> {

// in component

// VESTING

// in component
// OPTIONS / ONE-OFF
}

Expand Down
106 changes: 106 additions & 0 deletions src/govtoken.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
use starknet::{ContractAddress, ClassHash};

#[starknet::interface]
trait IveCARM<TContractState> {
fn name(self: @TContractState) -> felt252;
fn symbol(self: @TContractState) -> felt252;
fn decimals(self: @TContractState) -> u8;
fn mint(ref self: TContractState, recipient: ContractAddress, amount: u256);
fn burn(ref self: TContractState, account: ContractAddress, amount: u256);
fn upgrade(ref self: TContractState, new_class_hash: ClassHash);
}

#[starknet::contract]
mod MyToken {
use openzeppelin::access::ownable::ownable::OwnableComponent::InternalTrait;
use starknet::ContractAddress;
use starknet::ClassHash;
use openzeppelin::token::erc20::ERC20Component;
use openzeppelin::access::ownable::ownable::OwnableComponent;

component!(path: ERC20Component, storage: erc20, event: ERC20Event);
component!(path: OwnableComponent, storage: ownable, event: OwnableEvent);

// ERC20 Component
#[abi(embed_v0)]
impl ERC20Impl = ERC20Component::ERC20Impl<ContractState>;

#[abi(embed_v0)]
impl SafeAllowanceImpl = ERC20Component::SafeAllowanceImpl<ContractState>;

#[abi(embed_v0)]
impl ERC20CamelOnlyImpl = ERC20Component::ERC20CamelOnlyImpl<ContractState>;

impl ERC20InternalImpl = ERC20Component::InternalImpl<ContractState>;

impl OwnableInternalImpl = OwnableComponent::InternalImpl<ContractState>;

// Ownable Component
#[abi(embed_v0)]
impl OwnableImpl = OwnableComponent::OwnableImpl<ContractState>;


#[storage]
struct Storage {
#[substorage(v0)]
erc20: ERC20Component::Storage,
#[substorage(v0)]
ownable: OwnableComponent::Storage,
}

#[event]
#[derive(Drop, starknet::Event)]
enum Event {
Upgraded: Upgraded,
// #[flat]
ERC20Event: ERC20Component::Event,
OwnableEvent: OwnableComponent::Event
}

#[derive(Drop, starknet::Event)]
struct Upgraded {
class_hash: ClassHash
}


#[constructor]
fn constructor(ref self: ContractState, owner: ContractAddress) {
self.ownable.initializer(owner);
}

#[external(v0)]
#[generate_trait]
impl VeCARMImpl of IveCARM {
// Did not import Erc20MetaData, so we can change decimals
// so we need to define name, symbol and decimals ourselves
fn name(self: @ContractState) -> felt252 {
'vote escrowed Carmine Token'
}

fn symbol(self: @ContractState) -> felt252 {
'veCARM'
}

fn decimals(self: @ContractState) -> u8 {
18
}

fn mint(ref self: ContractState, recipient: ContractAddress, amount: u256) {
self.ownable.assert_only_owner();
self.erc20._mint(recipient, amount);
}

fn burn(ref self: ContractState, account: ContractAddress, amount: u256) {
self.ownable.assert_only_owner();
self.erc20._burn(account, amount);
}

fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {
self.ownable.assert_only_owner();
assert(!new_class_hash.is_zero(), 'Class hash cannot be zero');
starknet::replace_class_syscall(new_class_hash).unwrap();
self.emit(Upgraded { class_hash: new_class_hash });
}
}
}

1 change: 1 addition & 0 deletions src/lib.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ mod traits;
mod types;
mod upgrades;
mod vesting;
mod govtoken; // if I put this in tests/ , I seem unable to use declare('MyToken')
2 changes: 0 additions & 2 deletions src/options.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ mod Options {

use cubit::f128::types::{Fixed, FixedTrait};

use governance::contract::Governance::{amm_address, proposal_initializer_run};
use governance::constants::{
OPTION_CALL, OPTION_PUT, TRADE_SIDE_LONG, TRADE_SIDE_SHORT, OPTION_TOKEN_CLASS_HASH
};
Expand All @@ -30,7 +29,6 @@ mod Options {
use governance::types::OptionSide;
use governance::contract::Governance;
use governance::types::OptionType;
use governance::contract::Governance::proposal_initializer_runContractMemberStateTrait;

fn add_options(mut options: Span<FutureOption>) {
// TODO use block hash from block_hash syscall as salt // actually doable with the new syscall
Expand Down
115 changes: 115 additions & 0 deletions src/oz/access/ownable.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts for Cairo v0.8.0-beta.0 (access/ownable/ownable.cairo)

/// # Ownable Component
///
/// The Ownable component provides a basic access control mechanism, where
/// there is an account (an owner) that can be granted exclusive access to
/// specific functions.
///
/// The initial owner can be set by using the `initializer` function in
/// construction time. This can later be changed with `transfer_ownership`.
#[starknet::component]
mod OwnableComponent {
use carmine_protocol::oz::access::interface;
use starknet::ContractAddress;
use starknet::get_caller_address;

#[storage]
struct Storage {
Ownable_owner: ContractAddress
}

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

#[derive(Drop, starknet::Event)]
struct OwnershipTransferred {
previous_owner: ContractAddress,
new_owner: ContractAddress,
}

mod Errors {
const NOT_OWNER: felt252 = 'Caller is not the owner';
const ZERO_ADDRESS_CALLER: felt252 = 'Caller is the zero address';
const ZERO_ADDRESS_OWNER: felt252 = 'New owner is the zero address';
}

#[embeddable_as(OwnableImpl)]
impl Ownable<
TContractState, +HasComponent<TContractState>
> of interface::IOwnable<ComponentState<TContractState>> {
/// Returns the address of the current owner.
fn owner(self: @ComponentState<TContractState>) -> ContractAddress {
self.Ownable_owner.read()
}

/// Transfers ownership of the contract to a new address.
fn transfer_ownership(
ref self: ComponentState<TContractState>, new_owner: ContractAddress
) {
assert(!new_owner.is_zero(), Errors::ZERO_ADDRESS_OWNER);
self.assert_only_owner();
self._transfer_ownership(new_owner);
}

/// Leaves the contract without owner. It will not be possible to call `assert_only_owner`
/// functions anymore. Can only be called by the current owner.
fn renounce_ownership(ref self: ComponentState<TContractState>) {
self.assert_only_owner();
self._transfer_ownership(Zeroable::zero());
}
}

/// Adds camelCase support for `IOwnable`.
#[embeddable_as(OwnableCamelOnlyImpl)]
impl OwnableCamelOnly<
TContractState, +HasComponent<TContractState>
> of interface::IOwnableCamelOnly<ComponentState<TContractState>> {
fn transferOwnership(ref self: ComponentState<TContractState>, newOwner: ContractAddress) {
self.transfer_ownership(newOwner);
}

fn renounceOwnership(ref self: ComponentState<TContractState>) {
self.renounce_ownership();
}
}

#[generate_trait]
impl InternalImpl<
TContractState, +HasComponent<TContractState>
> of InternalTrait<TContractState> {
/// Sets the contract's initial owner.
///
/// This function should be called at construction time.
fn initializer(ref self: ComponentState<TContractState>, owner: ContractAddress) {
self._transfer_ownership(owner);
}

/// Panics if called by any account other than the owner. Use this
/// to restrict access to certain functions to the owner.
fn assert_only_owner(self: @ComponentState<TContractState>) {
let owner: ContractAddress = self.Ownable_owner.read();
let caller: ContractAddress = get_caller_address();
assert(!caller.is_zero(), Errors::ZERO_ADDRESS_CALLER);
assert(caller == owner, Errors::NOT_OWNER);
}

/// Transfers ownership of the contract to a new address.
///
/// Internal function without access restriction.
fn _transfer_ownership(
ref self: ComponentState<TContractState>, new_owner: ContractAddress
) {
let previous_owner: ContractAddress = self.Ownable_owner.read();
self.Ownable_owner.write(new_owner);
self
.emit(
OwnershipTransferred { previous_owner: previous_owner, new_owner: new_owner }
);
}
}
}
6 changes: 3 additions & 3 deletions src/upgrades.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ mod Upgrades {
use starknet::ContractAddress;
use starknet::class_hash;
use governance::proposals::Proposals;
use governance::contract::Governance::{
proposal_applied, amm_address, governance_token_address, proposal_details
};
// use governance::contract::Governance::{
// proposal_applied, amm_address, governance_token_address, proposal_details
// };

use governance::types::PropDetails;
use governance::contract::Governance;
Expand Down
3 changes: 3 additions & 0 deletions src/vesting.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ mod vesting {
use governance::contract::IGovernance;
use starknet::get_block_timestamp;
use starknet::ContractAddress;
use starknet::{get_caller_address, get_contract_address};

use governance::contract::Governance;
use governance::contract::Governance::ContractState;
Expand Down Expand Up @@ -88,6 +89,7 @@ mod vesting {
grantee: ContractAddress,
amount: u128
) {
assert(get_caller_address() == get_contract_address(), 'not self-call');
self.milestone.write((vesting_timestamp, grantee), amount);
self
.emit(
Expand All @@ -105,6 +107,7 @@ mod vesting {
total_amount: u128,
grantee: ContractAddress
) {
assert(get_caller_address() == get_contract_address(), 'not self-call');
let mut i: u16 = 0;
let mut curr_timestamp = first_vest;
assert(increments_count > 1, 'increments_count <= 1');
Expand Down
2 changes: 1 addition & 1 deletion tests/add_options.cairo
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use tests::basic::submit_44_signal_proposals;
//use tests::basic::submit_44_signal_proposals;

use governance::traits::IAMM;
use governance::contract::IGovernanceDispatcher;
Expand Down
1 change: 1 addition & 0 deletions tests/lib.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
mod vesting;
Loading

0 comments on commit 2d1514e

Please sign in to comment.