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

Add type field to accounts file #2050

Merged
merged 11 commits into from
May 8, 2024
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Cast

#### Added

- New required flag `--type` to `account add` command

## [0.22.0] - 2024-04-17

### Forge
Expand Down
6 changes: 6 additions & 0 deletions crates/sncast/src/starknet_commands/account/add.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::starknet_commands::account::{
add_created_profile_to_configuration, prepare_account_json, write_account_to_accounts_file,
AccountType,
};
use anyhow::{ensure, Context, Result};
use camino::Utf8PathBuf;
Expand All @@ -23,6 +24,10 @@ pub struct Add {
#[clap(short, long, requires = "private_key_input")]
pub address: FieldElement,

/// Type of the account
#[clap(short = 't', long = "type")]
pub account_type: AccountType,
MaksymilianDemitraszek marked this conversation as resolved.
Show resolved Hide resolved

/// Class hash of the account
#[clap(short, long)]
pub class_hash: Option<FieldElement>,
Expand Down Expand Up @@ -97,6 +102,7 @@ pub async fn add(
add.address,
deployed,
legacy,
&add.account_type,
class_hash,
add.salt,
);
Expand Down
2 changes: 2 additions & 0 deletions crates/sncast/src/starknet_commands/account/create.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::starknet_commands::account::{
add_created_profile_to_configuration, prepare_account_json, write_account_to_accounts_file,
AccountType,
};
use anyhow::{anyhow, bail, Context, Result};
use camino::Utf8PathBuf;
Expand Down Expand Up @@ -143,6 +144,7 @@ async fn generate_account(
address,
false,
legacy,
&AccountType::Oz,
Some(class_hash),
Some(salt),
);
Expand Down
21 changes: 19 additions & 2 deletions crates/sncast/src/starknet_commands/account/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@ use crate::starknet_commands::account::delete::Delete;
use crate::starknet_commands::account::deploy::Deploy;
use anyhow::{anyhow, bail, Context, Result};
use camino::Utf8PathBuf;
use clap::{Args, Subcommand};
use clap::{Args, Subcommand, ValueEnum};
use configuration::{
find_config_file, load_global_config, search_config_upwards_relative_to, CONFIG_FILENAME,
};
use serde_json::json;
use sncast::{chain_id_to_network_name, decode_chain_id, helpers::configuration::CastConfig};
use starknet::{core::types::FieldElement, signers::SigningKey};
use std::{fs::OpenOptions, io::Write};
use std::{fmt, fs::OpenOptions, io::Write};
use toml::Value;

pub mod add;
Expand All @@ -34,18 +34,35 @@ pub enum Commands {
Delete(Delete),
}

#[derive(ValueEnum, Clone, Debug)]
pub enum AccountType {
Oz,
ddoktorski marked this conversation as resolved.
Show resolved Hide resolved
Argent,
}

impl fmt::Display for AccountType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
AccountType::Oz => write!(f, "open_zeppelin"),
AccountType::Argent => write!(f, "argent"),
}
}
}
MaksymilianDemitraszek marked this conversation as resolved.
Show resolved Hide resolved

pub fn prepare_account_json(
private_key: &SigningKey,
address: FieldElement,
deployed: bool,
legacy: bool,
account_type: &AccountType,
class_hash: Option<FieldElement>,
salt: Option<FieldElement>,
) -> serde_json::Value {
let mut account_json = json!({
"private_key": format!("{:#x}", private_key.secret_scalar()),
"public_key": format!("{:#x}", private_key.verifying_key().scalar()),
"address": format!("{address:#x}"),
"type": format!("{account_type}"),
"deployed": deployed,
"legacy": legacy,
});
Expand Down
80 changes: 75 additions & 5 deletions crates/sncast/tests/e2e/account/add.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,12 @@ use serde_json::json;
use shared::test_utils::output_assert::assert_stderr_contains;
use std::fs::{self, File};
use tempfile::tempdir;
use test_case::test_case;

#[test_case("oz", "open_zeppelin"; "oz_account_type")]
#[test_case("argent", "argent"; "argent_account_type")]
#[tokio::test]
pub async fn test_happy_case() {
pub async fn test_happy_case(input_account_type: &str, saved_type: &str) {
let tempdir = tempdir().expect("Unable to create a temporary directory");
let accounts_file = "accounts.json";

Expand All @@ -31,6 +34,8 @@ pub async fn test_happy_case() {
"0x456",
"--class-hash",
DEVNET_OZ_CLASS_HASH_CAIRO_0,
"--type",
input_account_type,
];

let snapbox = runner(&args).current_dir(tempdir.path());
Expand All @@ -55,6 +60,7 @@ pub async fn test_happy_case() {
"legacy": true,
"private_key": "0x456",
"public_key": "0x5f679dacd8278105bd3b84a15548fe84079068276b0e84d6cc093eb5430f063",
"type": saved_type
}
}
}
Expand All @@ -80,6 +86,8 @@ pub async fn test_existent_account_address() {
DEVNET_PREDEPLOYED_ACCOUNT_ADDRESS,
"--private-key",
"0x456",
"--type",
"oz",
];

runner(&args).current_dir(tempdir.path()).assert();
Expand All @@ -98,7 +106,8 @@ pub async fn test_existent_account_address() {
"deployed": true,
"legacy": false,
"private_key": "0x456",
"public_key": "0x5f679dacd8278105bd3b84a15548fe84079068276b0e84d6cc093eb5430f063"
"public_key": "0x5f679dacd8278105bd3b84a15548fe84079068276b0e84d6cc093eb5430f063",
"type": "open_zeppelin"
}
}
}
Expand Down Expand Up @@ -126,6 +135,8 @@ pub async fn test_existent_account_address_and_incorrect_class_hash() {
"0x456",
"--class-hash",
DEVNET_OZ_CLASS_HASH_CAIRO_0,
"--type",
"oz",
];

let snapbox = runner(&args).current_dir(tempdir.path());
Expand Down Expand Up @@ -156,6 +167,8 @@ pub async fn test_nonexistent_account_address_and_nonexistent_class_hash() {
"0x456",
"--class-hash",
"0x101",
"--type",
"oz",
];

let snapbox = runner(&args).current_dir(tempdir.path());
Expand Down Expand Up @@ -184,6 +197,8 @@ pub async fn test_nonexistent_account_address() {
"0x123",
"--private-key",
"0x456",
"--type",
"oz",
];

let snapbox = runner(&args).current_dir(tempdir.path());
Expand All @@ -194,6 +209,40 @@ pub async fn test_nonexistent_account_address() {
"});
}

#[tokio::test]
pub async fn test_nonexistent_account_type() {
let tempdir = tempdir().expect("Unable to create a temporary directory");
let accounts_file = "accounts.json";

let args = vec![
"--url",
URL,
"--accounts-file",
accounts_file,
"account",
"add",
"--name",
"my_account_add",
"--address",
"0x123",
"--private-key",
"0x456",
"--type",
"unknown_type",
];

let snapbox = runner(&args).current_dir(tempdir.path());
let output = snapbox.assert().failure();

assert_stderr_contains(
output,
indoc! {r"
error: invalid value 'unknown_type' for '--type <ACCOUNT_TYPE>'
[possible values: oz, argent]
"},
);
}
ddoktorski marked this conversation as resolved.
Show resolved Hide resolved

#[tokio::test]
pub async fn test_happy_case_add_profile() {
let tempdir = tempdir().expect("Failed to create a temporary directory");
Expand All @@ -218,6 +267,8 @@ pub async fn test_happy_case_add_profile() {
"0x3",
"--class-hash",
DEVNET_OZ_CLASS_HASH_CAIRO_0,
"--type",
"oz",
"--add-profile",
"my_account_add",
];
Expand Down Expand Up @@ -245,7 +296,8 @@ pub async fn test_happy_case_add_profile() {
"private_key": "0x2",
"public_key": "0x759ca09377679ecd535a81e83039658bf40959283187c654c5416f439403cf5",
"salt": "0x3",
"legacy": true
"legacy": true,
"type": "open_zeppelin"
}
}
}
Expand Down Expand Up @@ -276,6 +328,8 @@ pub async fn test_detect_deployed() {
DEVNET_PREDEPLOYED_ACCOUNT_ADDRESS,
"--private-key",
"0x5",
"--type",
"oz",
];

let snapbox = runner(&args).current_dir(tempdir.path());
Expand All @@ -299,7 +353,8 @@ pub async fn test_detect_deployed() {
"deployed": true,
"private_key": "0x5",
"public_key": "0x788435d61046d3eec54d77d25bd194525f4fa26ebe6575536bc6f656656b74c",
"legacy": false
"legacy": false,
"type": "open_zeppelin"
}
}
}
Expand All @@ -322,6 +377,8 @@ pub async fn test_invalid_public_key() {
"0x456",
"--public-key",
"0x457",
"--type",
"oz",
];

let snapbox = runner(&args);
Expand All @@ -348,6 +405,7 @@ pub async fn test_missing_arguments() {
indoc! {r"
error: the following required arguments were not provided:
--address <ADDRESS>
--type <ACCOUNT_TYPE>
<--private-key <PRIVATE_KEY>|--private-key-file <PRIVATE_KEY_FILE_PATH>>
"},
);
Expand Down Expand Up @@ -376,6 +434,8 @@ pub async fn test_private_key_from_file() {
private_key_file,
"--class-hash",
DEVNET_OZ_CLASS_HASH_CAIRO_0,
"--type",
"oz",
];

let snapbox = runner(&args).current_dir(temp_dir.path());
Expand All @@ -400,6 +460,7 @@ pub async fn test_private_key_from_file() {
"private_key": "0x456",
"public_key": "0x5f679dacd8278105bd3b84a15548fe84079068276b0e84d6cc093eb5430f063",
"class_hash": DEVNET_OZ_CLASS_HASH_CAIRO_0,
"type": "open_zeppelin"
}
}
}
Expand Down Expand Up @@ -444,6 +505,8 @@ pub async fn test_invalid_private_key_file_path() {
"0x123",
"--private-key-file",
"my_private_key",
"--type",
"oz",
];

let snapbox = runner(&args);
Expand Down Expand Up @@ -482,6 +545,8 @@ pub async fn test_invalid_private_key_in_file() {
"0x123",
"--private-key-file",
private_key_file,
"--type",
"oz",
];

let snapbox = runner(&args).current_dir(temp_dir.path());
Expand Down Expand Up @@ -517,6 +582,8 @@ pub async fn test_private_key_as_int_in_file() {
DEVNET_PREDEPLOYED_ACCOUNT_ADDRESS,
"--private-key-file",
private_key_file,
"--type",
"oz",
];

runner(&args)
Expand All @@ -538,7 +605,8 @@ pub async fn test_private_key_as_int_in_file() {
"legacy": false,
"private_key": "0x456",
"public_key": "0x5f679dacd8278105bd3b84a15548fe84079068276b0e84d6cc093eb5430f063",
"class_hash": DEVNET_OZ_CLASS_HASH_CAIRO_1
"class_hash": DEVNET_OZ_CLASS_HASH_CAIRO_1,
"type": "open_zeppelin"
}
}
}
Expand All @@ -565,6 +633,8 @@ pub async fn test_empty_config_add_profile() {
DEVNET_PREDEPLOYED_ACCOUNT_ADDRESS,
"--private-key",
"0x456",
"--type",
"oz",
"--add-profile",
"random",
];
Expand Down
2 changes: 2 additions & 0 deletions crates/sncast/tests/e2e/account/create.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ pub async fn test_happy_case() {
assert!(contents.contains("salt"));
assert!(contents.contains("class_hash"));
assert!(contents.contains("legacy"));
assert!(contents.contains("type"));
}

#[tokio::test]
Expand Down Expand Up @@ -123,6 +124,7 @@ pub async fn test_happy_case_generate_salt() {
assert!(contents.contains("salt"));
assert!(contents.contains("class_hash"));
assert!(contents.contains("legacy"));
assert!(contents.contains("type"));
}

#[tokio::test]
Expand Down
5 changes: 5 additions & 0 deletions docs/src/appendix/sncast/account/add.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ Required.

Address of the account.

## `--type, -t <ACCOUNT_TYPE>`
Required.

Type of the account. Possible values: oz, argent.

## `--class-hash, -c <CLASS_HASH>`
Optional.

Expand Down
3 changes: 2 additions & 1 deletion docs/src/starknet/account.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ and the second one deploys it to the network. After deployment, account can be u
To remove an account from the accounts file, you can use `sncast account delete`. Please note this only removes the account information stored locally - this will not remove the account from Starknet.

> 💡 **Info**
> Currently, only OpenZeppelin account creation is supported.
> Currently, only OpenZeppelin account creation and deployment is supported.
MaksymilianDemitraszek marked this conversation as resolved.
Show resolved Hide resolved

## Examples

Expand Down Expand Up @@ -149,6 +149,7 @@ $ sncast \
--address 0x1 \
--private-key 0x2 \
--class-hash 0x3 \
--type oz
```

For a detailed CLI description, see [account add command reference](../appendix/sncast/account/add.md).
Expand Down
3 changes: 2 additions & 1 deletion docs/src/starknet/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ Starknet Foundry `sncast` is a command line tool for performing Starknet RPC cal
> At the moment, `sncast` only supports contracts written in [Cairo](https://github.com/starkware-libs/cairo) v1 and v2.

> ⚠️ **Warning**
> Currently, only OpenZeppelin accounts are supported.
> Currently, support is only provided for accounts that use the default signature based on the [Stark curve](https://docs.starknet.io/documentation/architecture_and_concepts/Cryptography/stark-curve).
> It is recommended to use OpenZeppelin accounts.
MaksymilianDemitraszek marked this conversation as resolved.
Show resolved Hide resolved

## How to Use `sncast`

Expand Down
Loading