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

Sovereign-Forge Phase Three #203

Merged
merged 11 commits into from
Dec 10, 2024
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

19 changes: 16 additions & 3 deletions chain-factory/src/factory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,18 +89,31 @@ pub trait FactoryModule: only_admin::OnlyAdminModule {

#[only_admin]
#[endpoint(deployEsdtSafe)]
fn deploy_esdt_safe(&self, is_sovereign_chain: bool) -> ManagedAddress {
fn deploy_esdt_safe(
&self,
is_sovereign_chain: bool,
header_verifier_address: ManagedAddress,
) -> ManagedAddress {
let source_address = self.enshrine_esdt_safe_template().get();
let metadata = self.blockchain().get_code_metadata(&source_address);

self.tx()
let esdt_safe_address = self
.tx()
.typed(EsdtSafeProxy)
.init(is_sovereign_chain)
.gas(60_000_000)
.from_source(source_address)
.code_metadata(metadata)
.returns(ReturnsNewManagedAddress)
.sync_call()
.sync_call();

self.tx()
.to(header_verifier_address)
.typed(HeaderverifierProxy)
.set_esdt_safe_address(&esdt_safe_address)
.sync_call();

esdt_safe_address
}

#[only_admin]
Expand Down
3 changes: 3 additions & 0 deletions common/proxies/src/chain_factory_proxy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,14 +156,17 @@ where

pub fn deploy_esdt_safe<
Arg0: ProxyArg<bool>,
Arg1: ProxyArg<ManagedAddress<Env::Api>>,
>(
self,
is_sovereign_chain: Arg0,
header_verifier_address: Arg1,
) -> TxTypedCall<Env, From, To, NotPayable, Gas, ManagedAddress<Env::Api>> {
self.wrapped_tx
.payment(NotPayable)
.raw_call("deployEsdtSafe")
.argument(&is_sovereign_chain)
.argument(&header_verifier_address)
.original_result()
}

Expand Down
13 changes: 13 additions & 0 deletions common/proxies/src/sovereign_forge_proxy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,19 @@ where
.original_result()
}

pub fn deploy_phase_three<
Arg0: ProxyArg<bool>,
>(
self,
is_sovereign_chain: Arg0,
) -> TxTypedCall<Env, From, To, NotPayable, Gas, ()> {
self.wrapped_tx
.payment(NotPayable)
.raw_call("deployPhaseThree")
.argument(&is_sovereign_chain)
.original_result()
}

pub fn chain_factories<
Arg0: ProxyArg<u32>,
>(
Expand Down
3 changes: 3 additions & 0 deletions sovereign-forge/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ path = "../chain-config"
[dependencies.header-verifier]
path = "../header-verifier"

[dependencies.esdt-safe]
path = "../esdt-safe"

[dependencies.proxies]
path = "../common/proxies"

Expand Down
8 changes: 6 additions & 2 deletions sovereign-forge/src/common/sc_deploy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,15 @@ pub trait ScDeployModule: super::utils::UtilsModule + super::storage::StorageMod
}

#[inline]
fn deploy_esdt_safe(&self, is_sovereign_chain: bool) -> ManagedAddress {
fn deploy_esdt_safe(
&self,
is_sovereign_chain: bool,
header_verifier_address: &ManagedAddress,
) -> ManagedAddress {
self.tx()
.to(self.get_chain_factory_address())
.typed(ChainFactoryContractProxy)
.deploy_esdt_safe(is_sovereign_chain)
.deploy_esdt_safe(is_sovereign_chain, header_verifier_address)
.returns(ReturnsResult)
.sync_call()
}
Expand Down
17 changes: 17 additions & 0 deletions sovereign-forge/src/common/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,13 @@ pub enum ScArray {

#[multiversx_sc::module]
pub trait UtilsModule: super::storage::StorageModule {
fn require_phase_two_completed(&self, caller: &ManagedAddress) {
require!(
self.is_contract_deployed(caller, ScArray::HeaderVerifier),
"The Header-Verifier SC is not deployed, you skipped the second phase"
);
}

fn require_phase_1_completed(&self, caller: &ManagedAddress) {
require!(
!self.sovereigns_mapper(caller).is_empty(),
Expand All @@ -63,6 +70,16 @@ pub trait UtilsModule: super::storage::StorageModule {
.any(|sc| sc.id == sc_id)
}

fn get_contract_address(&self, caller: &ManagedAddress, sc_id: ScArray) -> ManagedAddress {
let chain_id = self.sovereigns_mapper(caller).get();

self.sovereign_deployed_contracts(&chain_id)
.iter()
.find(|sc| sc.id == sc_id)
.unwrap()
.address
}

fn generate_chain_id(&self) -> ManagedBuffer {
loop {
let new_chain_id = self.generated_random_4_char_string();
Expand Down
25 changes: 25 additions & 0 deletions sovereign-forge/src/phases.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,10 @@ pub trait PhasesModule:
let caller = blockchain_api.get_caller();

self.require_phase_1_completed(&caller);
require!(
!self.is_contract_deployed(&caller, ScArray::HeaderVerifier),
"The Header-Verifier contract is already deployed"
);

let header_verifier_address = self.deploy_header_verifier(bls_keys);

Expand All @@ -102,4 +106,25 @@ pub trait PhasesModule:
self.sovereign_deployed_contracts(&self.sovereigns_mapper(&caller).get())
.insert(header_verifier_contract_info);
}

#[endpoint(deployPhaseThree)]
fn deploy_phase_three(&self, is_sovereign_chain: bool) {
let caller = self.blockchain().get_caller();

self.require_phase_two_completed(&caller);
require!(
!self.is_contract_deployed(&caller, ScArray::ESDTSafe),
"The ESDT-Safe SC is already deployed"
);

let header_verifier_address = self.get_contract_address(&caller, ScArray::HeaderVerifier);

let esdt_safe_address = self.deploy_esdt_safe(is_sovereign_chain, &header_verifier_address);

let esdt_safe_contract_info =
ContractInfo::new(ScArray::ESDTSafe, esdt_safe_address.clone());

self.sovereign_deployed_contracts(&self.sovereigns_mapper(&caller).get())
.insert(esdt_safe_contract_info);
}
}
168 changes: 158 additions & 10 deletions sovereign-forge/tests/sovereign_forge_unit_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ use multiversx_sc_scenario::{
};
use proxies::{
chain_config_proxy::ChainConfigContractProxy, chain_factory_proxy::ChainFactoryContractProxy,
header_verifier_proxy::HeaderverifierProxy, sovereign_forge_proxy::SovereignForgeProxy,
esdt_safe_proxy::EsdtSafeProxy, header_verifier_proxy::HeaderverifierProxy,
sovereign_forge_proxy::SovereignForgeProxy,
};
use setup_phase::SetupPhaseModule;
use sovereign_forge::common::{
Expand All @@ -29,6 +30,9 @@ const HEADER_VERIFIER_ADDRESS: TestSCAddress = TestSCAddress::new("header-verifi
const HEADER_VERIFIER_CODE_PATH: MxscPath =
MxscPath::new("../header-verifier/output/header-verifier.mxsc.json");

const ESDT_SAFE_ADDRESS: TestSCAddress = TestSCAddress::new("esdt-safe");
const ESDT_SAFE_CODE_PATH: MxscPath = MxscPath::new("../esdt-safe/output/esdt-safe.mxsc.json");

const TOKEN_HANDLER_ADDRESS: TestSCAddress = TestSCAddress::new("token-handler");

const BALANCE: u128 = 100_000_000_000_000_000;
Expand All @@ -41,6 +45,7 @@ fn world() -> ScenarioWorld {
blockchain.register_contract(FACTORY_CODE_PATH, chain_factory::ContractBuilder);
blockchain.register_contract(CONFIG_CODE_PATH, chain_config::ContractBuilder);
blockchain.register_contract(HEADER_VERIFIER_CODE_PATH, header_verifier::ContractBuilder);
blockchain.register_contract(ESDT_SAFE_CODE_PATH, esdt_safe::ContractBuilder);

blockchain
}
Expand Down Expand Up @@ -70,7 +75,7 @@ impl SovereignForgeTestState {
FORGE_ADDRESS,
CONFIG_ADDRESS,
HEADER_VERIFIER_ADDRESS,
FACTORY_ADDRESS,
ESDT_SAFE_ADDRESS,
FACTORY_ADDRESS,
)
.code(FACTORY_CODE_PATH)
Expand Down Expand Up @@ -129,6 +134,21 @@ impl SovereignForgeTestState {
self
}

fn deploy_esdt_safe_template(&mut self) -> &mut Self {
let is_sovereign_chain = false;

self.world
.tx()
.from(OWNER_ADDRESS)
.typed(EsdtSafeProxy)
.init(is_sovereign_chain)
.code(ESDT_SAFE_CODE_PATH)
.new_address(ESDT_SAFE_ADDRESS)
.run();

self
}

fn register_token_handler(
&mut self,
shard_id: u32,
Expand Down Expand Up @@ -187,6 +207,16 @@ impl SovereignForgeTestState {
}
}

fn finish_setup(&mut self) {
self.register_chain_factory(1, FACTORY_ADDRESS, None);
self.register_chain_factory(2, FACTORY_ADDRESS, None);
self.register_chain_factory(3, FACTORY_ADDRESS, None);
self.register_token_handler(1, TOKEN_HANDLER_ADDRESS, None);
self.register_token_handler(2, TOKEN_HANDLER_ADDRESS, None);
self.register_token_handler(3, TOKEN_HANDLER_ADDRESS, None);
self.complete_setup_phase(None);
}

fn deploy_phase_one(
&mut self,
payment: &BigUint<StaticApi>,
Expand Down Expand Up @@ -237,14 +267,20 @@ impl SovereignForgeTestState {
}
}

fn finish_setup(&mut self) {
self.register_chain_factory(1, FACTORY_ADDRESS, None);
self.register_chain_factory(2, FACTORY_ADDRESS, None);
self.register_chain_factory(3, FACTORY_ADDRESS, None);
self.register_token_handler(1, TOKEN_HANDLER_ADDRESS, None);
self.register_token_handler(2, TOKEN_HANDLER_ADDRESS, None);
self.register_token_handler(3, TOKEN_HANDLER_ADDRESS, None);
self.complete_setup_phase(None);
fn deploy_phase_three(&mut self, is_sovereign_chain: bool, expect_error: Option<ExpectError>) {
let transaction = self
.world
.tx()
.from(OWNER_ADDRESS)
.to(FORGE_ADDRESS)
.typed(SovereignForgeProxy)
.deploy_phase_three(is_sovereign_chain);

if let Some(error) = expect_error {
transaction.returns(error).run();
} else {
transaction.run();
}
}
}

Expand Down Expand Up @@ -499,3 +535,115 @@ fn deploy_phase_two_header_already_deployed() {
&bls_keys,
);
}

#[test]
fn deploy_phase_three() {
let mut state = SovereignForgeTestState::new();
state.deploy_sovereign_forge();
state.deploy_chain_factory();
state.deploy_chain_config_template();
state.finish_setup();

let deploy_cost = BigUint::from(100_000u32);

state.deploy_phase_one(
&deploy_cost,
1,
2,
BigUint::from(2u32),
MultiValueEncoded::new(),
None,
);

state.deploy_header_verifier_template();
state.deploy_esdt_safe_template();

let mut bls_keys = MultiValueEncoded::new();
bls_keys.push(ManagedBuffer::from("bls1"));
bls_keys.push(ManagedBuffer::from("bls2"));

state.deploy_phase_two(None, &bls_keys);
state.deploy_phase_three(false, None);
}

#[test]
fn deploy_phase_three_without_phase_one() {
let mut state = SovereignForgeTestState::new();
state.deploy_sovereign_forge();
state.deploy_chain_factory();
state.deploy_chain_config_template();
state.finish_setup();

state.deploy_phase_three(
false,
Some(ExpectError(
4,
"The Header-Verifier SC is not deployed, you skipped the second phase",
)),
);
}

#[test]
fn deploy_phase_three_without_phase_two() {
let mut state = SovereignForgeTestState::new();
state.deploy_sovereign_forge();
state.deploy_chain_factory();
state.deploy_chain_config_template();
state.finish_setup();

let deploy_cost = BigUint::from(100_000u32);

state.deploy_phase_one(
&deploy_cost,
1,
2,
BigUint::from(2u32),
MultiValueEncoded::new(),
None,
);

state.deploy_header_verifier_template();
state.deploy_esdt_safe_template();

state.deploy_phase_three(
false,
Some(ExpectError(
4,
"The Header-Verifier SC is not deployed, you skipped the second phase",
)),
);
}

#[test]
fn deploy_phase_three_already_deployed() {
let mut state = SovereignForgeTestState::new();
state.deploy_sovereign_forge();
state.deploy_chain_factory();
state.deploy_chain_config_template();
state.finish_setup();

let deploy_cost = BigUint::from(100_000u32);

state.deploy_phase_one(
&deploy_cost,
1,
2,
BigUint::from(2u32),
MultiValueEncoded::new(),
None,
);

state.deploy_header_verifier_template();
state.deploy_esdt_safe_template();

let mut bls_keys = MultiValueEncoded::new();
bls_keys.push(ManagedBuffer::from("bls1"));
bls_keys.push(ManagedBuffer::from("bls2"));

state.deploy_phase_two(None, &bls_keys);
state.deploy_phase_three(false, None);
state.deploy_phase_three(
false,
Some(ExpectError(4, "The ESDT-Safe SC is already deployed")),
);
}
Loading
Loading