Skip to content

Commit

Permalink
feat: implement eth_get_balance (#990)
Browse files Browse the repository at this point in the history
* implement eth_get_balance

* add missing files

* made requested changes

* fmt

---------

Co-authored-by: enitrat <msaug@protonmail.com>
  • Loading branch information
saimeunt and enitrat authored Sep 30, 2024
1 parent 4ce7e2d commit 5759f30
Show file tree
Hide file tree
Showing 5 changed files with 42 additions and 14 deletions.
20 changes: 19 additions & 1 deletion crates/contracts/src/kakarot_core/eth_rpc.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use evm::backend::starknet_backend;
use evm::backend::validation::validate_eth_tx;
use evm::model::{TransactionResult, Address};
use evm::{EVMTrait};
use openzeppelin::token::erc20::interface::{IERC20CamelDispatcher, IERC20CamelDispatcherTrait};
use utils::constants::POW_2_53;
use utils::eth_transaction::transaction::Transaction;

Expand Down Expand Up @@ -123,7 +124,11 @@ pub impl EthRPC<
TContractState, impl KakarotState: KakarotCoreState<TContractState>, +Drop<TContractState>
> of IEthRPC<TContractState> {
fn eth_get_balance(self: @TContractState, address: EthAddress) -> u256 {
panic!("unimplemented")
let kakarot_state = KakarotState::get_state();
let starknet_address = kakarot_state.get_starknet_address(address);
let native_token_address = kakarot_state.get_native_token();
let native_token = IERC20CamelDispatcher { contract_address: native_token_address };
native_token.balanceOf(starknet_address)
}

fn eth_get_transaction_count(self: @TContractState, address: EthAddress) -> u64 {
Expand Down Expand Up @@ -218,6 +223,9 @@ fn is_view(self: @KakarotCore::ContractState) -> bool {
mod tests {
use crate::kakarot_core::KakarotCore;
use crate::kakarot_core::eth_rpc::IEthRPC;
use crate::kakarot_core::interface::IExtendedKakarotCoreDispatcherTrait;
use crate::test_utils::{setup_contracts_for_testing, fund_account_with_native_token};
use evm::test_utils::{sequencer_evm_address, evm_address};
use snforge_std::{start_cheat_chain_id_global, stop_cheat_chain_id_global};
use utils::constants::POW_2_53;

Expand All @@ -232,6 +240,16 @@ mod tests {
stop_cheat_chain_id_global();
}

#[test]
fn test_eth_get_balance() {
let (native_token, kakarot_core) = setup_contracts_for_testing();
// Uninitialized accounts should return a zero balance
assert_eq!(kakarot_core.eth_get_balance(evm_address()), 0);
let sequencer_starknet_address = kakarot_core.get_starknet_address(sequencer_evm_address());
// Fund an initialized account and make sure the balance is correct
fund_account_with_native_token(sequencer_starknet_address, native_token, 0x1);
assert_eq!(kakarot_core.eth_get_balance(sequencer_evm_address()), 0x1);
}

#[test]
fn test_eth_chain_id_returns_input_when_less_than_pow_2_53() {
Expand Down
3 changes: 3 additions & 0 deletions crates/contracts/src/kakarot_core/interface.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ pub trait IExtendedKakarotCore<TContractState> {
ref self: TContractState, evm_address: EthAddress
) -> ContractAddress;

/// Returns the balance of the specified address.
fn eth_get_balance(self: @TContractState, address: EthAddress) -> u256;

/// View entrypoint into the EVM
/// Performs view calls into the blockchain
/// It cannot modify the state of the chain
Expand Down
2 changes: 1 addition & 1 deletion crates/contracts/src/kakarot_core/kakarot.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ pub mod KakarotCore {
// @return starknet_address The Starknet Account Contract address
fn get_starknet_address(self: @ContractState, evm_address: EthAddress) -> ContractAddress {
let registered_starknet_address = self.address_registry(evm_address);
if (registered_starknet_address.is_zero()) {
if (!registered_starknet_address.is_zero()) {
return registered_starknet_address;
}

Expand Down
4 changes: 1 addition & 3 deletions crates/evm/src/backend/starknet_backend.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -121,9 +121,7 @@ pub fn fetch_original_storage(account: @Account, key: u256) -> u256 {
/// The balance of the given address.
pub fn fetch_balance(self: @Address) -> u256 {
let kakarot_state = KakarotCore::unsafe_new_contract_state();
let native_token_address = kakarot_state.get_native_token();
let native_token = IERC20CamelDispatcher { contract_address: native_token_address };
native_token.balanceOf(*self.starknet)
kakarot_state.eth_get_balance(*self.evm)
}


Expand Down
27 changes: 18 additions & 9 deletions crates/evm/src/backend/validation.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ use core::ops::SnapshotDeref;
use core::starknet::storage::{StoragePointerReadAccess};
use core::starknet::{get_caller_address};
use crate::gas;
use openzeppelin::token::erc20::interface::{IERC20CamelDispatcher, IERC20CamelDispatcherTrait};
use starknet::storage::StorageTrait;
use utils::eth_transaction::check_gas_fee;
use utils::eth_transaction::transaction::{Transaction, TransactionTrait};
Expand Down Expand Up @@ -46,10 +45,7 @@ pub fn validate_eth_tx(kakarot_state: @KakarotCore::ContractState, tx: Transacti
assert(gas_limit >= intrinsic_gas, 'Intrinsic gas > gas limit');

// Validate balance
let balance = IERC20CamelDispatcher {
contract_address: kakarot_storage.Kakarot_native_token_address.read()
}
.balanceOf(starknet_caller_address);
let balance = kakarot_state.eth_get_balance(account.get_evm_address());
let max_gas_fee = tx.gas_limit().into() * tx.max_fee_per_gas();
let tx_cost = tx.value() + max_gas_fee.into();
assert(tx_cost <= balance, 'Not enough ETH');
Expand All @@ -61,11 +57,10 @@ mod tests {
use contracts::kakarot_core::KakarotCore;
use core::num::traits::Bounded;
use core::ops::SnapshotDeref;

use core::starknet::ContractAddress;
use core::starknet::storage::StorageTrait;
use core::starknet::storage::{StorageTrait, StoragePathEntry};
use core::starknet::{EthAddress, ContractAddress};
use evm::gas;
use snforge_std::cheatcodes::storage::store_felt252;
use snforge_std::cheatcodes::storage::{store_felt252};
use snforge_std::{
start_mock_call, test_address, start_cheat_chain_id_global, store,
start_cheat_caller_address, mock_call
Expand All @@ -82,6 +77,7 @@ mod tests {
let kakarot_state = KakarotCore::unsafe_new_contract_state();
let kakarot_storage = kakarot_state.snapshot_deref().storage();
let kakarot_address = test_address();
let account_evm_address: EthAddress = 'account_evm_address'.try_into().unwrap();
let account_starknet_address = 'account_starknet_address'.try_into().unwrap();
let native_token_address = 'native_token_address'.try_into().unwrap();

Expand All @@ -95,10 +91,23 @@ mod tests {
store_felt252(kakarot_address, base_fee_storage, 1_000_000_000); // 1 Gwei
store_felt252(kakarot_address, block_gas_limit_storage, BLOCK_GAS_LIMIT.into());
store_felt252(kakarot_address, native_token_storage_address, native_token_address.into());
let map_entry_address = kakarot_storage
.Kakarot_evm_to_starknet_address
.entry(account_evm_address)
.deref()
.__storage_pointer_address__;
store(
kakarot_address,
map_entry_address.into(),
array![account_starknet_address.into()].span()
);

// Mock the calls to the account contract and the native token contract
start_cheat_caller_address(kakarot_address, account_starknet_address);
start_mock_call(account_starknet_address, selector!("get_nonce"), 0);
start_mock_call(
account_starknet_address, selector!("get_evm_address"), account_evm_address
);
start_mock_call(
native_token_address, selector!("balanceOf"), Bounded::<u256>::MAX
); // Min to pay for gas + value
Expand Down

0 comments on commit 5759f30

Please sign in to comment.