Skip to content
This repository has been archived by the owner on Jan 9, 2025. It is now read-only.

Put balance in Account instead of State #807

Merged
merged 5 commits into from
Nov 22, 2023
Merged
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
236 changes: 236 additions & 0 deletions src/data_availability/starknet.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,236 @@
// SPDX-License-Identifier: MIT

%lang starknet

from starkware.cairo.common.alloc import alloc
from starkware.cairo.common.bool import FALSE
from starkware.cairo.common.cairo_builtins import HashBuiltin
from starkware.cairo.common.dict_access import DictAccess
from starkware.cairo.common.uint256 import Uint256
from starkware.starknet.common.syscalls import (
emit_event,
get_contract_address,
deploy as deploy_syscall,
)

from kakarot.account import Account
from kakarot.events import evm_contract_deployed
from kakarot.interfaces.interfaces import IERC20, IContractAccount, IAccount
from kakarot.model import model
from kakarot.state import State
from kakarot.storages import (
native_token_address,
contract_account_class_hash,
account_proxy_class_hash,
evm_to_starknet_address,
)

namespace Starknet {
// @notice Commit the current state to the underlying data backend (here, Starknet)
// @dev Works on State.Summary to make sure only finalized states are committed.
// @param self The pointer to the State
func commit{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(

Check warning on line 32 in src/data_availability/starknet.cairo

View check run for this annotation

Codecov / codecov/patch

src/data_availability/starknet.cairo#L32

Added line #L32 was not covered by tests
self: State.Summary*
) {
// Accounts
Internals._commit_accounts(self.accounts_start, self.accounts);

Check warning on line 36 in src/data_availability/starknet.cairo

View check run for this annotation

Codecov / codecov/patch

src/data_availability/starknet.cairo#L36

Added line #L36 was not covered by tests

// Events
Internals._emit_events(self.events_len, self.events);

Check warning on line 39 in src/data_availability/starknet.cairo

View check run for this annotation

Codecov / codecov/patch

src/data_availability/starknet.cairo#L39

Added line #L39 was not covered by tests

// Transfers
let (native_token_address_) = native_token_address.read();
Internals._transfer_eth(native_token_address_, self.transfers_len, self.transfers);

Check warning on line 43 in src/data_availability/starknet.cairo

View check run for this annotation

Codecov / codecov/patch

src/data_availability/starknet.cairo#L42-L43

Added lines #L42 - L43 were not covered by tests

return ();

Check warning on line 45 in src/data_availability/starknet.cairo

View check run for this annotation

Codecov / codecov/patch

src/data_availability/starknet.cairo#L45

Added line #L45 was not covered by tests
}

// @notice Deploy a new account proxy
// @dev Deploy an instance of an account
// @param evm_address The Ethereum address which will be controlling the account
// @param class_hash The hash of the implemented account (eoa/contract)
// @return account_address The Starknet Account Proxy address
func deploy{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
class_hash: felt, evm_address: felt
) -> (account_address: felt) {
alloc_locals;
let (kakarot_address: felt) = get_contract_address();
let (_account_proxy_class_hash: felt) = account_proxy_class_hash.read();
let (constructor_calldata: felt*) = alloc();
let (starknet_address) = deploy_syscall(
_account_proxy_class_hash,
contract_address_salt=evm_address,
constructor_calldata_size=0,
constructor_calldata=constructor_calldata,
deploy_from_zero=0,
);
assert constructor_calldata[0] = kakarot_address;
assert constructor_calldata[1] = evm_address;
IAccount.initialize(starknet_address, class_hash, 2, constructor_calldata);
evm_contract_deployed.emit(evm_address, starknet_address);
evm_to_starknet_address.write(evm_address, starknet_address);
return (account_address=starknet_address);
}

// @notice Return the bytecode of a given account
// @dev Return empty if the account is not deployed
// @param evm_address The address of the account
// @return bytecode_len The len of the bytecode
// @return bytecode The bytecode
func get_bytecode{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
evm_address: felt

Check warning on line 81 in src/data_availability/starknet.cairo

View check run for this annotation

Codecov / codecov/patch

src/data_availability/starknet.cairo#L80-L81

Added lines #L80 - L81 were not covered by tests
) -> (bytecode_len: felt, bytecode: felt*) {
let (starknet_address) = evm_to_starknet_address.read(evm_address);

Check warning on line 83 in src/data_availability/starknet.cairo

View check run for this annotation

Codecov / codecov/patch

src/data_availability/starknet.cairo#L83

Added line #L83 was not covered by tests

if (starknet_address == 0) {
let (bytecode: felt*) = alloc();
return (0, bytecode);

Check warning on line 87 in src/data_availability/starknet.cairo

View check run for this annotation

Codecov / codecov/patch

src/data_availability/starknet.cairo#L85-L87

Added lines #L85 - L87 were not covered by tests
}

let (bytecode_len, bytecode) = IAccount.bytecode(starknet_address);
return (bytecode_len, bytecode);

Check warning on line 91 in src/data_availability/starknet.cairo

View check run for this annotation

Codecov / codecov/patch

src/data_availability/starknet.cairo#L90-L91

Added lines #L90 - L91 were not covered by tests
}
}

namespace Internals {
// @notice Iterate through the accounts dict and commit them
// @dev Account is deployed here if it doesn't exist already
// @param accounts_start The dict start pointer
// @param accounts_end The dict end pointer
func _commit_accounts{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
accounts_start: DictAccess*, accounts_end: DictAccess*

Check warning on line 101 in src/data_availability/starknet.cairo

View check run for this annotation

Codecov / codecov/patch

src/data_availability/starknet.cairo#L100-L101

Added lines #L100 - L101 were not covered by tests
) {
alloc_locals;
if (accounts_start == accounts_end) {
return ();

Check warning on line 105 in src/data_availability/starknet.cairo

View check run for this annotation

Codecov / codecov/patch

src/data_availability/starknet.cairo#L103-L105

Added lines #L103 - L105 were not covered by tests
}

let (starknet_address) = Account.compute_starknet_address(accounts_start.key);
let account = cast(accounts_start.new_value, Account.Summary*);
_commit_account(account, starknet_address);

Check warning on line 110 in src/data_availability/starknet.cairo

View check run for this annotation

Codecov / codecov/patch

src/data_availability/starknet.cairo#L108-L110

Added lines #L108 - L110 were not covered by tests

_commit_accounts(accounts_start + DictAccess.SIZE, accounts_end);

Check warning on line 112 in src/data_availability/starknet.cairo

View check run for this annotation

Codecov / codecov/patch

src/data_availability/starknet.cairo#L112

Added line #L112 was not covered by tests

return ();

Check warning on line 114 in src/data_availability/starknet.cairo

View check run for this annotation

Codecov / codecov/patch

src/data_availability/starknet.cairo#L114

Added line #L114 was not covered by tests
}

// @notice Commit the account to the storage backend at given address
// @dev Account is deployed here if it doesn't exist already
// @dev Works on Account.Summary to make sure only finalized accounts are committed.
// @param self The pointer to the Account
// @param starknet_address A starknet address to commit to
// @notice Iterate through the storage dict and update the Starknet storage
func _commit_account{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
self: Account.Summary*, starknet_address: felt

Check warning on line 124 in src/data_availability/starknet.cairo

View check run for this annotation

Codecov / codecov/patch

src/data_availability/starknet.cairo#L123-L124

Added lines #L123 - L124 were not covered by tests
) {
alloc_locals;

Check warning on line 126 in src/data_availability/starknet.cairo

View check run for this annotation

Codecov / codecov/patch

src/data_availability/starknet.cairo#L126

Added line #L126 was not covered by tests

let starknet_account_exists = Account.is_registered(self.address);

Check warning on line 128 in src/data_availability/starknet.cairo

View check run for this annotation

Codecov / codecov/patch

src/data_availability/starknet.cairo#L128

Added line #L128 was not covered by tests

// Case new Account
if (starknet_account_exists == 0) {

Check warning on line 131 in src/data_availability/starknet.cairo

View check run for this annotation

Codecov / codecov/patch

src/data_availability/starknet.cairo#L131

Added line #L131 was not covered by tests
// Just casting the Summary into an Account to apply has_code_or_nonce
// cf Summary note: like an Account, but frozen after squashing all dicts
// There is no reason to have has_code_or_nonce available in the public API
// for Account.Summary, but safe to use here
let code_or_nonce = Account.has_code_or_nonce(cast(self, model.Account*));

Check warning on line 136 in src/data_availability/starknet.cairo

View check run for this annotation

Codecov / codecov/patch

src/data_availability/starknet.cairo#L136

Added line #L136 was not covered by tests

if (code_or_nonce != FALSE) {

Check warning on line 138 in src/data_availability/starknet.cairo

View check run for this annotation

Codecov / codecov/patch

src/data_availability/starknet.cairo#L138

Added line #L138 was not covered by tests
// Deploy accounts
let (class_hash) = contract_account_class_hash.read();
Starknet.deploy(class_hash, self.address);

Check warning on line 141 in src/data_availability/starknet.cairo

View check run for this annotation

Codecov / codecov/patch

src/data_availability/starknet.cairo#L140-L141

Added lines #L140 - L141 were not covered by tests
// If SELFDESTRUCT, stops here to leave the account empty
if (self.selfdestruct != 0) {
return ();

Check warning on line 144 in src/data_availability/starknet.cairo

View check run for this annotation

Codecov / codecov/patch

src/data_availability/starknet.cairo#L143-L144

Added lines #L143 - L144 were not covered by tests
}

// Write bytecode
IContractAccount.write_bytecode(starknet_address, self.code_len, self.code);

Check warning on line 148 in src/data_availability/starknet.cairo

View check run for this annotation

Codecov / codecov/patch

src/data_availability/starknet.cairo#L148

Added line #L148 was not covered by tests
// Set nonce
IContractAccount.set_nonce(starknet_address, self.nonce);

Check warning on line 150 in src/data_availability/starknet.cairo

View check run for this annotation

Codecov / codecov/patch

src/data_availability/starknet.cairo#L150

Added line #L150 was not covered by tests
// Save storages
_save_storage(starknet_address, self.storage_start, self.storage);
return ();

Check warning on line 153 in src/data_availability/starknet.cairo

View check run for this annotation

Codecov / codecov/patch

src/data_availability/starknet.cairo#L152-L153

Added lines #L152 - L153 were not covered by tests
} else {
// Touched an undeployed address in a CALL, do nothing
return ();

Check warning on line 156 in src/data_availability/starknet.cairo

View check run for this annotation

Codecov / codecov/patch

src/data_availability/starknet.cairo#L156

Added line #L156 was not covered by tests
}
}

// Case existing Account and SELFDESTRUCT
if (self.selfdestruct != 0) {
IContractAccount.selfdestruct(contract_address=starknet_address);
return ();

Check warning on line 163 in src/data_availability/starknet.cairo

View check run for this annotation

Codecov / codecov/patch

src/data_availability/starknet.cairo#L161-L163

Added lines #L161 - L163 were not covered by tests
}

let (account_type) = IAccount.account_type(contract_address=starknet_address);
if (account_type == 'EOA') {
return ();

Check warning on line 168 in src/data_availability/starknet.cairo

View check run for this annotation

Codecov / codecov/patch

src/data_availability/starknet.cairo#L166-L168

Added lines #L166 - L168 were not covered by tests
}

// Set nonce
IContractAccount.set_nonce(starknet_address, self.nonce);

Check warning on line 172 in src/data_availability/starknet.cairo

View check run for this annotation

Codecov / codecov/patch

src/data_availability/starknet.cairo#L172

Added line #L172 was not covered by tests
// Save storages
Internals._save_storage(starknet_address, self.storage_start, self.storage);

Check warning on line 174 in src/data_availability/starknet.cairo

View check run for this annotation

Codecov / codecov/patch

src/data_availability/starknet.cairo#L174

Added line #L174 was not covered by tests

return ();

Check warning on line 176 in src/data_availability/starknet.cairo

View check run for this annotation

Codecov / codecov/patch

src/data_availability/starknet.cairo#L176

Added line #L176 was not covered by tests
}

// @notice Iterates through a list of events and emits them.
// @param events_len The length of the events array.
// @param events The array of Event structs that are emitted via the `emit_event` syscall.
func _emit_events{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(

Check warning on line 182 in src/data_availability/starknet.cairo

View check run for this annotation

Codecov / codecov/patch

src/data_availability/starknet.cairo#L182

Added line #L182 was not covered by tests
events_len: felt, events: model.Event*
) {
alloc_locals;

Check warning on line 185 in src/data_availability/starknet.cairo

View check run for this annotation

Codecov / codecov/patch

src/data_availability/starknet.cairo#L185

Added line #L185 was not covered by tests

if (events_len == 0) {
return ();

Check warning on line 188 in src/data_availability/starknet.cairo

View check run for this annotation

Codecov / codecov/patch

src/data_availability/starknet.cairo#L187-L188

Added lines #L187 - L188 were not covered by tests
}

let event: model.Event = [events];
emit_event(
keys_len=event.topics_len, keys=event.topics, data_len=event.data_len, data=event.data
);

Check warning on line 194 in src/data_availability/starknet.cairo

View check run for this annotation

Codecov / codecov/patch

src/data_availability/starknet.cairo#L192-L194

Added lines #L192 - L194 were not covered by tests

_emit_events(events_len - 1, events + model.Event.SIZE);
return ();

Check warning on line 197 in src/data_availability/starknet.cairo

View check run for this annotation

Codecov / codecov/patch

src/data_availability/starknet.cairo#L196-L197

Added lines #L196 - L197 were not covered by tests
}

// @notice Iterates through a list of Transfer and makes them
// @dev Transfers are made last so as to have all accounts created beforehand.
// @param transfers_len The length of the transfers array.
// @param transfers The array of Transfer.
func _transfer_eth{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
token_address: felt, transfers_len: felt, transfers: model.Transfer*

Check warning on line 205 in src/data_availability/starknet.cairo

View check run for this annotation

Codecov / codecov/patch

src/data_availability/starknet.cairo#L204-L205

Added lines #L204 - L205 were not covered by tests
) {
if (transfers_len == 0) {
return ();

Check warning on line 208 in src/data_availability/starknet.cairo

View check run for this annotation

Codecov / codecov/patch

src/data_availability/starknet.cairo#L207-L208

Added lines #L207 - L208 were not covered by tests
}

let transfer = [transfers];
IERC20.transferFrom(
token_address, transfer.sender.starknet, transfer.recipient.starknet, transfer.amount
);
return _transfer_eth(token_address, transfers_len - 1, transfers + model.Transfer.SIZE);

Check warning on line 215 in src/data_availability/starknet.cairo

View check run for this annotation

Codecov / codecov/patch

src/data_availability/starknet.cairo#L212-L215

Added lines #L212 - L215 were not covered by tests
}

// @notice Iterates through the storage dict and update Contract Account storage.
// @param starknet_address The address of the Starknet account to save into.
// @param storage_start The dict start pointer
// @param storage_end The dict end pointer
func _save_storage{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
starknet_address: felt, storage_start: DictAccess*, storage_end: DictAccess*

Check warning on line 223 in src/data_availability/starknet.cairo

View check run for this annotation

Codecov / codecov/patch

src/data_availability/starknet.cairo#L222-L223

Added lines #L222 - L223 were not covered by tests
) {
if (storage_start == storage_end) {
return ();

Check warning on line 226 in src/data_availability/starknet.cairo

View check run for this annotation

Codecov / codecov/patch

src/data_availability/starknet.cairo#L225-L226

Added lines #L225 - L226 were not covered by tests
}
let value = cast(storage_start.new_value, Uint256*);

Check warning on line 228 in src/data_availability/starknet.cairo

View check run for this annotation

Codecov / codecov/patch

src/data_availability/starknet.cairo#L228

Added line #L228 was not covered by tests

IContractAccount.write_storage(
contract_address=starknet_address, storage_addr=storage_start.key, value=[value]
);

Check warning on line 232 in src/data_availability/starknet.cairo

View check run for this annotation

Codecov / codecov/patch

src/data_availability/starknet.cairo#L230-L232

Added lines #L230 - L232 were not covered by tests

return _save_storage(starknet_address, storage_start + DictAccess.SIZE, storage_end);

Check warning on line 234 in src/data_availability/starknet.cairo

View check run for this annotation

Codecov / codecov/patch

src/data_availability/starknet.cairo#L234

Added line #L234 was not covered by tests
}
}
Loading
Loading