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

Registry #702

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
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
2 changes: 1 addition & 1 deletion .tool-versions
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
scarb 2.7.0
starknet-foundry 0.18.0
starknet-foundry 0.27.0
nodejs v20.11.1
3 changes: 3 additions & 0 deletions Scarb.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
[workspace]
members = [
"packages/contracts/_deployment",
"packages/contracts/controller",
"packages/contracts/resolver",
"packages/contracts/registry",
]

[workspace.package]
Expand All @@ -15,5 +17,6 @@ alexandria_encoding = { git = "https://github.com/piniom/quaireaux.git", rev = "
alexandria_merkle_tree = { git = "https://github.com/piniom/quaireaux.git", rev = "b51ccc3" }
alexandria_data_structures = { git = "https://github.com/piniom/quaireaux.git", rev = "b51ccc3" }
snforge_std = { git = "https://github.com/foundry-rs/starknet-foundry.git", tag = "v0.27.0" }
sncast_std = { git = "https://github.com/foundry-rs/starknet-foundry.git", tag = "v0.27.0" }
openzeppelin = { git = "https://github.com/OpenZeppelin/cairo-contracts.git", rev = "a13bae3" }
argent = { git = "https://github.com/cartridge-gg/argent-contracts-starknet.git", rev = "daa8200" }
4 changes: 4 additions & 0 deletions packages/contracts/_accounts/dev.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export STARKNET_RPC="http://localhost:8001/x/starknet/sepolia"

export REGISTRY_ADDRESS=0x7b3e2237ea5db4d6d92eb2d5659c3225f56fb3b20ace75bd8c528b6346cfb9b
export RESOLVER_ADDRESS=0x9c6b9be3c25084f720ad9a8a75690a2f067633c5c5ef39a0e5257e7bf9463d
14 changes: 14 additions & 0 deletions packages/contracts/_accounts/dev_admin.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"version": 1,
"variant": {
"type": "open_zeppelin",
"version": 1,
"public_key": "0x41b6dab3967eaaee4cfecdc950079aee353afd96bcf0628bf84fc64a43c3021",
"legacy": false
},
"deployment": {
"status": "deployed",
"class_hash": "0x5400e90f7e0ae78bd02c77cd75527280470e2fe19c54970dd79dc37a9d3645c",
"address": "0x41b6dab3967eaaee4cfecdc950079aee353afd96bcf0628bf84fc64a43c3021"
}
}
8 changes: 8 additions & 0 deletions packages/contracts/_accounts/dev_admin.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@

source $(dirname "$0")/dev.sh

export STARKNET_ACCOUNT="$(dirname "$0")/dev_admin.json"
export STARKNET_KEYSTORE="$(dirname "$0")/dev_admin_keystore.json"
export ACCOUNT_PASS="admin"

echo $STARKNET_KEYSTORE
1 change: 1 addition & 0 deletions packages/contracts/_accounts/dev_admin_keystore.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"crypto":{"cipher":"aes-128-ctr","cipherparams":{"iv":"735fc1b003a1d2ff5ec6710a3715d8f2"},"ciphertext":"7337616c1f8ba9752749a29a0be463f25c1be24127322966ad3378ecc6162d63","kdf":"scrypt","kdfparams":{"dklen":32,"n":8192,"p":1,"r":8,"salt":"7643e0178a1b0aae77c520f3f0f422a3c6a152e03111b8d010653d33f901fefd"},"mac":"2b095670eb3edf2bf2b9806a98802792eacff527c1582af3f689c39089cc34e3"},"id":"a34ecfec-d2a3-45f5-889b-0053196487f4","version":3}
14 changes: 14 additions & 0 deletions packages/contracts/_accounts/dev_executor.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"version": 1,
"variant": {
"type": "open_zeppelin",
"version": 1,
"public_key": "0x657e5f424dc6dee0c5a305361ea21e93781fea133d83efa410b771b7f92b",
"legacy": false
},
"deployment": {
"status": "deployed",
"class_hash": "0x5400e90f7e0ae78bd02c77cd75527280470e2fe19c54970dd79dc37a9d3645c",
"address": "0x657e5f424dc6dee0c5a305361ea21e93781fea133d83efa410b771b7f92b"
}
}
6 changes: 6 additions & 0 deletions packages/contracts/_accounts/dev_executor.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
source $(dirname "$0")/dev.sh

export STARKNET_ACCOUNT="$(dirname "$0")/dev_executor.json"
export STARKNET_KEYSTORE="$(dirname "$0")/dev_executor_keystore.json"
export ACCOUNT_PASS="executor"

1 change: 1 addition & 0 deletions packages/contracts/_accounts/dev_executor_keystore.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"crypto":{"cipher":"aes-128-ctr","cipherparams":{"iv":"04c4cb99e387e4b31ddb1bd9a44fd921"},"ciphertext":"6408c057fcfcdf3042e9edbeb9c20fe05443be20a5806d3b2815a10371854504","kdf":"scrypt","kdfparams":{"dklen":32,"n":8192,"p":1,"r":8,"salt":"b25227d3c5a8b7f7e076e0c4667531ce38e7c422a489217b770b57f828b42a71"},"mac":"6bcefb8b41cc3e54daa8dfc877b0eff25883efbd3380250327d5c090313d7e5b"},"id":"a6504023-e3ab-435a-86d8-0edc5cf93ae0","version":3}
14 changes: 14 additions & 0 deletions packages/contracts/_accounts/print-env.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@

#!/bin/bash
set -euo pipefail
pushd $(dirname "$0")/..

echo "---------------------------------"
echo $STARKNET_RPC
echo $STARKNET_ACCOUNT
echo $STARKNET_KEYSTORE
echo $ACCOUNT_PASS
echo "---------------------------------"
echo "REGISTRY ADDRESS : " $REGISTRY_ADDRESS
echo "RESOLVER ADDRESS : " $RESOLVER_ADDRESS
echo "---------------------------------"
22 changes: 22 additions & 0 deletions packages/contracts/_deployment/Scarb.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
[package]
name = "_deployment"
version = "0.1.0"


[dependencies]
starknet.workspace = true
sncast_std.workspace = true

registry = { path = "../registry"}
resolver = { path = "../resolver"}

[script]
setup = "sncast script run --package _deployment setup "



[[target.starknet-contract]]
build-external-contracts = [
"registry::registry::Registry",
"resolver::resolver::ControllerResolverDelegation",
]
11 changes: 11 additions & 0 deletions packages/contracts/_deployment/commands.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@

# in dev remove artifacts before redeploying

# from /
sncast -p dev_admin script run --package _deployment setup

# from /packages/contracts

source ./_accounts/dev_admin.sh && ./_accounts/print-env.sh
source ./_accounts/dev_executor.sh && ./_accounts/print-env.sh

2 changes: 2 additions & 0 deletions packages/contracts/_deployment/src/lib.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pub mod utils;
pub mod setup;
26 changes: 26 additions & 0 deletions packages/contracts/_deployment/src/setup.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@

use sncast_std::{
declare, deploy, invoke, call, DeclareResult, DeployResult, InvokeResult, CallResult, get_nonce,
FeeSettings, EthFeeSettings
};

use starknet::{ContractAddress, ClassHash};

pub const DEV_ADMIN: felt252 = 0x41b6dab3967eaaee4cfecdc950079aee353afd96bcf0628bf84fc64a43c3021;
pub const DEV_EXECUTOR: felt252 = 0x657e5f424dc6dee0c5a305361ea21e93781fea133d83efa410b771b7f92b;

use super::utils::{declare_contract, deploy_contract};

pub fn main() {

let registry_class_hash = declare_contract("Registry");
let resolver_class_hash = declare_contract("ControllerResolverDelegation");

let registry_calldata: Array<felt252> = array![DEV_ADMIN, 0x1, DEV_EXECUTOR];
let registry_address = deploy_contract("- Registry -", registry_class_hash, registry_calldata);

let resolver_calldata: Array<felt252> = array![DEV_ADMIN, registry_address.into()];
let _resolver_address = deploy_contract("- Resolver -",resolver_class_hash, resolver_calldata);

}

45 changes: 45 additions & 0 deletions packages/contracts/_deployment/src/utils.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@

use sncast_std::{
declare, deploy, invoke, call, DeclareResult, DeployResult, InvokeResult, CallResult, get_nonce,
FeeSettings, EthFeeSettings
};

use starknet::{ContractAddress, ClassHash};

use debug::PrintTrait;


pub fn declare_contract(name: ByteArray) -> ClassHash {
println!("declaring: {}", name);

let declare_nonce = get_nonce('pending');
let declare_result = declare(
name,
FeeSettings::Eth(EthFeeSettings { max_fee: Option::None }),
Option::Some(declare_nonce)
)
.expect('declare_contract failed');

// declare_result.class_hash.print();

declare_result.class_hash
}

pub fn deploy_contract(name: ByteArray, class_hash: ClassHash, calldata: Array<felt252>) -> ContractAddress {
println!("deploying: {}", name);

let deploy_nonce = get_nonce('pending');
let deploy_result = deploy(
class_hash,
calldata,
Option::None,
true,
FeeSettings::Eth(EthFeeSettings { max_fee: Option::None }),
Option::Some(deploy_nonce)
)
.expect('deploy_contract failed');

deploy_result.contract_address.print();

deploy_result.contract_address
}
17 changes: 17 additions & 0 deletions packages/contracts/registry/Scarb.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[package]
name = "registry"
version = "0.1.0"

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

[dependencies]
starknet.workspace = true
openzeppelin.workspace = true


[[target.starknet-contract]]
sierra = true
casm = true
casm-add-pythonic-hints = true

[lib]
4 changes: 4 additions & 0 deletions packages/contracts/registry/src/lib.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
mod registry;
mod registry_component;

mod roles;
68 changes: 68 additions & 0 deletions packages/contracts/registry/src/registry.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// SPDX-License-Identifier: MIT
// Compatible with OpenZeppelin Contracts for Cairo ^0.16.0

#[starknet::contract]
mod Registry {
use openzeppelin::access::accesscontrol::AccessControlComponent;
use openzeppelin::introspection::src5::SRC5Component;
use openzeppelin::upgrades::UpgradeableComponent;
use openzeppelin::upgrades::interface::IUpgradeable;
use starknet::ClassHash;
use starknet::ContractAddress;
use registry::roles::{ADMIN_ROLE, EXECUTOR_ROLE};

component!(path: AccessControlComponent, storage: accesscontrol, event: AccessControlEvent);
component!(path: SRC5Component, storage: src5, event: SRC5Event);
component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);

#[abi(embed_v0)]
impl AccessControlMixinImpl =
AccessControlComponent::AccessControlMixinImpl<ContractState>;

impl AccessControlInternalImpl = AccessControlComponent::InternalImpl<ContractState>;
impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl<ContractState>;

#[storage]
struct Storage {
#[substorage(v0)]
accesscontrol: AccessControlComponent::Storage,
#[substorage(v0)]
src5: SRC5Component::Storage,
#[substorage(v0)]
upgradeable: UpgradeableComponent::Storage,
}

#[event]
#[derive(Drop, starknet::Event)]
enum Event {
#[flat]
AccessControlEvent: AccessControlComponent::Event,
#[flat]
SRC5Event: SRC5Component::Event,
#[flat]
UpgradeableEvent: UpgradeableComponent::Event,
}

#[constructor]
fn constructor(
ref self: ContractState, admin: ContractAddress, mut executors: Span<ContractAddress>,
) {
self.accesscontrol.initializer();

self.accesscontrol._grant_role(ADMIN_ROLE, admin);

self.accesscontrol.set_role_admin(EXECUTOR_ROLE, ADMIN_ROLE);

while let Option::Some(executor) = executors.pop_front() {
self.accesscontrol._grant_role(EXECUTOR_ROLE, *executor);
}
}

#[abi(embed_v0)]
impl UpgradeableImpl of IUpgradeable<ContractState> {
fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {
self.accesscontrol.assert_only_role(ADMIN_ROLE);
self.upgradeable.upgrade(new_class_hash);
}
}
}
73 changes: 73 additions & 0 deletions packages/contracts/registry/src/registry_component.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
use starknet::ContractAddress;

#[starknet::interface]
trait IRegistry<TContractState> {
fn set_registry(ref self: TContractState, registry_address: ContractAddress);
fn has_role(self: @TContractState, role: felt252, account: ContractAddress) -> bool;

fn assert_only_executor(self: @TContractState);
}

#[starknet::component]
pub mod RegistryComponent {
use starknet::ContractAddress;
use starknet::get_caller_address;

use openzeppelin::access::ownable::{
OwnableComponent, OwnableComponent::InternalImpl as OwnableInternalImpl
};

use registry::roles::{ADMIN_ROLE, EXECUTOR_ROLE};
use super::{IRegistry, IRegistryDispatcher, IRegistryDispatcherTrait};

#[storage]
struct Storage {
Registry_address: ContractAddress,
}

pub mod Errors {
pub const REGISTRY_ZERO: felt252 = 'Registry: is zero';
pub const ONLY_EXECUTOR: felt252 = 'Registry: only executor';
}

#[embeddable_as(RegistryImpl)]
impl Registry<
TContractState,
+Drop<TContractState>,
+HasComponent<TContractState>,
impl Owner: OwnableComponent::HasComponent<TContractState>,
> of super::IRegistry<ComponentState<TContractState>> {
fn set_registry(
ref self: ComponentState<TContractState>, registry_address: ContractAddress
) {
let mut ownable_component = get_dep_component_mut!(ref self, Owner);
ownable_component.assert_only_owner();

self.Registry_address.write(registry_address)
}

fn has_role(
self: @ComponentState<TContractState>, role: felt252, account: ContractAddress
) -> bool {
self.registry_dispatcher().has_role(role, account)
}

fn assert_only_executor(self: @ComponentState<TContractState>) {
assert(self.has_role(EXECUTOR_ROLE, get_caller_address()), Errors::ONLY_EXECUTOR)
}
}

#[generate_trait]
pub impl InternalImpl<
TContractState, +HasComponent<TContractState>
> of InternalTrait<TContractState> {
fn initializer(ref self: ComponentState<TContractState>, registry_address: ContractAddress) {
assert(registry_address.is_non_zero(), Errors::REGISTRY_ZERO);
self.Registry_address.write(registry_address);
}

fn registry_dispatcher(self: @ComponentState<TContractState>) -> IRegistryDispatcher {
IRegistryDispatcher { contract_address: self.Registry_address.read() }
}
}
}
2 changes: 2 additions & 0 deletions packages/contracts/registry/src/roles.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
const ADMIN_ROLE: felt252 = selector!("ADMIN_ROLE");
const EXECUTOR_ROLE: felt252 = selector!("EXECUTOR_ROLE");
Loading
Loading