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

Build with scarb for declare #2138

Merged
merged 39 commits into from
Jul 3, 2023
Merged
Show file tree
Hide file tree
Changes from 31 commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
a728631
remove redundant mut
Jun 26, 2023
26d1f69
call args
Jun 26, 2023
d13966e
declare args
Jun 26, 2023
32f7402
invoke args
Jun 26, 2023
1935e1e
add parsing contract addr
Jun 26, 2023
964f27b
parse calldata
Jun 26, 2023
03085c9
Merge branch 'master' into kb/improve-cli-args
Jun 26, 2023
58d44c4
Merge branch 'master' into kb/improve-cli-args
Jun 27, 2023
292f092
address fdbck
Jun 27, 2023
5dce670
build with scarb for declare
Jun 27, 2023
d4670b6
Merge branch 'master' into kb/cli-build-with-scarb
Jun 28, 2023
36eff60
Merge branch 'master' into kb/improve-cli-args
Jun 28, 2023
9efa310
Merge branch 'kb/improve-cli-args' into kb/cli-build-with-scarb
Jun 28, 2023
b9d5156
remove log
Jun 28, 2023
f2c1dc2
move account file check outside of match case
Jun 28, 2023
c9efb8e
start err msgs from capital letter
Jun 28, 2023
05adf8a
remove resolved todo
Jun 28, 2023
563be52
fix
Jun 28, 2023
1c5b959
fix executing scarb command
Jun 28, 2023
a46bd90
change err msg
Jun 28, 2023
1239607
revert change with default path
Jun 29, 2023
d1af2fa
add todo issue for starknet artifacts
Jun 29, 2023
34ef305
expect => context
Jun 29, 2023
2587f26
fix bug
Jun 29, 2023
38e8c6d
remove tests
Jun 29, 2023
c18edf2
fdbck
Jun 29, 2023
90758f1
Merge branch 'master' into kb/cli-build-with-scarb
Jun 29, 2023
038d08f
take sierra and casm from starknet artifacts
Jun 29, 2023
a0f6a1e
pull network from scarb config
Jun 29, 2023
1fbe96f
address feedback
Jun 29, 2023
c3aca46
Merge branch 'master' into kb/cli-build-with-scarb
Jun 29, 2023
a55b3af
add todo for using scareb command
Jun 30, 2023
bfb5eac
use scarb release build
Jun 30, 2023
e81c3f3
Merge branch 'master' into kb/cli-build-with-scarb
Jul 3, 2023
693ca2b
remove redundant import
Jul 3, 2023
cc68f5b
move parse number to lib
Jul 3, 2023
76be159
remove todo 2147
Jul 3, 2023
2501533
revert claps
Jul 3, 2023
d1be504
revert network changes
Jul 3, 2023
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
20 changes: 20 additions & 0 deletions cast/Cargo.lock

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

1 change: 1 addition & 0 deletions cast/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ starknet = { git = "https://github.com/xJonathanLEI/starknet-rs" }
tokio = { version = "1.28.2", features = ["full"] }
url = "2.2.2"
rand = "0.8.5"
scarb-metadata = "1.4.2"

[dev-dependencies]
ctor = "0.2.2"
Expand Down
2 changes: 1 addition & 1 deletion cast/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ pub fn get_account<'a>(
&account_info.address
)
})?;
let mut account = SingleOwnerAccount::new(provider, signer, address, network.get_chain_id());
let account = SingleOwnerAccount::new(provider, signer, address, network.get_chain_id());

Ok(account)
}
Expand Down
38 changes: 32 additions & 6 deletions cast/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ use camino::Utf8PathBuf;
use cast::{get_account, get_block_id, get_network, get_provider, print_formatted};
use clap::{Parser, Subcommand};
use console::style;
use scarb_metadata;
use std::env::current_dir;

mod starknet_commands;

Expand All @@ -24,6 +26,7 @@ struct Cli {
account: String,

/// Path to the file holding accounts info, defaults to ~/.starknet_accounts/starknet_open_zeppelin_accounts.json
// TODO #2147
karol-bisztyga marked this conversation as resolved.
Show resolved Hide resolved
#[clap(
short = 'f',
long = "accounts-file",
Expand Down Expand Up @@ -57,12 +60,36 @@ enum Commands {
#[tokio::main]
async fn main() -> Result<()> {
let cli = Cli::parse();

// todo: #2052 take network from scarb config if flag not provided
karol-bisztyga marked this conversation as resolved.
Show resolved Hide resolved
let network_name = cli.network.unwrap_or_else(|| {
let mut maybe_network_name = None;
if let Some(network_name) = cli.network {
maybe_network_name = Some(network_name);
} else {
let metadata = scarb_metadata::MetadataCommand::new()
.inherit_stderr()
.current_dir(current_dir().expect("failed to read current directory"))
.no_deps()
.exec()
.unwrap();
if metadata.packages.len() != 1 {
anyhow::bail!("invalid number of packages obtained from scarb metadata");
}
let package = &metadata.packages[0];
if let Some(tool) = &package.manifest_metadata.tool {
if let Some(protostar_tool) = tool.get("protostar") {
if let Some(network) = protostar_tool.get("network") {
if let Some(network_str) = network.as_str() {
maybe_network_name = Some(network_str.to_string());
}
}
}
}
karol-bisztyga marked this conversation as resolved.
Show resolved Hide resolved
}
if maybe_network_name.is_none() {
// todo: #2107
karol-bisztyga marked this conversation as resolved.
Show resolved Hide resolved
eprintln!("{}", style("No --network flag passed!").red());
std::process::exit(1);
karol-bisztyga marked this conversation as resolved.
Show resolved Hide resolved
});
};
let network_name = maybe_network_name.expect("Could not find network neither in args nor in scarb config");
let network = get_network(&network_name)?;
let provider = get_provider(&cli.rpc_url)?;

Expand All @@ -72,8 +99,7 @@ async fn main() -> Result<()> {
get_account(&cli.account, &cli.accounts_file_path, &provider, &network)?;

let declared_contract = starknet_commands::declare::declare(
&declare.sierra_contract_path,
&declare.casm_contract_path,
&declare.contract,
declare.max_fee,
&mut account,
)
Expand Down
9 changes: 4 additions & 5 deletions cast/src/starknet_commands/call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@ use starknet::core::utils::get_selector_from_name;
use starknet::providers::jsonrpc::HttpTransport;
use starknet::providers::{JsonRpcClient, Provider};

use crate::starknet_commands::helpers::parse_number;

#[derive(Args)]
#[command(about = "Call a contract instance on Starknet", long_about = None)]
pub struct Call {
/// Address of the called contract (hex)
#[clap(short = 'a', long = "contract-address")]
pub contract_address: String,

/// Name of the contract function to be called
#[clap(short = 'f', long = "function-name")]
karol-bisztyga marked this conversation as resolved.
Show resolved Hide resolved
pub function_name: String,

/// Arguments of the called function (list of hex)
Expand All @@ -36,14 +36,13 @@ pub async fn call(
block_id: &BlockId,
) -> Result<Vec<FieldElement>> {
let function_call = FunctionCall {
contract_address: FieldElement::from_hex_be(contract_address)
.context("Failed to convert contract address to FieldElement")?,
contract_address: parse_number(contract_address)?,
entry_point_selector: get_selector_from_name(func_name)
.context("Failed to convert entry point selector to FieldElement")?,
calldata: calldata
.iter()
.map(|x| {
FieldElement::from_hex_be(x).context("Failed to convert calldata to FieldElement")
parse_number(x).context("Failed to convert calldata to FieldElement")
})
.collect::<Result<Vec<_>>>()?,
};
Expand Down
101 changes: 86 additions & 15 deletions cast/src/starknet_commands/declare.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,41 +15,112 @@ use starknet::{
signers::LocalWallet,
};
use std::sync::Arc;
use std::process::{Command, Stdio};
use serde::Deserialize;
use std::path::PathBuf;

#[allow(dead_code)]
#[derive(Deserialize)]
struct ScarbStarknetArtifacts {
version: u32,
contracts: Vec<ScarbStarknetContract>,
}

#[allow(dead_code)]
#[derive(Deserialize)]
struct ScarbStarknetContract {
id: String,
package_name: String,
contract_name: String,
artifacts: ScarbStarknetContractArtifact,
}

#[allow(dead_code)]
#[derive(Deserialize)]
war-in marked this conversation as resolved.
Show resolved Hide resolved
struct ScarbStarknetContractArtifact {
sierra: PathBuf,
casm: Option<PathBuf>,
karol-bisztyga marked this conversation as resolved.
Show resolved Hide resolved
}

#[derive(Args)]
#[command(about = "Declare a contract to starknet", long_about = None)]
pub struct Declare {
/// Path to the sierra compiled contract
#[clap(short = 's', long = "sierra-contract-path")]
pub sierra_contract_path: Utf8PathBuf,

/// Path to the casm compiled contract
#[clap(short = 'c', long = "casm-contract-path")]
pub casm_contract_path: Utf8PathBuf,
/// contract name
pub contract: String,

/// Max fee for the transaction. If not provided, max fee will be automatically estimated
#[clap(short, long)]
pub max_fee: Option<u128>,
}

pub async fn declare(
karol-bisztyga marked this conversation as resolved.
Show resolved Hide resolved
sierra_contract_path: &Utf8PathBuf,
casm_contract_path: &Utf8PathBuf,
contract_name: &str,
max_fee: Option<u128>,
account: &mut SingleOwnerAccount<&JsonRpcClient<HttpTransport>, LocalWallet>,
) -> Result<DeclareTransactionResult> {
let contract_name: String = contract_name.to_string();
let command_result = Command::new("scarb")
.current_dir(std::env::current_dir().context("Failed to obtain current dir")?)
.arg("build")
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.output()
.context("Failed to start building contracts with Scarb")?;
let result_code = command_result.status.code().context("failed to obtain status code from scarb build")?;
if result_code != 0 {
anyhow::bail!("scarb build returned non-zero exit code: {}", result_code);
}

// TODO #2141 improve handling starknet artifacts
let current_dir = std::env::current_dir()
.context("Failed to get current directory")?
.join("target/dev");
karol-bisztyga marked this conversation as resolved.
Show resolved Hide resolved
let mut paths = std::fs::read_dir(&current_dir)
.context("Failed to read ./target/dev, scarb build probably failed")?;

let starknet_artifacts = &paths
.find_map(|path| match path {
Ok(path) => {
let name = path.file_name().into_string().ok()?;
name.contains("starknet_artifacts").then_some(path)
}
Err(_) => None,
})
.context("Failed to find starknet_artifacts.json file")?;
let starknet_artifacts = std::fs::read_to_string(starknet_artifacts.path())
.context("Failed to read starknet_artifacts.json contents")?;
let starknet_artifacts: ScarbStarknetArtifacts =
serde_json::from_str(starknet_artifacts.as_str())
.context("Failed to parse starknet_artifacts.json contents")?;

let sierra_path = starknet_artifacts.contracts.iter().find_map(|contract| {
if contract.contract_name == contract_name {
return Some(contract.artifacts.sierra.clone());
}
None
}).unwrap_or_else(|| panic!("Failed to find contract {contract_name} in starknet_artifacts.json"));
let sierra_contract_path = current_dir.join(sierra_path);

let casm_path = starknet_artifacts.contracts.iter().find_map(|contract| {
if contract.contract_name == contract_name {
return Some(contract.artifacts.casm.clone());
}
None
}).unwrap_or_else(|| panic!("Failed to find contract {contract_name} in starknet_artifacts.json")).unwrap();
let casm_contract_path = current_dir.join(casm_path);

let contract_definition: SierraClass = {
let file_contents = std::fs::read(sierra_contract_path)
.with_context(|| format!("Failed to read contract file: {sierra_contract_path}"))?;
let file_contents = std::fs::read(sierra_contract_path.clone())
.with_context(|| format!("Failed to read contract file: {}", sierra_contract_path.to_str().expect("failed to convert sierra_contract_path to string")))?;
serde_json::from_slice(&file_contents).with_context(|| {
format!("Failed to parse contract definition: {sierra_contract_path}")
format!("Failed to parse contract definition: {}", sierra_contract_path.to_str().expect("failed to convert sierra_contract_path to string"))
})?
};
let casm_contract_definition: CompiledClass = {
let file_contents = std::fs::read(casm_contract_path)
.with_context(|| format!("Failed to read contract file: {casm_contract_path}"))?;
let file_contents = std::fs::read(casm_contract_path.clone())
.with_context(|| format!("Failed to read contract file: {}", casm_contract_path.to_str().expect("failed to convert casm_contract_path to string")))?;
serde_json::from_slice(&file_contents)
.with_context(|| format!("Failed to parse contract definition: {casm_contract_path}"))?
.with_context(|| format!("Failed to parse contract definition: {}", casm_contract_path.to_str().expect("failed to convert casm_contract_path to string")))?
};

let casm_class_hash = casm_contract_definition.class_hash()?;
Expand Down
10 changes: 10 additions & 0 deletions cast/src/starknet_commands/helpers.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
use starknet::core::types::FieldElement;
karol-bisztyga marked this conversation as resolved.
Show resolved Hide resolved
use anyhow::Result;

pub fn parse_number(number_as_str: &str) -> Result<FieldElement> {
let contract_address = match &number_as_str[..2] {
"0x" => FieldElement::from_hex_be(number_as_str)?,
_ => FieldElement::from_dec_str(number_as_str)?,
};
Ok(contract_address)
}
8 changes: 4 additions & 4 deletions cast/src/starknet_commands/invoke.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@ use starknet::providers::jsonrpc::HttpTransport;
use starknet::providers::JsonRpcClient;
use starknet::signers::LocalWallet;

use crate::starknet_commands::helpers::parse_number;

#[derive(Args)]
#[command(about = "Invoke a contract on Starknet")]
pub struct Invoke {
/// Address of contract to invoke
#[clap(short = 'a', long)]
pub contract_address: String,

/// Name of the function to invoke
#[clap(short, long)]
pub entry_point_name: String,

/// Calldata for the invoked function
Expand All @@ -38,12 +38,12 @@ pub async fn invoke(
account: &mut SingleOwnerAccount<&JsonRpcClient<HttpTransport>, LocalWallet>,
) -> Result<FieldElement> {
let call = Call {
to: FieldElement::from_hex_be(contract_address)?,
to: parse_number(contract_address)?,
selector: get_selector_from_name(entry_point_name)?,
calldata: calldata
.iter()
.map(|cd| {
FieldElement::from_hex_be(cd).context("Failed to convert calldata to FieldElement")
parse_number(cd).context("Failed to convert calldata to FieldElement")
})
.collect::<Result<Vec<_>>>()?,
};
Expand Down
2 changes: 2 additions & 0 deletions cast/src/starknet_commands/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
mod helpers;

pub mod call;
pub mod declare;
pub mod deploy;
Expand Down