Skip to content

Commit fb5b581

Browse files
authored
Predeclare Argent accounts (#658)
1 parent 4baa0b5 commit fb5b581

File tree

11 files changed

+127
-20
lines changed

11 files changed

+127
-20
lines changed

crates/starknet-devnet-core/contracts/accounts_artifacts/Argent/argent_0.4.0.sierra

Lines changed: 1 addition & 0 deletions
Large diffs are not rendered by default.

crates/starknet-devnet-core/contracts/accounts_artifacts/Argent/argent_multisig_0.2.0.sierra

Lines changed: 1 addition & 0 deletions
Large diffs are not rendered by default.

crates/starknet-devnet-core/src/constants.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,24 @@ pub(crate) const UDC_CONTRACT: &str = include_str!(concat!(
5151
"/contracts/system_artifacts/UDC_OZ_0.5.0.json"
5252
));
5353

54+
/// https://github.com/argentlabs/argent-contracts-starknet/blob/main/deployments/account.txt
55+
pub const ARGENT_CONTRACT_VERSION: &str = "0.4.0";
56+
pub(crate) const ARGENT_CONTRACT_SIERRA: &str = include_str!(concat!(
57+
env!("CARGO_MANIFEST_DIR"),
58+
"/contracts/accounts_artifacts/Argent/argent_0.4.0.sierra"
59+
));
60+
pub const ARGENT_CONTRACT_CLASS_HASH: Felt =
61+
Felt::from_hex_unchecked("0x36078334509b514626504edc9fb252328d1a240e4e948bef8d0c08dff45927f");
62+
63+
/// https://github.com/argentlabs/argent-contracts-starknet/blob/main/deployments/multisig.txt
64+
pub const ARGENT_MULTISIG_CONTRACT_VERSION: &str = "0.2.0";
65+
pub(crate) const ARGENT_MULTISIG_CONTRACT_SIERRA: &str = include_str!(concat!(
66+
env!("CARGO_MANIFEST_DIR"),
67+
"/contracts/accounts_artifacts/Argent/argent_multisig_0.2.0.sierra"
68+
));
69+
pub const ARGENT_MULTISIG_CONTRACT_CLASS_HASH: Felt =
70+
Felt::from_hex_unchecked("0x7aeca3456816e3b833506d7cc5c1313d371fbdb0ae95ee70af72a4ddbf42594");
71+
5472
pub const UDC_CONTRACT_CLASS_HASH: Felt =
5573
Felt::from_hex_unchecked("0x7B3E05F48F0C69E4A65CE5E076A66271A527AFF2C34CE1083EC6E1526997A69");
5674

crates/starknet-devnet-core/src/starknet/mod.rs

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -60,10 +60,11 @@ use self::transaction_trace::create_trace;
6060
use crate::account::Account;
6161
use crate::blocks::{StarknetBlock, StarknetBlocks};
6262
use crate::constants::{
63-
CHARGEABLE_ACCOUNT_ADDRESS, CHARGEABLE_ACCOUNT_PRIVATE_KEY, DEVNET_DEFAULT_CHAIN_ID,
64-
DEVNET_DEFAULT_DATA_GAS_PRICE, DEVNET_DEFAULT_GAS_PRICE, DEVNET_DEFAULT_STARTING_BLOCK_NUMBER,
65-
ETH_ERC20_CONTRACT_ADDRESS, ETH_ERC20_NAME, ETH_ERC20_SYMBOL, STRK_ERC20_CONTRACT_ADDRESS,
66-
STRK_ERC20_NAME, STRK_ERC20_SYMBOL, USE_KZG_DA,
63+
ARGENT_CONTRACT_CLASS_HASH, ARGENT_CONTRACT_SIERRA, ARGENT_MULTISIG_CONTRACT_CLASS_HASH,
64+
ARGENT_MULTISIG_CONTRACT_SIERRA, CHARGEABLE_ACCOUNT_ADDRESS, CHARGEABLE_ACCOUNT_PRIVATE_KEY,
65+
DEVNET_DEFAULT_CHAIN_ID, DEVNET_DEFAULT_DATA_GAS_PRICE, DEVNET_DEFAULT_GAS_PRICE,
66+
DEVNET_DEFAULT_STARTING_BLOCK_NUMBER, ETH_ERC20_CONTRACT_ADDRESS, ETH_ERC20_NAME,
67+
ETH_ERC20_SYMBOL, STRK_ERC20_CONTRACT_ADDRESS, STRK_ERC20_NAME, STRK_ERC20_SYMBOL, USE_KZG_DA,
6768
};
6869
use crate::contract_class_choice::AccountContractClassChoice;
6970
use crate::error::{DevnetResult, Error, TransactionValidationError};
@@ -151,7 +152,7 @@ impl Starknet {
151152
let rpc_contract_classes = Arc::new(RwLock::new(CommittedClassStorage::default()));
152153
let mut state = StarknetState::new(defaulter, rpc_contract_classes.clone());
153154

154-
// predeclare account classes
155+
// predeclare account classes eligible for predeployment
155156
for account_class_choice in
156157
[AccountContractClassChoice::Cairo0, AccountContractClassChoice::Cairo1]
157158
{
@@ -162,6 +163,18 @@ impl Starknet {
162163
)?;
163164
}
164165

166+
// predeclare argent account classes (not predeployable)
167+
if config.predeclare_argent {
168+
for (class_hash, raw_sierra) in [
169+
(ARGENT_CONTRACT_CLASS_HASH, ARGENT_CONTRACT_SIERRA),
170+
(ARGENT_MULTISIG_CONTRACT_CLASS_HASH, ARGENT_MULTISIG_CONTRACT_SIERRA),
171+
] {
172+
let contract_class =
173+
ContractClass::Cairo1(ContractClass::cairo_1_from_sierra_json_str(raw_sierra)?);
174+
state.predeclare_contract_class(class_hash, contract_class)?;
175+
}
176+
}
177+
165178
// deploy udc, eth erc20 and strk erc20 contracts
166179
let eth_erc20_fee_contract = predeployed::create_erc20_at_address_extended(
167180
ETH_ERC20_CONTRACT_ADDRESS,
@@ -1371,6 +1384,8 @@ mod tests {
13711384
use crate::account::{Account, FeeToken};
13721385
use crate::blocks::StarknetBlock;
13731386
use crate::constants::{
1387+
ARGENT_CONTRACT_CLASS_HASH, ARGENT_MULTISIG_CONTRACT_CLASS_HASH,
1388+
CAIRO_0_ACCOUNT_CONTRACT_HASH, CAIRO_1_ACCOUNT_CONTRACT_SIERRA_HASH,
13741389
DEVNET_DEFAULT_CHAIN_ID, DEVNET_DEFAULT_INITIAL_BALANCE,
13751390
DEVNET_DEFAULT_STARTING_BLOCK_NUMBER, ETH_ERC20_CONTRACT_ADDRESS,
13761391
STRK_ERC20_CONTRACT_ADDRESS,
@@ -1636,6 +1651,21 @@ mod tests {
16361651
}
16371652
}
16381653

1654+
#[test]
1655+
fn assert_expected_predeclared_account_classes() {
1656+
let config = StarknetConfig { predeclare_argent: true, ..Default::default() };
1657+
let starknet = Starknet::new(&config).unwrap();
1658+
for class_hash in [
1659+
ARGENT_CONTRACT_CLASS_HASH,
1660+
ARGENT_MULTISIG_CONTRACT_CLASS_HASH,
1661+
Felt::from_hex_unchecked(CAIRO_0_ACCOUNT_CONTRACT_HASH),
1662+
Felt::from_hex_unchecked(CAIRO_1_ACCOUNT_CONTRACT_SIERRA_HASH),
1663+
] {
1664+
let contract = starknet.get_class(&BlockId::Tag(BlockTag::Latest), class_hash).unwrap();
1665+
assert_eq!(contract.generate_hash().unwrap(), class_hash);
1666+
}
1667+
}
1668+
16391669
#[test]
16401670
fn calling_method_of_undeployed_contract() {
16411671
let config = StarknetConfig::default();

crates/starknet-devnet-core/src/starknet/starknet_config.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,8 @@ pub struct StarknetConfig {
123123
pub eth_erc20_contract_class: String,
124124
#[serde(skip_serializing)]
125125
pub strk_erc20_contract_class: String,
126+
#[serde(skip_serializing)]
127+
pub predeclare_argent: bool,
126128
}
127129

128130
#[allow(clippy::unwrap_used)]
@@ -156,6 +158,7 @@ impl Default for StarknetConfig {
156158
strk_erc20_class_hash: CAIRO_1_ERC20_CONTRACT_CLASS_HASH,
157159
eth_erc20_contract_class: CAIRO_1_ERC20_CONTRACT.to_string(),
158160
strk_erc20_contract_class: CAIRO_1_ERC20_CONTRACT.to_string(),
161+
predeclare_argent: false,
159162
}
160163
}
161164
}

crates/starknet-devnet/src/cli.rs

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@ use server::restrictive_mode::DEFAULT_RESTRICTED_JSON_RPC_METHODS;
77
use server::server::HTTP_API_ROUTES_WITHOUT_LEADING_SLASH;
88
use server::ServerConfig;
99
use starknet_core::constants::{
10-
DEVNET_DEFAULT_DATA_GAS_PRICE, DEVNET_DEFAULT_GAS_PRICE, DEVNET_DEFAULT_PORT,
11-
DEVNET_DEFAULT_REQUEST_BODY_SIZE_LIMIT, DEVNET_DEFAULT_TIMEOUT, DEVNET_DEFAULT_TOTAL_ACCOUNTS,
10+
ARGENT_CONTRACT_VERSION, ARGENT_MULTISIG_CONTRACT_VERSION, DEVNET_DEFAULT_DATA_GAS_PRICE,
11+
DEVNET_DEFAULT_GAS_PRICE, DEVNET_DEFAULT_PORT, DEVNET_DEFAULT_REQUEST_BODY_SIZE_LIMIT,
12+
DEVNET_DEFAULT_TIMEOUT, DEVNET_DEFAULT_TOTAL_ACCOUNTS,
1213
};
1314
use starknet_core::contract_class_choice::{AccountClassWrapper, AccountContractClassChoice};
1415
use starknet_core::random_number_generator::generate_u32_random_number;
@@ -55,6 +56,14 @@ pub(crate) struct Args {
5556
#[arg(help = "Specify the path to a Cairo Sierra artifact to be used by predeployed accounts;")]
5657
account_class_custom: Option<AccountClassWrapper>,
5758

59+
#[arg(long = "predeclare-argent")]
60+
#[arg(env = "PREDECLARE_ARGENT")]
61+
#[arg(help = format!(
62+
"If set, predeclares Argent account contract classes: regular ({ARGENT_CONTRACT_VERSION}) \
63+
and multisig ({ARGENT_MULTISIG_CONTRACT_VERSION}); does not affect account predeployment;"
64+
))]
65+
predeclare_argent: bool,
66+
5867
/// Initial balance of predeployed accounts
5968
#[arg(long = "initial-balance")]
6069
#[arg(env = "INITIAL_BALANCE")]
@@ -245,6 +254,7 @@ impl Args {
245254
block_number: self.fork_block,
246255
block_hash: None,
247256
},
257+
predeclare_argent: self.predeclare_argent,
248258
..Default::default()
249259
};
250260

@@ -613,7 +623,8 @@ mod tests {
613623
#[test]
614624
#[serial_test::serial]
615625
fn test_boolean_param_specification_via_env_vars() {
616-
let config_source = [("--lite-mode", "LITE_MODE")];
626+
let config_source =
627+
[("--lite-mode", "LITE_MODE"), ("--predeclare-argent", "PREDECLARE_ARGENT")];
617628

618629
let mut cli_args = vec!["--"];
619630
for (cli_param, _) in config_source {

crates/starknet-devnet/src/main.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ use server::rpc_core::request::{Id, RequestParams, Version};
1515
use server::server::serve_http_api_json_rpc;
1616
use starknet_core::account::Account;
1717
use starknet_core::constants::{
18-
ETH_ERC20_CONTRACT_ADDRESS, STRK_ERC20_CONTRACT_ADDRESS, UDC_CONTRACT_ADDRESS,
19-
UDC_CONTRACT_CLASS_HASH,
18+
ARGENT_CONTRACT_CLASS_HASH, ARGENT_MULTISIG_CONTRACT_CLASS_HASH, ETH_ERC20_CONTRACT_ADDRESS,
19+
STRK_ERC20_CONTRACT_ADDRESS, UDC_CONTRACT_ADDRESS, UDC_CONTRACT_CLASS_HASH,
2020
};
2121
use starknet_core::starknet::starknet_config::{
2222
BlockGenerationOn, DumpOn, ForkConfig, StarknetConfig,
@@ -116,6 +116,15 @@ fn log_predeployed_contracts(config: &StarknetConfig) {
116116
println!();
117117
}
118118

119+
fn log_other_predeclared_contracts(config: &StarknetConfig) {
120+
if config.predeclare_argent {
121+
println!("Predeclared Argent account classes");
122+
println!("Regular class hash: 0x{:X}", ARGENT_CONTRACT_CLASS_HASH);
123+
println!("Multisig class hash: 0x{:X}", ARGENT_MULTISIG_CONTRACT_CLASS_HASH);
124+
println!();
125+
}
126+
}
127+
119128
fn log_chain_id(chain_id: &ChainId) {
120129
println!("Chain ID: {} ({})", chain_id, chain_id.to_felt().to_hex_string());
121130
}
@@ -286,6 +295,7 @@ async fn main() -> Result<(), anyhow::Error> {
286295
};
287296

288297
log_predeployed_contracts(&starknet_config);
298+
log_other_predeclared_contracts(&starknet_config);
289299
log_chain_id(&starknet_config.chain_id);
290300

291301
let predeployed_accounts = api.starknet.lock().await.get_predeployed_accounts();

tests/integration/common/constants.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ pub const INVALID_ACCOUNT_SIERRA_PATH: &str =
7878

7979
/// Argent v0.4.0
8080
pub const ARGENT_ACCOUNT_CLASS_HASH: &str =
81-
"0x36078334509b514626504edc9fb252328d1a240e4e948bef8d0c08dff45927f";
81+
"0x036078334509b514626504edc9fb252328d1a240e4e948bef8d0c08dff45927f";
8282

8383
// Forking
8484
pub const INTEGRATION_SEPOLIA_HTTP_URL: &str =

tests/integration/common/utils.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,7 @@ use starknet_rs_providers::{JsonRpcClient, Provider};
2222
use starknet_rs_signers::LocalWallet;
2323

2424
use super::background_devnet::BackgroundDevnet;
25-
use super::constants::{
26-
ARGENT_ACCOUNT_CLASS_HASH, CAIRO_1_ACCOUNT_CONTRACT_SIERRA_HASH, CAIRO_1_CONTRACT_PATH,
27-
};
25+
use super::constants::{CAIRO_1_ACCOUNT_CONTRACT_SIERRA_HASH, CAIRO_1_CONTRACT_PATH};
2826
use super::safe_child::SafeChild;
2927

3028
pub enum ImpersonationAction {
@@ -285,11 +283,12 @@ pub async fn deploy_oz_account(
285283
/// Assumes the Argent account contract is declared in the target network.
286284
pub async fn deploy_argent_account(
287285
devnet: &BackgroundDevnet,
286+
class_hash: Felt,
288287
) -> Result<(DeployAccountTransactionResult, LocalWallet), anyhow::Error> {
289288
let signer = get_deployable_account_signer();
290289
let salt = Felt::THREE;
291290
let factory = ArgentAccountFactory::new(
292-
Felt::from_hex(ARGENT_ACCOUNT_CLASS_HASH)?,
291+
class_hash,
293292
devnet.json_rpc_client.chain_id().await?,
294293
None,
295294
signer.clone(),
@@ -301,7 +300,8 @@ pub async fn deploy_argent_account(
301300

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

306306
Ok((deployment_result, signer))
307307
}

tests/integration/test_account_selection.rs

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use std::sync::Arc;
22

33
use serde_json::json;
4+
use server::test_utils::assert_contains;
45
use starknet_core::utils::exported_test_utils::dummy_cairo_0_contract_class;
56
use starknet_rs_accounts::{Account, ExecutionEncoding, SingleOwnerAccount};
67
use starknet_rs_contract::ContractFactory;
@@ -12,7 +13,8 @@ use starknet_rs_signers::LocalWallet;
1213

1314
use crate::common::background_devnet::BackgroundDevnet;
1415
use crate::common::constants::{
15-
CAIRO_1_ACCOUNT_CONTRACT_SIERRA_HASH, CAIRO_1_ACCOUNT_CONTRACT_SIERRA_PATH, MAINNET_URL,
16+
ARGENT_ACCOUNT_CLASS_HASH, CAIRO_1_ACCOUNT_CONTRACT_SIERRA_HASH,
17+
CAIRO_1_ACCOUNT_CONTRACT_SIERRA_PATH, MAINNET_URL,
1618
};
1719
use crate::common::reqwest_client::GetReqwestSender;
1820
use crate::common::utils::{
@@ -112,13 +114,39 @@ async fn can_deploy_new_custom_oz_account() {
112114
can_declare_deploy_invoke_cairo1_using_account(&devnet, &signer, account_address).await;
113115
}
114116

117+
#[tokio::test]
118+
async fn argent_account_undeployable_by_default() {
119+
let devnet = BackgroundDevnet::spawn().await.unwrap();
120+
121+
let account_hash = Felt::from_hex_unchecked(ARGENT_ACCOUNT_CLASS_HASH);
122+
let error = deploy_argent_account(&devnet, account_hash).await.unwrap_err();
123+
assert_contains(
124+
&error.to_string(),
125+
&format!("Class with hash {ARGENT_ACCOUNT_CLASS_HASH} is not declared"),
126+
);
127+
}
128+
115129
#[tokio::test]
116130
/// Relying on forking: the origin network is expected to have the account class declared.
117-
async fn can_deploy_new_argent_account() {
131+
async fn can_deploy_instance_of_argent_account_via_fork() {
118132
let cli_args = ["--fork-network", MAINNET_URL];
119133
let devnet = BackgroundDevnet::spawn_with_additional_args(&cli_args).await.unwrap();
120134

121-
let (account_deployment, signer) = deploy_argent_account(&devnet).await.unwrap();
135+
let account_hash = Felt::from_hex_unchecked(ARGENT_ACCOUNT_CLASS_HASH);
136+
let (account_deployment, signer) = deploy_argent_account(&devnet, account_hash).await.unwrap();
137+
assert_tx_successful(&account_deployment.transaction_hash, &devnet.json_rpc_client).await;
138+
139+
let account_address = account_deployment.contract_address;
140+
can_declare_deploy_invoke_cairo1_using_account(&devnet, &signer, account_address).await;
141+
}
142+
143+
#[tokio::test]
144+
async fn can_deploy_new_argent_account_from_predeclared_class() {
145+
let devnet_args = ["--predeclare-argent"];
146+
let devnet = BackgroundDevnet::spawn_with_additional_args(&devnet_args).await.unwrap();
147+
148+
let account_hash = Felt::from_hex_unchecked(ARGENT_ACCOUNT_CLASS_HASH);
149+
let (account_deployment, signer) = deploy_argent_account(&devnet, account_hash).await.unwrap();
122150
assert_tx_successful(&account_deployment.transaction_hash, &devnet.json_rpc_client).await;
123151

124152
let account_address = account_deployment.contract_address;

0 commit comments

Comments
 (0)