Skip to content

Commit

Permalink
feat: update starknet address computation method (#862)
Browse files Browse the repository at this point in the history
* feat: update starknet address computation method

* fix deployment arguments of accounts during initialization

* fix deploy_eoa test util
  • Loading branch information
enitrat authored Aug 22, 2024
1 parent 041acc9 commit 14d6036
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 31 deletions.
16 changes: 4 additions & 12 deletions crates/contracts/src/account_contract.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,7 @@ use core::starknet::{ContractAddress, EthAddress, ClassHash};
#[starknet::interface]
pub trait IAccount<TContractState> {
fn initialize(
ref self: TContractState,
kakarot_address: ContractAddress,
evm_address: EthAddress,
implementation_class: ClassHash
ref self: TContractState, evm_address: EthAddress, implementation_class: ClassHash
);
fn get_implementation(self: @TContractState) -> ClassHash;
fn get_evm_address(self: @TContractState) -> EthAddress;
Expand Down Expand Up @@ -74,10 +71,8 @@ pub mod AccountContract {

// Add ownable component
component!(path: ownable_component, storage: ownable, event: OwnableEvent);

#[abi(embed_v0)]
impl OwnableImpl = ownable_component::Ownable<ContractState>;

impl OwnableInternal = ownable_component::InternalImpl<ContractState>;


Expand Down Expand Up @@ -120,19 +115,16 @@ pub mod AccountContract {
#[abi(embed_v0)]
impl Account of super::IAccount<ContractState> {
fn initialize(
ref self: ContractState,
kakarot_address: ContractAddress,
evm_address: EthAddress,
implementation_class: ClassHash
ref self: ContractState, evm_address: EthAddress, implementation_class: ClassHash
) {
assert(!self.Account_is_initialized.read(), 'Account already initialized');
self.Account_is_initialized.write(true);
self.ownable.initializer(kakarot_address);

self.Account_evm_address.write(evm_address);
self.Account_implementation.write(implementation_class);

let kakarot_address = self.ownable.owner();
let kakarot = IKakarotCoreDispatcher { contract_address: kakarot_address };

let native_token = kakarot.get_native_token();
// To internally perform value transfer of the network's native
// token (which conforms to the ERC20 standard), we need to give the
Expand Down
5 changes: 2 additions & 3 deletions crates/contracts/src/test_utils.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -129,14 +129,13 @@ pub(crate) fn deploy_contract_account(evm_address: EthAddress, bytecode: Span<u8
}

fn deploy_eoa(eoa_address: EthAddress) -> IAccountDispatcher {
let kakarot_address = get_contract_address();
let calldata: Span<felt252> = [kakarot_address.into(), eoa_address.into()].span();
let calldata: Span<felt252> = [1, eoa_address.into()].span();

let (starknet_address, _) = deploy_syscall(
UninitializedAccount::TEST_CLASS_HASH.try_into().unwrap(),
eoa_address.into(),
calldata,
true
deploy_from_zero: false
)
.expect('failed to deploy EOA');

Expand Down
43 changes: 34 additions & 9 deletions crates/contracts/src/uninitialized_account.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -19,24 +19,49 @@ trait IAccount<TContractState> {

#[starknet::contract]
pub mod UninitializedAccount {
use contracts::components::ownable::IOwnable;
use contracts::components::ownable::ownable_component::InternalTrait;
use contracts::components::ownable::ownable_component;
use contracts::kakarot_core::interface::{IKakarotCoreDispatcher, IKakarotCoreDispatcherTrait};
use core::starknet::SyscallResultTrait;
use core::starknet::syscalls::replace_class_syscall;
use core::starknet::syscalls::{library_call_syscall, replace_class_syscall};
use core::starknet::{ContractAddress, EthAddress, ClassHash, get_caller_address};
use super::{IAccountLibraryDispatcher, IAccountDispatcherTrait};

// Add ownable component
component!(path: ownable_component, storage: ownable, event: OwnableEvent);
#[abi(embed_v0)]
impl OwnableImpl = ownable_component::Ownable<ContractState>;
impl OwnableInternal = ownable_component::InternalImpl<ContractState>;

#[storage]
struct Storage {}
struct Storage {
#[substorage(v0)]
ownable: ownable_component::Storage,
}

#[event]
#[derive(Drop, starknet::Event)]
enum Event {
OwnableEvent: ownable_component::Event
}

#[constructor]
fn constructor(
ref self: ContractState, kakarot_address: ContractAddress, evm_address: EthAddress
) {
let implementation_class = IKakarotCoreDispatcher { contract_address: kakarot_address }
fn constructor(ref self: ContractState, mut calldata: Array<felt252>) {
let owner_address: ContractAddress = get_caller_address();
self.ownable.initializer(owner_address);
let implementation_class = IKakarotCoreDispatcher { contract_address: owner_address }
.get_account_contract_class_hash();

IAccountLibraryDispatcher { class_hash: implementation_class }
.initialize(kakarot_address, evm_address, implementation_class);
//TODO: Difference from KakarotZero in that the account contract takes the class
//implementation to write it in storage,
// as it is not a transparent proxy in Cairo1
calldata.append(implementation_class.into());
library_call_syscall(
class_hash: implementation_class,
function_selector: selector!("initialize"),
calldata: calldata.span()
)
.unwrap_syscall();

replace_class_syscall(implementation_class).unwrap_syscall();
}
Expand Down
8 changes: 5 additions & 3 deletions crates/evm/src/backend/starknet_backend.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,13 @@ fn deploy(evm_address: EthAddress) -> Result<Address, EVMError> {

let mut kakarot_state = KakarotCore::unsafe_new_contract_state();
let uninitialized_account_class_hash = kakarot_state.uninitialized_account_class_hash();
let kakarot_address = get_contract_address();
let calldata: Span<felt252> = [kakarot_address.into(), evm_address.into()].span();
let calldata: Span<felt252> = [1, evm_address.into()].span();

let (starknet_address, _) = deploy_syscall(
uninitialized_account_class_hash, evm_address.into(), calldata, true
uninitialized_account_class_hash,
contract_address_salt: evm_address.into(),
calldata: calldata,
deploy_from_zero: false
)
.unwrap_syscall();

Expand Down
8 changes: 4 additions & 4 deletions crates/utils/src/helpers.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -761,22 +761,22 @@ pub impl ResultExImpl<T, E, +Drop<T>, +Drop<E>> of ResultExTrait<T, E> {
pub fn compute_starknet_address(
kakarot_address: ContractAddress, evm_address: EthAddress, class_hash: ClassHash
) -> ContractAddress {
// Deployer is always 0
// Deployer is always Kakarot (current contract)
// pedersen(a1, a2, a3) is defined as:
// pedersen(pedersen(pedersen(a1, a2), a3), len([a1, a2, a3]))
// https://github.com/starkware-libs/cairo-lang/blob/master/src/starkware/cairo/common/hash_state.py#L6
// https://github.com/xJonathanLEI/starknet-rs/blob/master/starknet-core/src/crypto.rs#L49
// Constructor Calldata For an Account, the constructor calldata is:
// [kakarot_address, evm_address]
// [1, evm_address]
let constructor_calldata_hash = PedersenTrait::new(0)
.update_with(kakarot_address)
.update_with(1)
.update_with(evm_address)
.update(2)
.finalize();

let hash = PedersenTrait::new(0)
.update_with(CONTRACT_ADDRESS_PREFIX)
.update_with(0)
.update_with(kakarot_address)
.update_with(evm_address)
.update_with(class_hash)
.update_with(constructor_calldata_hash)
Expand Down

0 comments on commit 14d6036

Please sign in to comment.