diff --git a/book/src/argument-resolution.md b/book/src/argument-resolution.md index 40a3f32..2242cad 100644 --- a/book/src/argument-resolution.md +++ b/book/src/argument-resolution.md @@ -31,14 +31,19 @@ The `const` scheme uses `content` as the key to look up a hard-coded table to co ### `selector` -The `selector` calculates the _Starknet Keccak_ hash for the content to derive the function entryponit. +The `selector` scheme calculates the _Starknet Keccak_ hash for the content to derive the function entryponit. + +### `storage` + +This scheme is currently the same as `selector`, but support for offsets and maps (e.g. `ERC20_balances[0x1234]`) might be added in the future to differentiate it. ## Scheme omission Normally, the `scheme:` prefix is required for opting in to argument resolution. However, there are a few exceptions: - the `addr:` prefix can be omitted when an address is expected; -- the `selector:` prefix can be omitted when a selector is expected. +- the `selector:` prefix can be omitted when a selector is expected; +- the `storage:` prefix can be omitted in the `starkli storage` command. As an example, consider the `starkli invoke` command. To use the `addr` and `selector` schemes, one would run: diff --git a/src/decode.rs b/src/decode.rs index 3875df9..5f0a3e1 100644 --- a/src/decode.rs +++ b/src/decode.rs @@ -2,7 +2,7 @@ use anyhow::Result; use num_bigint::BigUint; use starknet::core::{ types::FieldElement, - utils::{cairo_short_string_to_felt, get_selector_from_name}, + utils::{cairo_short_string_to_felt, get_selector_from_name, get_storage_var_address}, }; use crate::{address_book::AddressBookResolver, chain_id::ChainIdSource}; @@ -15,6 +15,7 @@ pub struct FeltDecoder { enum FallbackOption { Address, Selector, + Storage, None, } @@ -56,6 +57,19 @@ where } } + pub async fn decode_single_with_storage_fallback(&self, raw: &str) -> Result { + let decoded = self.decode_inner(raw, FallbackOption::Storage).await?; + + if decoded.len() == 1 { + Ok(decoded[0]) + } else { + Err(anyhow::anyhow!( + "expected 1 element but found {}", + decoded.len() + )) + } + } + pub async fn decode(&self, raw: &str) -> Result> { self.decode_inner(raw, FallbackOption::None).await } @@ -128,6 +142,11 @@ where Ok(vec![cairo_short_string_to_felt(short_string)?]) } else if let Some(selector) = raw.strip_prefix("selector:") { Ok(vec![get_selector_from_name(selector)?]) + } else if let Some(storage) = raw.strip_prefix("storage:") { + if storage.contains('[') || storage.contains(']') { + anyhow::bail!("cannot resolve storage address: maps not supported yet") + } + Ok(vec![get_storage_var_address(storage, &[])?]) } else { match raw.parse::() { Ok(value) => Ok(vec![value]), @@ -137,6 +156,12 @@ where Err(_) => Err(err.into()), }, FallbackOption::Selector => Ok(vec![get_selector_from_name(raw)?]), + FallbackOption::Storage => { + if raw.contains('[') || raw.contains(']') { + anyhow::bail!("cannot resolve storage address: maps not supported yet") + } + Ok(vec![get_storage_var_address(raw, &[])?]) + } FallbackOption::None => Err(err.into()), }, } diff --git a/src/subcommands/storage.rs b/src/subcommands/storage.rs index 281f97b..656b090 100644 --- a/src/subcommands/storage.rs +++ b/src/subcommands/storage.rs @@ -1,11 +1,15 @@ +use std::sync::Arc; + use anyhow::Result; use clap::Parser; use starknet::{ - core::types::{BlockId, BlockTag, FieldElement}, + core::types::{BlockId, BlockTag}, providers::Provider, }; -use crate::{verbosity::VerbosityArgs, ProviderArgs}; +use crate::{ + address_book::AddressBookResolver, decode::FeltDecoder, verbosity::VerbosityArgs, ProviderArgs, +}; #[derive(Debug, Parser)] pub struct Storage { @@ -23,9 +27,15 @@ impl Storage { pub async fn run(self) -> Result<()> { self.verbosity.setup_logging(); - let provider = self.provider.into_provider(); - let address = FieldElement::from_hex_be(&self.address)?; - let key = FieldElement::from_hex_be(&self.key)?; + let provider = Arc::new(self.provider.into_provider()); + let felt_decoder = FeltDecoder::new(AddressBookResolver::new(provider.clone())); + + let address = felt_decoder + .decode_single_with_addr_fallback(&self.address) + .await?; + let key = felt_decoder + .decode_single_with_storage_fallback(&self.key) + .await?; // TODO: allow custom block let value = provider