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

Predeclare Argent accounts #658

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

Large diffs are not rendered by default.

Large diffs are not rendered by default.

16 changes: 16 additions & 0 deletions crates/starknet-devnet-core/src/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,22 @@ pub(crate) const UDC_CONTRACT: &str = include_str!(concat!(
"/contracts/system_artifacts/UDC_OZ_0.5.0.json"
));

pub(crate) const ARGENT_CONTRACT_SIERRA: &str = include_str!(concat!(
env!("CARGO_MANIFEST_DIR"),
"/contracts/accounts_artifacts/Argent/argent_0.4.0.sierra"
));

pub const ARGENT_CONTRACT_CLASS_HASH: Felt =
Felt::from_hex_unchecked("0x36078334509b514626504edc9fb252328d1a240e4e948bef8d0c08dff45927f");

pub(crate) const ARGENT_MULTISIG_CONTRACT_SIERRA: &str = include_str!(concat!(
env!("CARGO_MANIFEST_DIR"),
"/contracts/accounts_artifacts/Argent/argent_multisig_0.2.0.sierra"
));

pub const ARGENT_MULTISIG_CONTRACT_CLASS_HASH: Felt =
Felt::from_hex_unchecked("0x7aeca3456816e3b833506d7cc5c1313d371fbdb0ae95ee70af72a4ddbf42594");

pub const UDC_CONTRACT_CLASS_HASH: Felt =
Felt::from_hex_unchecked("0x7B3E05F48F0C69E4A65CE5E076A66271A527AFF2C34CE1083EC6E1526997A69");

Expand Down
40 changes: 35 additions & 5 deletions crates/starknet-devnet-core/src/starknet/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,11 @@ use self::transaction_trace::create_trace;
use crate::account::Account;
use crate::blocks::{StarknetBlock, StarknetBlocks};
use crate::constants::{
CHARGEABLE_ACCOUNT_ADDRESS, CHARGEABLE_ACCOUNT_PRIVATE_KEY, DEVNET_DEFAULT_CHAIN_ID,
DEVNET_DEFAULT_DATA_GAS_PRICE, DEVNET_DEFAULT_GAS_PRICE, DEVNET_DEFAULT_STARTING_BLOCK_NUMBER,
ETH_ERC20_CONTRACT_ADDRESS, ETH_ERC20_NAME, ETH_ERC20_SYMBOL, STRK_ERC20_CONTRACT_ADDRESS,
STRK_ERC20_NAME, STRK_ERC20_SYMBOL, USE_KZG_DA,
ARGENT_CONTRACT_CLASS_HASH, ARGENT_CONTRACT_SIERRA, ARGENT_MULTISIG_CONTRACT_CLASS_HASH,
ARGENT_MULTISIG_CONTRACT_SIERRA, CHARGEABLE_ACCOUNT_ADDRESS, CHARGEABLE_ACCOUNT_PRIVATE_KEY,
DEVNET_DEFAULT_CHAIN_ID, DEVNET_DEFAULT_DATA_GAS_PRICE, DEVNET_DEFAULT_GAS_PRICE,
DEVNET_DEFAULT_STARTING_BLOCK_NUMBER, ETH_ERC20_CONTRACT_ADDRESS, ETH_ERC20_NAME,
ETH_ERC20_SYMBOL, STRK_ERC20_CONTRACT_ADDRESS, STRK_ERC20_NAME, STRK_ERC20_SYMBOL, USE_KZG_DA,
};
use crate::contract_class_choice::AccountContractClassChoice;
use crate::error::{DevnetResult, Error, TransactionValidationError};
Expand Down Expand Up @@ -151,7 +152,7 @@ impl Starknet {
let rpc_contract_classes = Arc::new(RwLock::new(CommittedClassStorage::default()));
let mut state = StarknetState::new(defaulter, rpc_contract_classes.clone());

// predeclare account classes
// predeclare account classes eligible for predeployment
for account_class_choice in
[AccountContractClassChoice::Cairo0, AccountContractClassChoice::Cairo1]
{
Expand All @@ -162,6 +163,18 @@ impl Starknet {
)?;
}

// predeclare argent account classes (not predeployable)
if config.predeclare_argent {
for (class_hash, raw_sierra) in [
(ARGENT_CONTRACT_CLASS_HASH, ARGENT_CONTRACT_SIERRA),
(ARGENT_MULTISIG_CONTRACT_CLASS_HASH, ARGENT_MULTISIG_CONTRACT_SIERRA),
] {
let contract_class =
ContractClass::Cairo1(ContractClass::cairo_1_from_sierra_json_str(raw_sierra)?);
state.predeclare_contract_class(class_hash, contract_class)?;
}
}

// deploy udc, eth erc20 and strk erc20 contracts
let eth_erc20_fee_contract = predeployed::create_erc20_at_address_extended(
ETH_ERC20_CONTRACT_ADDRESS,
Expand Down Expand Up @@ -1362,6 +1375,8 @@ mod tests {
use crate::account::{Account, FeeToken};
use crate::blocks::StarknetBlock;
use crate::constants::{
ARGENT_CONTRACT_CLASS_HASH, ARGENT_MULTISIG_CONTRACT_CLASS_HASH,
CAIRO_0_ACCOUNT_CONTRACT_HASH, CAIRO_1_ACCOUNT_CONTRACT_SIERRA_HASH,
DEVNET_DEFAULT_CHAIN_ID, DEVNET_DEFAULT_INITIAL_BALANCE,
DEVNET_DEFAULT_STARTING_BLOCK_NUMBER, ETH_ERC20_CONTRACT_ADDRESS,
STRK_ERC20_CONTRACT_ADDRESS,
Expand Down Expand Up @@ -1627,6 +1642,21 @@ mod tests {
}
}

#[test]
fn assert_expected_predeclared_account_classes() {
let config = StarknetConfig { predeclare_argent: true, ..Default::default() };
let starknet = Starknet::new(&config).unwrap();
for class_hash in [
ARGENT_CONTRACT_CLASS_HASH,
ARGENT_MULTISIG_CONTRACT_CLASS_HASH,
Felt::from_hex_unchecked(CAIRO_0_ACCOUNT_CONTRACT_HASH),
Felt::from_hex_unchecked(CAIRO_1_ACCOUNT_CONTRACT_SIERRA_HASH),
] {
let contract = starknet.get_class(&BlockId::Tag(BlockTag::Latest), class_hash).unwrap();
assert_eq!(contract.generate_hash().unwrap(), class_hash);
}
}

#[test]
fn calling_method_of_undeployed_contract() {
let config = StarknetConfig::default();
Expand Down
3 changes: 3 additions & 0 deletions crates/starknet-devnet-core/src/starknet/starknet_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,8 @@ pub struct StarknetConfig {
pub eth_erc20_contract_class: String,
#[serde(skip_serializing)]
pub strk_erc20_contract_class: String,
#[serde(skip_serializing)]
pub predeclare_argent: bool,
}

#[allow(clippy::unwrap_used)]
Expand Down Expand Up @@ -156,6 +158,7 @@ impl Default for StarknetConfig {
strk_erc20_class_hash: CAIRO_1_ERC20_CONTRACT_CLASS_HASH,
eth_erc20_contract_class: CAIRO_1_ERC20_CONTRACT.to_string(),
strk_erc20_contract_class: CAIRO_1_ERC20_CONTRACT.to_string(),
predeclare_argent: false,
}
}
}
9 changes: 8 additions & 1 deletion crates/starknet-devnet/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,11 @@ pub(crate) struct Args {
#[arg(help = "Specify the path to a Cairo Sierra artifact to be used by predeployed accounts;")]
account_class_custom: Option<AccountClassWrapper>,

#[arg(long = "predeclare-argent")]
#[arg(env = "PREDECLARE_ARGENT")]
#[arg(help = "If set, predeclares the latest Argent contract classes (regular and multisig)")]
predeclare_argent: bool,

/// Initial balance of predeployed accounts
#[arg(long = "initial-balance")]
#[arg(env = "INITIAL_BALANCE")]
Expand Down Expand Up @@ -244,6 +249,7 @@ impl Args {
block_number: self.fork_block,
block_hash: None,
},
predeclare_argent: self.predeclare_argent,
..Default::default()
};

Expand Down Expand Up @@ -612,7 +618,8 @@ mod tests {
#[test]
#[serial_test::serial]
fn test_boolean_param_specification_via_env_vars() {
let config_source = [("--lite-mode", "LITE_MODE")];
let config_source =
[("--lite-mode", "LITE_MODE"), ("--predeclare-argent", "PREDECLARE_ARGENT")];

let mut cli_args = vec!["--"];
for (cli_param, _) in config_source {
Expand Down
14 changes: 12 additions & 2 deletions crates/starknet-devnet/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ use server::rpc_core::request::{Id, RequestParams, Version};
use server::server::serve_http_api_json_rpc;
use starknet_core::account::Account;
use starknet_core::constants::{
ETH_ERC20_CONTRACT_ADDRESS, STRK_ERC20_CONTRACT_ADDRESS, UDC_CONTRACT_ADDRESS,
UDC_CONTRACT_CLASS_HASH,
ARGENT_CONTRACT_CLASS_HASH, ARGENT_MULTISIG_CONTRACT_CLASS_HASH, ETH_ERC20_CONTRACT_ADDRESS,
STRK_ERC20_CONTRACT_ADDRESS, UDC_CONTRACT_ADDRESS, UDC_CONTRACT_CLASS_HASH,
};
use starknet_core::starknet::starknet_config::{
BlockGenerationOn, DumpOn, ForkConfig, StarknetConfig,
Expand Down Expand Up @@ -115,6 +115,15 @@ fn log_predeployed_contracts(config: &StarknetConfig) {
println!();
}

fn log_other_predeclared_contracts(config: &StarknetConfig) {
if config.predeclare_argent {
println!("Predeclared Argent account classes");
println!("Regular class hash: 0x{:X}", ARGENT_CONTRACT_CLASS_HASH);
println!("Multisig class hash: 0x{:X}", ARGENT_MULTISIG_CONTRACT_CLASS_HASH);
println!();
}
}

fn log_chain_id(chain_id: &ChainId) {
println!("Chain ID: {} ({})", chain_id, chain_id.to_felt().to_hex_string());
}
Expand Down Expand Up @@ -275,6 +284,7 @@ async fn main() -> Result<(), anyhow::Error> {
};

log_predeployed_contracts(&starknet_config);
log_other_predeclared_contracts(&starknet_config);
log_chain_id(&starknet_config.chain_id);

let predeployed_accounts = api.starknet.lock().await.get_predeployed_accounts();
Expand Down
8 changes: 6 additions & 2 deletions crates/starknet-devnet/tests/common/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,14 @@ pub const INVALID_ACCOUNT_SIERRA_PATH: &str =
"../../contracts/test_artifacts/cairo1/invalid_account/invalid_account.sierra";

/// hash of the sierra artifact at commit d9f5220059c1e61ff87e4a5752522569135e464c of
/// argentlabs/argent-contracts-starknet:main
pub const ARGENT_ACCOUNT_CLASS_HASH: &str =
/// argentlabs/argent-contracts-starknet:main (same as v0.3.1)
pub const LEGACY_ARGENT_ACCOUNT_CLASS_HASH: &str =
"0x029927c8af6bccf3f6fda035981e765a7bdbf18a2dc0d630494f8758aa908e2b";

/// v0.4.0
pub const ARGENT_ACCOUNT_CLASS_HASH: &str =
"0x36078334509b514626504edc9fb252328d1a240e4e948bef8d0c08dff45927f";

/// Forking
pub const INTEGRATION_SEPOLIA_HTTP_URL: &str =
"http://rpc.pathfinder.equilibrium.co/integration-sepolia/rpc/v0_7";
Expand Down
8 changes: 5 additions & 3 deletions crates/starknet-devnet/tests/common/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use starknet_rs_signers::LocalWallet;
use starknet_types::felt::felt_from_prefixed_hex;

use super::background_devnet::BackgroundDevnet;
use super::constants::{ARGENT_ACCOUNT_CLASS_HASH, CAIRO_1_CONTRACT_PATH};
use super::constants::CAIRO_1_CONTRACT_PATH;

pub enum ImpersonationAction {
ImpersonateAccount(Felt),
Expand Down Expand Up @@ -288,11 +288,12 @@ pub async fn deploy_oz_account(
/// Assumes the Argent account contract is declared in the target network.
pub async fn deploy_argent_account(
devnet: &BackgroundDevnet,
class_hash: Felt,
) -> Result<(DeployAccountTransactionResult, LocalWallet), anyhow::Error> {
let signer = get_deployable_account_signer();
let salt = Felt::THREE;
let factory = ArgentAccountFactory::new(
felt_from_prefixed_hex(ARGENT_ACCOUNT_CLASS_HASH)?,
class_hash,
devnet.json_rpc_client.chain_id().await?,
Felt::ZERO,
signer.clone(),
Expand All @@ -304,7 +305,8 @@ pub async fn deploy_argent_account(

let account_address = deployment.address();
devnet.mint(account_address, 1e18 as u128).await;
let deployment_result = deployment.send().await?;
let deployment_result =
deployment.send().await.map_err(|e| anyhow::Error::msg(format!("{e:?}")))?;

Ok((deployment_result, signer))
}
Expand Down
25 changes: 22 additions & 3 deletions crates/starknet-devnet/tests/test_account_selection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ mod test_account_selection {
use starknet_types::rpc::transaction_receipt::FeeUnit;

use crate::common::background_devnet::BackgroundDevnet;
use crate::common::constants::MAINNET_URL;
use crate::common::constants::{
ARGENT_ACCOUNT_CLASS_HASH, LEGACY_ARGENT_ACCOUNT_CLASS_HASH, MAINNET_URL,
};
use crate::common::reqwest_client::GetReqwestSender;
use crate::common::utils::{
assert_tx_successful, deploy_argent_account, deploy_oz_account,
Expand Down Expand Up @@ -124,11 +126,28 @@ mod test_account_selection {

#[tokio::test]
/// Relying on forking: the origin network is expected to have the account class declared.
async fn can_deploy_new_argent_account() {
async fn can_deploy_instance_of_legacy_argent_account_via_fork() {
let cli_args = ["--fork-network", MAINNET_URL];
let devnet = BackgroundDevnet::spawn_with_additional_args(&cli_args).await.unwrap();

let (account_deployment, signer) = deploy_argent_account(&devnet).await.unwrap();
let account_hash = Felt::from_hex_unchecked(LEGACY_ARGENT_ACCOUNT_CLASS_HASH);
let (account_deployment, signer) =
deploy_argent_account(&devnet, account_hash).await.unwrap();
assert_tx_successful(&account_deployment.transaction_hash, &devnet.json_rpc_client).await;

let account_address = account_deployment.contract_address;
can_declare_deploy_invoke_cairo1_using_account(&devnet, &signer, account_address).await;
}

#[tokio::test]
#[ignore = "Requires starknet-rs with https://github.com/xJonathanLEI/starknet-rs/pull/680"]
async fn can_deploy_new_argent_account_from_predeclared_class() {
let devnet_args = ["--predeclare-argent"];
let devnet = BackgroundDevnet::spawn_with_additional_args(&devnet_args).await.unwrap();

let account_hash = Felt::from_hex_unchecked(ARGENT_ACCOUNT_CLASS_HASH);
let (account_deployment, signer) =
deploy_argent_account(&devnet, account_hash).await.unwrap();
assert_tx_successful(&account_deployment.transaction_hash, &devnet.json_rpc_client).await;

let account_address = account_deployment.contract_address;
Expand Down
4 changes: 4 additions & 0 deletions website/docs/predeployed.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ Alternatively, provide a path to the [Sierra artifact](https://github.com/starkw
--account-class-custom <SIERRA_PATH>
```

## Predeclared account classes

Both Cairo 0 and Cairo 1 versions of OpenZeppelin account are always predeclared, regardless of the chosen predeployment variant. If you specify the `--predeclare-argent` flag on startup, the latest regular and multistig variants of Argent account will also be predeclared.

## Deploying an undeclared account

If you want to deploy an instance of an account contract class not predeclared on Devnet, you can use [forking](./forking). Just fork an origin network which has the needed class already declared, e.g. the Sepolia testnet. Why? Because new versions of wallets like ArgentX and Braavos tend to be declared on testnet/mainnet soon after release.
Expand Down