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

invoke V3 #1530

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
3 changes: 2 additions & 1 deletion src/bin/hive_chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@ async fn main() -> eyre::Result<()> {
std::env::set_var("STARKNET_NETWORK", STARKNET_RPC_URL);

// Prepare the relayer
let relayer_balance = starknet_provider.balance_at(args.relayer_address, BlockId::Tag(BlockTag::Latest)).await?;
let relayer_balance =
starknet_provider.balance_at_native(args.relayer_address, BlockId::Tag(BlockTag::Latest)).await?;
let relayer_balance = into_via_try_wrapper!(relayer_balance)?;

let relayer = Relayer::new(
Expand Down
54 changes: 54 additions & 0 deletions src/models/felt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,28 @@ impl TryFrom<Felt252Wrapper> for Address {
}
}

impl TryFrom<Felt252Wrapper> for u64 {
type Error = EthereumDataFormatError;

fn try_from(felt: Felt252Wrapper) -> Result<Self, Self::Error> {
match felt.to_be_digits() {
[0, 0, 0, d] => Ok(d),
_ => Err(EthereumDataFormatError::Primitive),
}
}
}

impl TryFrom<Felt252Wrapper> for u128 {
type Error = EthereumDataFormatError;

fn try_from(felt: Felt252Wrapper) -> Result<Self, Self::Error> {
match felt.to_be_digits() {
[0, 0, d1, d2] => Ok(Self::from(d1) << 64 | Self::from(d2)),
_ => Err(EthereumDataFormatError::Primitive),
}
}
}
Comment on lines +55 to +75
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't we use directly this

https://github.com/starknet-io/types-rs/blob/7ef30234da7957f7585ea832d57d13083c76995c/crates/starknet-types-core/src/felt/primitive_conversions.rs#L91-L96

by doing something like

let a = Felt252Wrapper;
let b: u64 = a.0.try_into().expect("");


impl From<B256> for Felt252Wrapper {
fn from(value: B256) -> Self {
Self(Felt::from_bytes_be(value.as_ref()))
Expand Down Expand Up @@ -191,4 +213,36 @@ mod tests {
// When
assert_eq!(Felt252Wrapper::from(hash).0, Felt::ZERO,);
}

#[test]
fn test_u64_try_from_felt_should_pass() {
let value = Felt::from(u64::MAX);

let value = u64::try_from(Felt252Wrapper::from(value)).unwrap();
assert_eq!(u64::MAX, value);
}

#[test]
fn test_u64_try_from_felt_should_fail() {
let value = Felt::from(u64::MAX) + Felt::ONE;

let value = u64::try_from(Felt252Wrapper::from(value));
assert!(value.is_err());
}

#[test]
fn test_u128_try_from_felt_should_pass() {
let value = Felt::from(u128::MAX);

let value = u128::try_from(Felt252Wrapper::from(value)).unwrap();
assert_eq!(u128::MAX, value);
}

#[test]
fn test_u128_try_from_felt_should_fail() {
let value = Felt::from(u128::MAX) + Felt::ONE;

let value = u128::try_from(Felt252Wrapper::from(value));
assert!(value.is_err());
}
}
2 changes: 1 addition & 1 deletion src/pool/mempool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ impl<SP: starknet::providers::Provider + Send + Sync + Clone + 'static> AccountM
// Get the balance of the address for the Pending block.
self.eth_client
.starknet_provider()
.balance_at(account_address, starknet::core::types::BlockId::Tag(BlockTag::Pending))
.strk_balance_at(account_address, starknet::core::types::BlockId::Tag(BlockTag::Pending))
.await
.map_err(Into::into)
}
Expand Down
9 changes: 6 additions & 3 deletions src/providers/eth_provider/starknet/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,13 @@ pub mod relayer;

use cainome::rs::abigen_legacy;
use starknet::core::types::Felt;
use std::sync::LazyLock;

abigen_legacy!(ERC20, "./.kakarot/artifacts/ERC20.json");

/// Starknet native token address
pub static STARKNET_NATIVE_TOKEN: LazyLock<Felt> =
LazyLock::new(|| Felt::from_hex("0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7").unwrap());
pub static STARKNET_NATIVE_TOKEN: Felt =
Felt::from_hex_unchecked("0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d");

/// Starknet eth token address
pub static STARKNET_ETH: Felt =
Felt::from_hex_unchecked("0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7");
36 changes: 29 additions & 7 deletions src/providers/eth_provider/starknet/relayer.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
use crate::{
constants::STARKNET_CHAIN_ID,
models::transaction::transaction_data_to_starknet_calldata,
models::{felt::Felt252Wrapper, transaction::transaction_data_to_starknet_calldata},
providers::eth_provider::{
database::{ethereum::EthereumTransactionStore, types::transaction::EthStarknetHashes, Database},
error::{SignatureError, TransactionError},
error::{KakarotError, SignatureError, TransactionError},
provider::EthApiResult,
starknet::kakarot_core::{starknet_address, EXECUTE_FROM_OUTSIDE},
},
};
use reth_primitives::TransactionSigned;
use starknet::{
accounts::{Account, ConnectedAccount, ExecutionEncoding, ExecutionV1, SingleOwnerAccount},
accounts::{Account, ConnectedAccount, ExecutionEncoding, ExecutionV3, SingleOwnerAccount},
core::types::{BlockTag, Felt, NonZeroFelt},
providers::Provider,
signers::{LocalWallet, SigningKey},
Expand All @@ -37,7 +37,7 @@ static RELAYER_SIGNER: LazyLock<LocalWallet> = LazyLock::new(|| {
pub struct Relayer<SP: Provider + Send + Sync> {
/// The account used to sign and broadcast the transaction
account: SingleOwnerAccount<SP, LocalWallet>,
/// The balance of the relayer
/// The balance of the relayer in STRK
balance: Felt,
/// The database used to store the relayer's transaction hashes map (Ethereum -> Starknet)
database: Option<Arc<Database>>,
Expand Down Expand Up @@ -76,7 +76,7 @@ where

// Construct the call
let call = starknet::core::types::Call { to: eoa_address, selector: *EXECUTE_FROM_OUTSIDE, calldata };
let mut execution = ExecutionV1::new(vec![call], &self.account);
let mut execution = ExecutionV3::new(vec![call], &self.account);

// Fetch the relayer nonce from the Starknet provider
let relayer_nonce = self
Expand All @@ -88,9 +88,31 @@ where

execution = execution.nonce(relayer_nonce);

// We set the max fee to the balance of the account / 5. This means that the account could
// Fetch the current gas price from the Starknet provider
// TODO: fetch the gas price in background and cache it
let fri_gas_price = self
.account
.provider()
.get_block_with_tx_hashes(starknet::core::types::BlockId::Tag(BlockTag::Pending))
.await
.map_err(KakarotError::from)?
.l1_gas_price()
.price_in_fri;

// We set the gas to the balance of the account / 5. This means that the account could
// send up to 5 transactions before hitting a feeder gateway error.
execution = execution.max_fee(self.balance.floor_div(&NonZeroFelt::from_felt_unchecked(5.into())));
let max_fee = self.balance.floor_div(&NonZeroFelt::from_felt_unchecked(5.into()));

let max_gas_price = fri_gas_price.double();
let max_gas = max_fee.floor_div(&NonZeroFelt::from_felt_unchecked(if max_gas_price == Felt::ZERO {
Felt::from(1)
} else {
max_gas_price
}));

execution = execution
.gas(Felt252Wrapper::from(max_gas).try_into()?)
.gas_price(Felt252Wrapper::from(max_gas_price).try_into()?);

let prepared = execution.prepared().map_err(|_| SignatureError::SigningFailure)?;
let res = prepared.send().await.map_err(|err| TransactionError::Broadcast(err.into()))?;
Expand Down
2 changes: 1 addition & 1 deletion src/providers/eth_provider/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ where
// Convert the optional Ethereum block ID to a Starknet block ID.
let starknet_block_id = self.to_starknet_block_id(block_id).await?;
// Get the balance of the address at the given block ID.
self.starknet_provider().balance_at(starknet_address(address), starknet_block_id).await.map_err(Into::into)
self.starknet_provider().eth_balance_at(starknet_address(address), starknet_block_id).await.map_err(Into::into)
}

async fn storage_at(
Expand Down
52 changes: 41 additions & 11 deletions src/providers/sn_provider/starknet_provider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use crate::{
into_via_wrapper,
providers::eth_provider::{
error::ExecutionError,
starknet::{ERC20Reader, STARKNET_NATIVE_TOKEN},
starknet::{ERC20Reader, STARKNET_ETH, STARKNET_NATIVE_TOKEN},
utils::{class_hash_not_declared, contract_not_found},
},
};
Expand Down Expand Up @@ -38,25 +38,55 @@ where
Self { provider }
}

/// Retrieves the balance of a Starknet address for a specified block.
/// Retrieves the balance of the parent token for a Starknet address.
///
/// This method interacts with the Starknet native token contract to query the balance of the given
/// address at a specific block.
/// # Arguments
/// * `token_address` - The address of the token contract
/// * `address` - The address to check the balance for
/// * `block_id` - The block ID at which to check the balance
///
/// If the contract is not deployed or the class hash is not declared, a balance of 0 is returned
/// instead of an error.
pub async fn balance_at(&self, address: Felt, block_id: BlockId) -> Result<U256, ExecutionError> {
// Create a new `ERC20Reader` instance for the Starknet native token
let eth_contract = ERC20Reader::new(*STARKNET_NATIVE_TOKEN, &self.provider);
/// # Returns
/// * `Result<U256, ExecutionError>` - The balance as a U256 value or an execution error
pub async fn eth_balance_at(&self, address: Felt, block_id: BlockId) -> Result<U256, ExecutionError> {
self.balance_at(STARKNET_ETH, address, block_id).await
}

/// Retrieves the balance of the native Starknet token for an address.
///
/// # Arguments
/// * `token_address` - The address of the token contract
/// * `address` - The address to check the balance for
/// * `block_id` - The block ID at which to check the balance
///
/// # Returns
/// * `Result<U256, ExecutionError>` - The balance as a U256 value or an execution error
pub async fn strk_balance_at(&self, address: Felt, block_id: BlockId) -> Result<U256, ExecutionError> {
self.balance_at(STARKNET_NATIVE_TOKEN, address, block_id).await
}

/// Internal method to retrieve the balance of any ERC20 token for a Starknet address.
///
/// # Arguments
/// * `token_address` - The address of the ERC20 token contract
/// * `address` - The address to check the balance for
/// * `block_id` - The block ID at which to check the balance
///
/// # Returns
/// * `Result<U256, ExecutionError>` - The balance as a U256 value or an execution error
///
/// # Notes
/// - Returns a balance of 0 if the contract is not deployed or the class hash is not declared
/// - The balance is returned as a U256, combining low and high 128-bit components
async fn balance_at(&self, token_address: Felt, address: Felt, block_id: BlockId) -> Result<U256, ExecutionError> {
// Create a new `ERC20Reader` instance for the Starknet parent native token
let eth_contract = ERC20Reader::new(token_address, &self.provider);

// Call the `balanceOf` method on the contract for the given address and block ID, awaiting the result
let span = tracing::span!(tracing::Level::INFO, "sn::balance");
let res = eth_contract.balanceOf(&address).block_id(block_id).call().instrument(span).await;

// Check if the contract was not found or the class hash not declared,
// returning a default balance of 0 if true.
// The native token contract should be deployed on Kakarot, so this should not happen
// We want to avoid errors in this case and return a default balance of 0
if contract_not_found(&res) || class_hash_not_declared(&res) {
return Ok(Default::default());
}
Expand Down
4 changes: 2 additions & 2 deletions src/test_utils/eoa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ impl<P: Provider + Send + Sync + Clone> KakarotEOA<P> {
let relayer_balance = self
.eth_client
.starknet_provider()
.balance_at(self.relayer.address(), BlockId::Tag(BlockTag::Latest))
.balance_at_native(self.relayer.address(), BlockId::Tag(BlockTag::Latest))
.await?;
let relayer_balance = into_via_try_wrapper!(relayer_balance)?;

Expand Down Expand Up @@ -226,7 +226,7 @@ impl<P: Provider + Send + Sync + Clone> KakarotEOA<P> {
let relayer_balance = self
.eth_client
.starknet_provider()
.balance_at(self.relayer.address(), BlockId::Tag(BlockTag::Latest))
.balance_at_native(self.relayer.address(), BlockId::Tag(BlockTag::Latest))
.await?;
let relayer_balance = into_via_try_wrapper!(relayer_balance)?;

Expand Down
6 changes: 3 additions & 3 deletions tests/tests/eth_provider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -746,7 +746,7 @@ async fn test_send_raw_transaction(#[future] katana_empty: Katana, _setup: ()) {
// Prepare the relayer
let relayer_balance = eth_client
.starknet_provider()
.balance_at(katana.eoa.relayer.address(), BlockId::Tag(BlockTag::Latest))
.balance_at_native(katana.eoa.relayer.address(), BlockId::Tag(BlockTag::Latest))
.await
.expect("Failed to get relayer balance");
let relayer_balance = into_via_try_wrapper!(relayer_balance).expect("Failed to convert balance");
Expand Down Expand Up @@ -1018,7 +1018,7 @@ async fn test_send_raw_transaction_pre_eip_155(#[future] katana_empty: Katana, _
let relayer_balance = katana
.eth_client
.starknet_provider()
.balance_at(katana.eoa.relayer.address(), BlockId::Tag(BlockTag::Latest))
.balance_at_native(katana.eoa.relayer.address(), BlockId::Tag(BlockTag::Latest))
.await
.expect("Failed to get relayer balance");
let relayer_balance = into_via_try_wrapper!(relayer_balance).expect("Failed to convert balance");
Expand Down Expand Up @@ -1391,7 +1391,7 @@ async fn test_transaction_by_hash(#[future] katana_empty: Katana, _setup: ()) {
let relayer_balance = katana_empty
.eth_client
.starknet_provider()
.balance_at(katana_empty.eoa.relayer.address(), BlockId::Tag(BlockTag::Latest))
.balance_at_native(katana_empty.eoa.relayer.address(), BlockId::Tag(BlockTag::Latest))
.await
.expect("Failed to get relayer balance");
let relayer_balance = into_via_try_wrapper!(relayer_balance).expect("Failed to convert balance");
Expand Down
Loading