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 authority #70

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
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
1 change: 1 addition & 0 deletions Scarb.lock
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ dependencies = [
"onchain_id_starknet",
"openzeppelin_access",
"openzeppelin_token",
"openzeppelin_upgrades",
"registry",
"roles",
"snforge_std",
Expand Down
14 changes: 11 additions & 3 deletions crates/compliance/src/modular_compliance.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ pub mod ModularCompliance {
modules: StorageArrayContractAddress,
/// Mapping of module binding status
module_bound: Map<ContractAddress, bool>,
implementation_authority: ContractAddress,
#[substorage(v0)]
upgrades: UpgradeableComponent::Storage,
#[substorage(v0)]
Expand Down Expand Up @@ -96,6 +97,7 @@ pub mod ModularCompliance {
pub const ZERO_ADDRESS: felt252 = 'Zero address';
pub const NO_VALUE_TRANSFER: felt252 = 'No value transfer';
pub const ONLY_BOUND_TOKEN: felt252 = 'Only token bound can call';
pub const CALLER_IS_NOT_IMPLEMENTATION_AUTHORITY: felt252 = 'Caller is not IA';
}

#[abi(embed_v0)]
Expand All @@ -108,17 +110,23 @@ pub mod ModularCompliance {
///
/// # Requirements
///
/// - This function can only be called by the owner.
/// - This function can only be called by the implementation authority.
/// - The `ClassHash` should already have been declared.
fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {
self.ownable.assert_only_owner();
assert(
self.implementation_authority.read() == starknet::get_caller_address(),
Errors::CALLER_IS_NOT_IMPLEMENTATION_AUTHORITY,
);
self.upgrades.upgrade(new_class_hash);
}
}

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

#[abi(embed_v0)]
Expand Down
7 changes: 6 additions & 1 deletion crates/compliance/tests/modular_compliance_test.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,12 @@ pub struct Setup {
pub fn setup() -> Setup {
let modular_compliance_contract = declare("ModularCompliance").unwrap().contract_class();
let (mc_address, _) = modular_compliance_contract
.deploy(@array![starknet::get_contract_address().into()])
.deploy(
@array![
starknet::contract_address_const::<'IMPLEMENTATION_AUTHORITY'>().into(),
starknet::get_contract_address().into(),
],
)
.unwrap();

Setup {
Expand Down
2 changes: 2 additions & 0 deletions crates/factory/Scarb.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ edition = "2024_07"
starknet.workspace = true
openzeppelin_access.workspace = true
openzeppelin_token.workspace = true
openzeppelin_upgrades.workspace = true
roles = { path = "../roles"}
compliance = { path = "../compliance"}
registry = { path = "../registry"}
Expand All @@ -19,6 +20,7 @@ snforge_std.workspace = true
[[target.starknet-contract]]
sierra = true
build-external-contracts = ["onchain_id_starknet::*", "registry::*", "roles::*", "compliance::*", "token::*"]
allowed-libfuncs-list.name = "all"

[tool]
fmt.workspace = true
Expand Down
62 changes: 62 additions & 0 deletions crates/factory/src/iimplementation_authority.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
use core::starknet::storage_access::StorePacking;
use starknet::{ClassHash, ContractAddress};

#[derive(Drop, Copy, Serde, PartialEq)]
pub struct Version {
pub major: u8,
pub minor: u8,
pub patch: u8,
}

const SHIFT_8: u32 = 0x100;
const SHIFT_16: u32 = 0x10000;
const MASK_8: u32 = 0xff;

pub impl VersionStorePacking of StorePacking<Version, u32> {
fn pack(value: Version) -> u32 {
value.major.into() + (value.minor.into() * SHIFT_8) + (value.patch.into() * SHIFT_16)
}

fn unpack(value: u32) -> Version {
let major = value & MASK_8;
let minor = (value / SHIFT_8) & MASK_8;
let patch = value / SHIFT_16;

Version {
major: major.try_into().unwrap(),
minor: minor.try_into().unwrap(),
patch: patch.try_into().unwrap(),
}
}
}

#[derive(Drop, Copy, Serde, starknet::Store)]
pub struct TREXImplementations {
pub token_implementation: ClassHash,
pub ctr_implementation: ClassHash,
pub ir_implementation: ClassHash,
pub irs_implementation: ClassHash,
pub tir_implementation: ClassHash,
pub mc_implementation: ClassHash,
}

#[starknet::interface]
pub trait IImplementationAuthority<TContractState> {
fn add_trex_version(
ref self: TContractState, version: Version, implementations: TREXImplementations,
);
fn add_and_use_trex_version(
ref self: TContractState, version: Version, implementations: TREXImplementations,
);
fn use_trex_version(ref self: TContractState, version: Version);
fn upgrade_trex_suite(ref self: TContractState, token: ContractAddress, version: Version);
fn get_current_version(self: @TContractState) -> Version;
fn get_implementations(self: @TContractState, version: Version) -> TREXImplementations;
fn get_current_implementations(self: @TContractState) -> TREXImplementations;
fn get_token_implementation(self: @TContractState) -> ClassHash;
fn get_ctr_implementation(self: @TContractState) -> ClassHash;
fn get_ir_implementation(self: @TContractState) -> ClassHash;
fn get_irs_implementation(self: @TContractState) -> ClassHash;
fn get_tir_implementation(self: @TContractState) -> ClassHash;
fn get_mc_implementation(self: @TContractState) -> ClassHash;
}
Loading
Loading