Skip to content

Commit

Permalink
feat(katana): check predeployed settlement contract is configured cor…
Browse files Browse the repository at this point in the history
…rectly (#2971)
  • Loading branch information
kariy authored Jan 29, 2025
1 parent 4f3373e commit 010bf80
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 55 deletions.
106 changes: 64 additions & 42 deletions bin/katana/src/cli/init/deployment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,23 @@ use starknet::signers::LocalWallet;
use thiserror::Error;
use tracing::trace;

type InitializerAccount = SingleOwnerAccount<Arc<JsonRpcClient<HttpTransport>>, LocalWallet>;
type RpcProvider = Arc<JsonRpcClient<HttpTransport>>;
type InitializerAccount = SingleOwnerAccount<RpcProvider, LocalWallet>;

#[rustfmt::skip]
abigen!(
AppchainContract,
"[{\"type\":\"function\",\"name\":\"set_program_info\",\"inputs\":[{\"name\":\"\
program_hash\",\"type\":\"core::Felt\"},{\"name\":\"config_hash\",\"type\":\"\
core::Felt\"}],\"outputs\":[],\"state_mutability\":\"external\"},{\"type\":\"\
function\",\"name\":\"set_facts_registry\",\"inputs\":[{\"name\":\"address\",\"type\"\
:\"core::starknet::contract_address::ContractAddress\"}],\"outputs\":[],\"\
state_mutability\":\"external\"},{\"type\":\"function\",\"name\":\"\
get_facts_registry\",\"inputs\":[],\"outputs\":[{\"type\":\"\
core::starknet::contract_address::ContractAddress\"}],\"state_mutability\":\"view\"},\
{\"type\":\"function\",\"name\":\"get_program_info\",\"inputs\":[],\"outputs\":[{\"\
type\":\"(core::Felt, core::Felt)\"}],\"state_mutability\":\"view\"}]"
);

const PROGRAM_HASH: Felt =
felt!("0x5ab580b04e3532b6b18f81cfa654a05e29dd8e2352d88df1e765a84072db07");
Expand Down Expand Up @@ -56,20 +72,6 @@ pub async fn deploy_settlement_contract(
"../../../../../crates/katana/contracts/build/appchain_core_contract.json"
);

abigen!(
AppchainContract,
"[{\"type\":\"function\",\"name\":\"set_program_info\",\"inputs\":[{\"name\":\"\
program_hash\",\"type\":\"core::Felt\"},{\"name\":\"config_hash\",\"type\":\"\
core::Felt\"}],\"outputs\":[],\"state_mutability\":\"external\"},{\"type\":\"\
function\",\"name\":\"set_facts_registry\",\"inputs\":[{\"name\":\"address\",\"type\"\
:\"core::starknet::contract_address::ContractAddress\"}],\"outputs\":[],\"\
state_mutability\":\"external\"},{\"type\":\"function\",\"name\":\"\
get_facts_registry\",\"inputs\":[],\"outputs\":[{\"type\":\"\
core::starknet::contract_address::ContractAddress\"}],\"state_mutability\":\"view\"},\
{\"type\":\"function\",\"name\":\"get_program_info\",\"inputs\":[],\"outputs\":[{\"\
type\":\"(core::Felt, core::Felt)\"}],\"state_mutability\":\"view\"}]"
);

let class = ContractClass::from_str(class)?;
let class_hash = class.class_hash()?;

Expand Down Expand Up @@ -176,33 +178,7 @@ pub async fn deploy_settlement_contract(
// FINAL CHECKS
// -----------------------------------------------------------------------

// Assert that the values are correctly set
let (program_info_res, facts_registry_res) =
tokio::join!(appchain.get_program_info().call(), appchain.get_facts_registry().call());

let (actual_program_hash, actual_config_hash) = program_info_res?;
let facts_registry = facts_registry_res?;

if actual_program_hash != PROGRAM_HASH {
return Err(ContractInitError::InvalidProgramHash {
actual: actual_program_hash,
expected: PROGRAM_HASH,
});
}

if actual_config_hash != config_hash {
return Err(ContractInitError::InvalidConfigHash {
actual: actual_config_hash,
expected: config_hash,
});
}

if facts_registry != ATLANTIC_FACT_REGISTRY_SEPOLIA.into() {
return Err(ContractInitError::InvalidFactRegistry {
actual: facts_registry.into(),
expected: ATLANTIC_FACT_REGISTRY_SEPOLIA,
});
}
check_program_info(chain_id, deployed_appchain_contract, account.provider()).await?;

Ok(deployed_appchain_contract.into())
}
Expand All @@ -215,6 +191,52 @@ pub async fn deploy_settlement_contract(
result
}

/// Checks that the program info is correctly set on the contract according to the chain's
/// configuration.
pub async fn check_program_info(
chain_id: Felt,
appchain_address: Felt,
provider: &RpcProvider,
) -> Result<(), ContractInitError> {
let appchain = AppchainContractReader::new(appchain_address, provider);

// Compute the chain's config hash
let config_hash = compute_config_hash(
chain_id,
felt!("0x2e7442625bab778683501c0eadbc1ea17b3535da040a12ac7d281066e915eea"),
);

// Assert that the values are correctly set
let (program_info_res, facts_registry_res) =
tokio::join!(appchain.get_program_info().call(), appchain.get_facts_registry().call());

let (actual_program_hash, actual_config_hash) = program_info_res?;
let facts_registry = facts_registry_res?;

if actual_program_hash != PROGRAM_HASH {
return Err(ContractInitError::InvalidProgramHash {
actual: actual_program_hash,
expected: PROGRAM_HASH,
});
}

if actual_config_hash != config_hash {
return Err(ContractInitError::InvalidConfigHash {
actual: actual_config_hash,
expected: config_hash,
});
}

if facts_registry != ATLANTIC_FACT_REGISTRY_SEPOLIA.into() {
return Err(ContractInitError::InvalidFactRegistry {
actual: facts_registry.into(),
expected: ATLANTIC_FACT_REGISTRY_SEPOLIA,
});
}

Ok(())
}

/// Error that can happen during the initialization of the core contract.
#[derive(Error, Debug)]
pub enum ContractInitError {
Expand Down
28 changes: 15 additions & 13 deletions bin/katana/src/cli/init/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use starknet::core::utils::{cairo_short_string_to_felt, parse_cairo_short_string
use starknet::providers::jsonrpc::HttpTransport;
use starknet::providers::{JsonRpcClient, Provider, Url};
use starknet::signers::{LocalWallet, SigningKey};
use tokio::runtime::Runtime;
use tokio::runtime::Runtime as AsyncRuntime;

const CARTRIDGE_SN_SEPOLIA_PROVIDER: &str = "https://api.cartridge.gg/x/starknet/sepolia";

Expand Down Expand Up @@ -53,7 +53,7 @@ impl InitArgs {
Ok(())
}

fn prompt(&self, rt: &Runtime) -> Result<PromptOutcome> {
fn prompt(&self, rt: &AsyncRuntime) -> Result<PromptOutcome> {
let chain_id = CustomType::<String>::new("Id")
.with_help_message("This will be the id of your rollup chain.")
// checks that the input is a valid ascii string.
Expand Down Expand Up @@ -128,13 +128,6 @@ impl InitArgs {
ExecutionEncoding::New,
);

// TODO: uncomment once we actually using the fee token.
// // The L1 fee token. Must be an existing token.
// let fee_token = CustomType::<ContractAddress>::new("Fee token")
// .with_parser(contract_exist_parser)
// .with_error_message("Please enter a valid fee token (the token must exist on L1)")
// .prompt()?;

// The core settlement contract on L1c.
// Prompt the user whether to deploy the settlement contract or not.
let settlement_contract =
Expand All @@ -146,11 +139,20 @@ impl InitArgs {
}
// If denied, prompt the user for an already deployed contract.
else {
// TODO: add a check to make sure the contract is indeed a valid settlement
// contract.
CustomType::<ContractAddress>::new("Settlement contract")
let address = CustomType::<ContractAddress>::new("Settlement contract")
.with_parser(contract_exist_parser)
.prompt()?
.prompt()?;

// Check that the settlement contract has been initialized with the correct program
// info.
let chain_id = cairo_short_string_to_felt(&chain_id)?;
rt.block_on(deployment::check_program_info(chain_id, address.into(), &l1_provider))
.context(
"Invalid settlement contract. The contract might have been configured \
incorrectly.",
)?;

address
};

Ok(PromptOutcome {
Expand Down

0 comments on commit 010bf80

Please sign in to comment.