Skip to content

Commit

Permalink
Kakarot Ethereum Account Abstraction (#422)
Browse files Browse the repository at this point in the history
The Kakarot Ethereum Account Abstraction (KETHAA) is a set of two
contracts, a deployer and the account. The deployer is in charge of
deploying the accounts and the account manages the EVM transaction
verification and execution. For the moment only EIP-1559 transactions
are considered valid and no tx is executed. Few more things will be
added (see related issues). Not final state.

## Pull request type

Please check the type of change your PR introduces:

- [ ] Bugfix
- [x] Feature
- [ ] Code style update (formatting, renaming)
- [ ] Refactoring (no functional changes, no api changes)
- [ ] Build related changes
- [ ] Documentation content changes
- [ ] Other (please describe):

## What is the current behavior?

<!-- Please describe the current behavior that you are modifying, or
link to a relevant issue. -->

Resolves #388 

## What is the new behavior?

Kakarot itself is not altered.

## Other information

Time spent on this PR:  10 days

Co-authored-by: kakarot CI <sayajin-labs@users.noreply.github.com>
  • Loading branch information
Flydexo and kakarot CI committed Jan 14, 2023
1 parent 601a480 commit 9514bc0
Show file tree
Hide file tree
Showing 24 changed files with 2,963 additions and 1,563 deletions.
15 changes: 9 additions & 6 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,20 @@ build:
$(MAKE) clean
poetry run starknet-compile ./src/kakarot/kakarot.cairo --output build/kakarot.json --cairo_path ./src --abi build/kakarot_abi.json
poetry run starknet-compile ./src/kakarot/accounts/contract/contract_account.cairo --output build/contract_account.json --cairo_path ./src --abi build/contract_account_abi.json
poetry run starknet-compile ./src/kakarot/accounts/eoa/externally_owned_account.cairo --output build/externally_owned_account.json --cairo_path ./src --abi build/externally_owned_account_abi.json
poetry run starknet-compile ./src/kakarot/accounts/registry/account/account_registry.cairo --output build/account_registry.json --cairo_path ./src --abi build/account_registry_abi.json
poetry run starknet-compile ./src/kakarot/accounts/registry/blockhash/blockhash_registry.cairo --output build/blockhash_registry.json --cairo_path ./src --abi build/blockhash_registry_abi.json
poetry run starknet-compile ./src/kakarot/accounts/eoa/aa/externally_owned_account.cairo --account_contract --output build/externally_owned_account.json --cairo_path ./src --abi build/externally_owned_account_abi.json
poetry run starknet-compile ./src/kakarot/accounts/eoa/deployer/deployer.cairo --output build/kethaa_deployer.json --cairo_path ./src --abi build/kethaa_deployer_abi.json


build-mac:
$(MAKE) clean
starknet-compile ./src/kakarot/kakarot.cairo --output build/kakarot.json --cairo_path ./src --abi build/kakarot_abi.json
starknet-compile ./src/kakarot/accounts/contract/contract_account.cairo --output build/contract_account.json --cairo_path ./src --abi build/contract_account_abi.json
starknet-compile ./src/kakarot/accounts/eoa/externally_owned_account.cairo --output build/externally_owned_account.json --cairo_path ./src --abi build/externally_owned_account_abi.json
starknet-compile ./src/kakarot/accounts/registry/account/account_registry.cairo --output build/account_registry.json --cairo_path ./src --abi build/account_registry_abi.json
starknet-compile ./src/kakarot/accounts/registry/blockhash/blockhash_registry.cairo --output build/blockhash_registry.json --cairo_path ./src --abi build/blockhash_registry_abi.json
starknet-compile ./src/kakarot/accounts/eoa/aa/account.cairo --account_contract --output build/kethaa.json --cairo_path ./src --abi build/kethaa_abi.json
starknet-compile ./src/kakarot/accounts/eoa/deployer/deployer.cairo --output build/kethaa_deployer.json --cairo_path ./src --abi build/kethaa_deployer_abi.json

setup:
poetry install --no-root
Expand All @@ -34,17 +37,17 @@ test-unit: build-sol

run-test-log: build-sol
poetry run pytest -k $(test) --log-cli-level=INFO -vvv

run-test: build-sol
poetry run pytest -k $(test)

run-test-mark-log: build-sol
poetry run pytest -m $(mark) --log-cli-level=INFO -vvv

run-test-mark: build-sol
poetry run pytest -m $(mark)
poetry run pytest -m $(mark)

deploy:
deploy:
poetry run python ./scripts/deploy_kakarot.py

format:
Expand Down Expand Up @@ -74,6 +77,6 @@ check-resources:

get-blockhashes:
poetry run python scripts/get_latest_blockhashes.py

build-sol:
forge build --contracts tests/integration/solidity_contracts -o tests/integration/solidity_contracts/build
Binary file modified docs/callgraphs/account_registry.gv.pdf
Binary file not shown.
Binary file modified docs/callgraphs/blockhash_registry.gv.pdf
Binary file not shown.
Binary file modified docs/callgraphs/contract_account.gv.pdf
Binary file not shown.
296 changes: 269 additions & 27 deletions docs/callgraphs/externally_owned_account.gv

Large diffs are not rendered by default.

Binary file modified docs/callgraphs/externally_owned_account.gv.pdf
Binary file not shown.
3,103 changes: 1,637 additions & 1,466 deletions docs/callgraphs/kakarot.gv

Large diffs are not rendered by default.

Binary file modified docs/callgraphs/kakarot.gv.pdf
Binary file not shown.
76 changes: 76 additions & 0 deletions docs/callgraphs/kethaa_deployer.gv
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
// Call flow graph
digraph kethaa_deployer {
graph [fontname="Helvetica,Arial,sans-serif" fontsize=20 layout=dot newrank=true rankdir=LR]
node [fontname="Helvetica,Arial,sans-serif" pencolor="#00000044" shape="rect, plaintext" style=filled]
edge [arrowsize=0.5 fontname="Helvetica,Arial,sans-serif" labeldistance=3 labelfontcolor="#00000080" penwidth=2]
0 [label="starkware.cairo.common.alloc.alloc" color="" fillcolor=lightcoral shape=oval style=filled]
3 [label="starkware.cairo.common.hash.hash2" color="" fillcolor=lightcoral shape=oval style=filled]
9 [label="starkware.cairo.lang.compiler.lib.registers.get_fp_and_pc" color="" fillcolor=lightcoral shape=oval style=filled]
10 [label="starkware.cairo.common.math.assert_250_bit\l['known_ap_change']" color="" fillcolor=yellow shape=oval style=filled]
23 [label="starkware.starknet.common.storage.normalize_address\l['known_ap_change']" color="" fillcolor=yellow shape=oval style=filled]
63 [label="starkware.starknet.common.syscalls.deploy" color="" fillcolor=lightcoral shape=oval style=filled]
75 [label="starkware.starknet.common.syscalls.get_contract_address" color="" fillcolor=lightcoral shape=oval style=filled]
82 [label="starkware.starknet.common.syscalls.storage_read" color="" fillcolor=lightcoral shape=oval style=filled]
90 [label="starkware.starknet.common.syscalls.storage_write" color="" fillcolor=lightcoral shape=oval style=filled]
98 [label="starkware.cairo.common.registers.get_label_location" color="" fillcolor=lightcoral shape=oval style=filled]
104 [label="starkware.cairo.common.hash_state.hash_init" color="" fillcolor=lightcoral shape=oval style=filled]
114 [label="starkware.cairo.common.hash_state.hash_update" color="" fillcolor=lightcoral shape=oval style=filled]
130 [label="starkware.cairo.common.hash_state.hash_update_single" color="" fillcolor=lightcoral shape=oval style=filled]
146 [label="starkware.cairo.common.hash_state.hash_update_with_hashchain" color="" fillcolor=lightcoral shape=oval style=filled]
157 [label="starkware.cairo.common.hash_state.hash_finalize" color="" fillcolor=lightcoral shape=oval style=filled]
163 [label="starkware.cairo.common.hash_state.hash_update_inner" color="" fillcolor=lightcoral shape=oval style=filled]
188 [label="starkware.cairo.common.hash_state.hash_felts" color="" fillcolor=lightcoral shape=oval style=filled]
199 [label="__main__.account_abstraction_class_hash.addr" color="" fillcolor=white shape=oval style=solid]
204 [label="__main__.account_abstraction_class_hash.read" color="" fillcolor=white shape=oval style=solid]
217 [label="__main__.account_abstraction_class_hash.write" color="" fillcolor=white shape=oval style=solid]
229 [label="__main__.kakarot_address.addr" color="" fillcolor=white shape=oval style=solid]
234 [label="__main__.kakarot_address.read" color="" fillcolor=white shape=oval style=solid]
247 [label="__main__.kakarot_address.write" color="" fillcolor=white shape=oval style=solid]
259 [label="__main__.constructor\l['constructor']" color="" fillcolor=violet shape=oval style=filled]
269 [label="__wrappers__.constructor\l['constructor']" color="" fillcolor=violet shape=doubleoctagon style=filled]
288 [label="__main__.create_account\l['external']" color="" fillcolor=lightgreen shape=oval style=filled]
317 [label="__wrappers__.create_account\l['external']" color="" fillcolor=lightgreen shape=doubleoctagon style=filled]
335 [label="__main__.compute_starknet_address\l['view']" color="" fillcolor=orange shape=oval style=filled]
390 [label="__wrappers__.compute_starknet_address_encode_return" color="" fillcolor=white shape=oval style=solid]
399 [label="__wrappers__.compute_starknet_address\l['view']" color="" fillcolor=orange shape=doubleoctagon style=filled]
23 -> 10 [label=4]
98 -> 9
104 -> 9
114 -> 163
114 -> 9
130 -> 3
130 -> 9
146 -> 188
146 -> 130
157 -> 3
188 -> 104
188 -> 114
188 -> 157
204 -> 199
204 -> 82
217 -> 199
217 -> 90
234 -> 229
234 -> 82
247 -> 229
247 -> 90
259 -> 217
259 -> 247
269 -> 259
288 -> 0
288 -> 234
288 -> 204
288 -> 63
317 -> 288
335 -> 75
335 -> 234
335 -> 0
335 -> 204
335 -> 104
335 -> 130 [label=4]
335 -> 146
335 -> 157
335 -> 23
399 -> 335
399 -> 390
}
Binary file added docs/callgraphs/kethaa_deployer.gv.pdf
Binary file not shown.
139 changes: 139 additions & 0 deletions src/kakarot/accounts/eoa/aa/externally_owned_account.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
// SPDX-License-Identifier: MIT

%lang starknet

// Starkware dependencies
from starkware.cairo.common.cairo_builtins import HashBuiltin, SignatureBuiltin, BitwiseBuiltin
from starkware.starknet.common.syscalls import get_caller_address
from starkware.starknet.common.eth_utils import assert_eth_address_range
from starkware.cairo.common.math_cmp import is_le_felt
from starkware.cairo.common.alloc import alloc
from starkware.cairo.common.cairo_secp.signature import verify_eth_signature_uint256
from starkware.cairo.common.uint256 import Uint256
// Account library
from kakarot.accounts.eoa.aa.library import ExternallyOwnedAccount

@storage_var
func eth_address() -> (adress: felt) {
}

@storage_var
func kakarot_address() -> (address: felt) {
}

// Constructor
// @param _eth_address The Ethereum address which will control the account
// @param _kakarot_address The Starknet address of the Kakarot contract
@constructor
func constructor{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
_eth_address: felt, _kakarot_address: felt
) {
assert_eth_address_range(_eth_address);
eth_address.write(_eth_address);
kakarot_address.write(_kakarot_address);
return ();
}

// Account specific methods

// @notice validate a transaction
// @dev the transaction is considered as valid if it is signed with the correct address and is a valid kakarot transaction
// @param call_array_len The length of the call_array
// @param call_array An array containing all the calls of the transaction see: https://docs.openzeppelin.com/contracts-cairo/0.6.0/accounts#call_and_accountcallarray_format
// @param calldata_len The length of the Calldata array
// @param calldata The calldata
@external
func __validate__{
syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, bitwise_ptr: BitwiseBuiltin*, range_check_ptr
}(
call_array_len: felt,
call_array: ExternallyOwnedAccount.CallArray*,
calldata_len: felt,
calldata: felt*,
) {
alloc_locals;
let (address) = eth_address.read();
ExternallyOwnedAccount.validate(
eth_address=address,
call_array_len=call_array_len,
call_array=call_array,
calldata_len=calldata_len,
calldata=calldata,
);
return ();
}

// @notice validates this account class for declaration
// @dev For our usecase the account doesn't need to declare contracts
@external
func __validate_declare__{
syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, bitwise_ptr: BitwiseBuiltin*, range_check_ptr
}(class_hash: felt) {
assert 1 = 0;
return ();
}

// @notice executes the Kakarot transaction
// @dev this is executed only if the __validate__ function succeeded
// @param call_array_len The length of the call_array
// @param call_array An array containing all the calls of the transaction see: https://docs.openzeppelin.com/contracts-cairo/0.6.0/accounts#call_and_accountcallarray_format
// @param calldata_len The length of the Calldata array
// @param calldata The calldata
// @return response_len The length of the response array
// @return response The response from the kakarot contract
@external
func __execute__{
syscall_ptr: felt*,
pedersen_ptr: HashBuiltin*,
ecdsa_ptr: SignatureBuiltin*,
bitwise_ptr: BitwiseBuiltin*,
range_check_ptr,
}(
call_array_len: felt,
call_array: ExternallyOwnedAccount.CallArray*,
calldata_len: felt,
calldata: felt*,
) -> (response_len: felt, response: felt*) {
let (response: felt*) = alloc();
// TODO: parse, call kakarot, and format response
return (response_len=0, response=response);
}

// @return eth_address The Ethereum address controlling this account
@view
func get_eth_address{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (
eth_address: felt
) {
let (address) = eth_address.read();
return (eth_address=address);
}

// @dev returns true if the interface_id is supported
// @dev TODO: check what interfaces the contract should support and maybe create one for a kakarot account
// @param interface_id The interface Id to verify if supported
@view
func supports_interface{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
interface_id: felt
) -> (success: felt) {
if (interface_id == ExternallyOwnedAccount.INTERFACE_ID) {
return (success=1);
}
return (success=0);
}

// @notice checks if the signature is valid
// @dev returns true if the signature is signed by the account controller
// @param hash_len The hash length which was signed
// @param hash The hash [low_128_bits, high_128_bits]
// @param signature_len The length of the signature array
// @param signature The array of the ethereum signature (as v, r, s)
@view
func is_valid_signature{
syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, bitwise_ptr: BitwiseBuiltin*, range_check_ptr
}(hash_len: felt, hash: felt*, signature_len: felt, signature: felt*) -> (is_valid: felt) {
alloc_locals;
let (_eth_address) = eth_address.read();
return ExternallyOwnedAccount.is_valid_signature(
_eth_address, hash_len, hash, signature_len, signature
);
}
Loading

0 comments on commit 9514bc0

Please sign in to comment.