From 14d6036f02d9425a17b0976695e49aa836ef7001 Mon Sep 17 00:00:00 2001 From: Mathieu <60658558+enitrat@users.noreply.github.com> Date: Thu, 22 Aug 2024 17:49:41 +0200 Subject: [PATCH] feat: update starknet address computation method (#862) * feat: update starknet address computation method * fix deployment arguments of accounts during initialization * fix deploy_eoa test util --- crates/contracts/src/account_contract.cairo | 16 ++----- crates/contracts/src/test_utils.cairo | 5 +-- .../contracts/src/uninitialized_account.cairo | 43 +++++++++++++++---- crates/evm/src/backend/starknet_backend.cairo | 8 ++-- crates/utils/src/helpers.cairo | 8 ++-- 5 files changed, 49 insertions(+), 31 deletions(-) diff --git a/crates/contracts/src/account_contract.cairo b/crates/contracts/src/account_contract.cairo index 36aceae56..616c85703 100644 --- a/crates/contracts/src/account_contract.cairo +++ b/crates/contracts/src/account_contract.cairo @@ -9,10 +9,7 @@ use core::starknet::{ContractAddress, EthAddress, ClassHash}; #[starknet::interface] pub trait IAccount { 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; @@ -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; - impl OwnableInternal = ownable_component::InternalImpl; @@ -120,19 +115,16 @@ pub mod AccountContract { #[abi(embed_v0)] impl Account of super::IAccount { 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 diff --git a/crates/contracts/src/test_utils.cairo b/crates/contracts/src/test_utils.cairo index 30284d090..d962de3b6 100644 --- a/crates/contracts/src/test_utils.cairo +++ b/crates/contracts/src/test_utils.cairo @@ -129,14 +129,13 @@ pub(crate) fn deploy_contract_account(evm_address: EthAddress, bytecode: Span IAccountDispatcher { - let kakarot_address = get_contract_address(); - let calldata: Span = [kakarot_address.into(), eoa_address.into()].span(); + let calldata: Span = [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'); diff --git a/crates/contracts/src/uninitialized_account.cairo b/crates/contracts/src/uninitialized_account.cairo index 9258fde3f..2e44295f2 100644 --- a/crates/contracts/src/uninitialized_account.cairo +++ b/crates/contracts/src/uninitialized_account.cairo @@ -19,24 +19,49 @@ trait IAccount { #[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; + impl OwnableInternal = ownable_component::InternalImpl; + #[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) { + 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(); } diff --git a/crates/evm/src/backend/starknet_backend.cairo b/crates/evm/src/backend/starknet_backend.cairo index 327e47fb2..c87c6926a 100644 --- a/crates/evm/src/backend/starknet_backend.cairo +++ b/crates/evm/src/backend/starknet_backend.cairo @@ -44,11 +44,13 @@ fn deploy(evm_address: EthAddress) -> Result { 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 = [kakarot_address.into(), evm_address.into()].span(); + let calldata: Span = [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(); diff --git a/crates/utils/src/helpers.cairo b/crates/utils/src/helpers.cairo index 573123850..d2ce39238 100644 --- a/crates/utils/src/helpers.cairo +++ b/crates/utils/src/helpers.cairo @@ -761,22 +761,22 @@ pub impl ResultExImpl, +Drop> of ResultExTrait { 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)