From 1fad8ec6bc32f7e64f69f428a3a361f7382e43e9 Mon Sep 17 00:00:00 2001 From: enitrat Date: Fri, 11 Oct 2024 15:28:41 +0200 Subject: [PATCH 01/20] dev: dualvm tokens deployment scripts --- .gitmodules | 3 + kakarot_scripts/constants.py | 34 +--- .../deployment/dualvm_token_deployments.py | 147 ++++++++++++++++++ kakarot_scripts/utils/starknet.py | 7 + solidity_contracts/lib/openzeppelin | 1 + starknet-addresses | 1 + .../CairoPrecompiles/test_dual_vm_token.py | 24 +-- 7 files changed, 169 insertions(+), 48 deletions(-) create mode 100644 kakarot_scripts/deployment/dualvm_token_deployments.py create mode 160000 solidity_contracts/lib/openzeppelin create mode 160000 starknet-addresses diff --git a/.gitmodules b/.gitmodules index dac7bb0f9..d5e8f4eb7 100644 --- a/.gitmodules +++ b/.gitmodules @@ -16,3 +16,6 @@ [submodule "solidity_contracts/lib/openzeppelin-contracts"] path = solidity_contracts/lib/openzeppelin-contracts url = https://github.com/OpenZeppelin/openzeppelin-contracts +[submodule "starknet-addresses"] + path = starknet-addresses + url = https://github.com/starknet-io/starknet-addresses diff --git a/kakarot_scripts/constants.py b/kakarot_scripts/constants.py index a7c085cce..bccc83b93 100644 --- a/kakarot_scripts/constants.py +++ b/kakarot_scripts/constants.py @@ -34,7 +34,7 @@ class NetworkType(Enum): NETWORKS = { "mainnet": { - "name": "starknet-mainnet", + "name": "mainnet", "explorer_url": "https://starkscan.co", "rpc_url": f"https://rpc.nethermind.io/mainnet-juno/?apikey={os.getenv('NETHERMIND_API_KEY')}", "l1_rpc_url": f"https://mainnet.infura.io/v3/{os.getenv('INFURA_KEY')}", @@ -47,7 +47,7 @@ class NetworkType(Enum): "argent_multisig_api": "https://cloud.argent-api.com/v1/multisig/starknet/mainnet", }, "sepolia": { - "name": "starknet-sepolia", + "name": "sepolia", "explorer_url": "https://sepolia.starkscan.co/", "rpc_url": f"https://rpc.nethermind.io/sepolia-juno/?apikey={os.getenv('NETHERMIND_API_KEY')}", "l1_rpc_url": f"https://sepolia.infura.io/v3/{os.getenv('INFURA_KEY')}", @@ -136,34 +136,7 @@ class NetworkType(Enum): "type": NetworkType.DEV, "check_interval": 6, "max_wait": 30, - }, - "sharingan": { - "name": "sharingan", - "explorer_url": "", - "rpc_url": os.getenv("SHARINGAN_RPC_URL"), - "l1_rpc_url": "http://127.0.0.1:8545", - "type": NetworkType.PROD, - "check_interval": 6, - "max_wait": 30, - }, - "kakarot-sepolia": { - "name": "kakarot-sepolia", - "explorer_url": "", - "rpc_url": os.getenv("KAKAROT_SEPOLIA_RPC_URL"), - "l1_rpc_url": f"https://sepolia.infura.io/v3/{os.getenv('INFURA_KEY')}", - "type": NetworkType.PROD, - "check_interval": 6, - "max_wait": 360, - }, - "kakarot-staging": { - "name": "kakarot-staging", - "explorer_url": "", - "rpc_url": os.getenv("KAKAROT_STAGING_RPC_URL"), - "l1_rpc_url": f"https://sepolia.infura.io/v3/{os.getenv('INFURA_KEY')}", - "type": NetworkType.STAGING, - "check_interval": 1, - "max_wait": 30, - }, + } } if os.getenv("STARKNET_NETWORK") is not None: @@ -238,6 +211,7 @@ class ChainId(IntEnum): CAIRO_DIR = Path("cairo") TESTS_DIR_CAIRO_ZERO = Path("cairo_zero/tests") TESTS_DIR_END_TO_END = Path("tests") +TOKEN_ADDRESSES_DIR = Path("starknet-addresses/bridged_tokens") CONTRACTS = { p.stem: p diff --git a/kakarot_scripts/deployment/dualvm_token_deployments.py b/kakarot_scripts/deployment/dualvm_token_deployments.py new file mode 100644 index 000000000..ab1331873 --- /dev/null +++ b/kakarot_scripts/deployment/dualvm_token_deployments.py @@ -0,0 +1,147 @@ +# %% Imports +import json +import logging +from typing import List, Dict, Any + +from uvloop import run + +from kakarot_scripts.constants import EVM_ADDRESS, NETWORK, RPC_CLIENT, TOKEN_ADDRESSES_DIR, NetworkType +from kakarot_scripts.utils.kakarot import ( + deploy as deploy_kakarot, + deploy_and_fund_evm_address, + get_deployments as get_evm_deployments, + dump_deployments as dump_evm_deployments, +) +from kakarot_scripts.utils.starknet import ( + deploy as deploy_starknet, + get_class_hash_at, + get_deployments as get_starknet_deployments, + get_contract as get_contract_starknet, + get_starknet_account, + invoke, +) + +logging.basicConfig() +logger = logging.getLogger(__name__) +logger.setLevel(logging.INFO) +# %% + +async def deploy_starknet_token(owner_address: str) -> Any: + address = await deploy_starknet("StarknetToken", int(1e18), owner_address) + return get_contract_starknet("StarknetToken", address=address) + +async def deploy_dualvm_token(kakarot_address: str, starknet_token_address: str, deployer_account: Any = None) -> Any: + dual_vm_token = await deploy_kakarot( + "CairoPrecompiles", + "DualVmToken", + kakarot_address, + starknet_token_address, + caller_eoa=deployer_account, + ) + + await invoke( + "kakarot", + "set_authorized_cairo_precompile_caller", + int(dual_vm_token.address, 16), + True, + ) + return dual_vm_token + +async def deploy_dualvm_tokens() -> None: + # %% Deploy DualVM Tokens + kakarot = get_starknet_deployments()["kakarot"] + evm_deployments = get_evm_deployments() + tokens = await get_tokens(NETWORK) + + for token in tokens: + token_name = token["name"] + if token_name not in evm_deployments: + await deploy_new_token(token_name, token, kakarot, evm_deployments) + else: + await verify_and_update_existing_token(token_name, token, kakarot, evm_deployments) + + logger.info("Finished processing all tokens") + dump_evm_deployments(evm_deployments) + logger.info("Updated EVM deployments have been saved") + # %% + + +async def get_tokens(network) -> List[Dict[str, Any]]: + """ + Gets the list of tokens for a given network. + If in dev mode, will return the sepolia token list. + """ + if network["type"] == NetworkType.DEV: + return await load_tokens("sepolia") + if network["name"] not in ("mainnet", "sepolia"): + raise ValueError(f"No known token addresses for network: {network['name']}") + return await load_tokens(network["name"]) + +async def load_tokens(network_name: str) -> List[Dict[str, Any]]: + file_name = network_name.replace("starknet-", "") + file_path = TOKEN_ADDRESSES_DIR / f"{file_name}.json" + return json.loads(file_path.read_text()) + + +async def deploy_new_token(token_name: str, token: Dict[str, Any], kakarot: str, evm_deployments: Dict[str, Any]) -> None: + """ + Deploys a new DualVMToken for a corresponding Starknet ERC20 token. + """ + l2_token_address = await ensure_starknet_token(token_name, token) + contract = await deploy_dualvm_token(kakarot, l2_token_address) + evm_deployments[token_name] = { + "address": int(contract.address, 16), + "starknet_address": contract.starknet_address, + } + logger.info(f"Deployed new DualVMToken for {token_name} at address {contract.address}") + +async def verify_and_update_existing_token(token_name: str, token: Dict[str, Any], kakarot: str, evm_deployments: Dict[str, Any]) -> None: + """ + Given an existing DualVMToken, verifies it is _actually_ deployed. If not, deploys a new one. + """ + dualvm_token_address = evm_deployments[token_name]["starknet_address"] + if not await get_class_hash_at(dualvm_token_address): + l2_token_address = await ensure_starknet_token(token_name, token) + contract = await deploy_dualvm_token(kakarot, l2_token_address) + evm_deployments[token_name] = { + "address": int(contract.address, 16), + "starknet_address": contract.starknet_address, + } + logger.info(f"Deployed new DualVMToken for {token_name} at address {contract.address}") + else: + logger.info(f"Existing DualVMToken for {token_name} is valid") + +async def ensure_starknet_token(token_name: str, token: Dict[str, Any]) -> str: + """ + Ensures a Starknet ERC20 token exists for a given dualVM token. + If not, deploys a new one in dev networks, or returns the starknet address in production networks. + """ + if NETWORK["type"] == NetworkType.DEV: + owner = await get_starknet_account() + starknet_token = await deploy_starknet_token(owner.address) + token["l2_token_address"] = starknet_token.address + logger.info(f"Deployed new Starknet token for {token_name} at address {starknet_token.address}") + else: + logger.info(f"Using existing Starknet token for {token_name} at address {token['l2_token_address']}") + return token["l2_token_address"] + +async def main() -> None: + try: + await RPC_CLIENT.get_class_hash_at(get_starknet_deployments()["kakarot"]) + except Exception: + logger.error("❌ Kakarot is not deployed, exiting...") + return + + await deploy_and_fund_evm_address( + EVM_ADDRESS, amount=100 if NETWORK["type"] is NetworkType.DEV else 0.01 + ) + + await deploy_dualvm_tokens() + +def main_sync() -> None: + run(main()) + +if __name__ == "__main__": + main_sync() + +# %% diff --git a/kakarot_scripts/utils/starknet.py b/kakarot_scripts/utils/starknet.py index 0e52a2c85..3d7e15b95 100644 --- a/kakarot_scripts/utils/starknet.py +++ b/kakarot_scripts/utils/starknet.py @@ -730,3 +730,10 @@ async def wait_for_transaction(tx_hash): except Exception as e: logger.error(f"Error while waiting for transaction 0x{tx_hash:064x}: {e}") return "❌" + + +async def get_class_hash_at(address): + try: + return await RPC_CLIENT.get_class_hash_at(address) + except Exception: + return None diff --git a/solidity_contracts/lib/openzeppelin b/solidity_contracts/lib/openzeppelin new file mode 160000 index 000000000..8e0296096 --- /dev/null +++ b/solidity_contracts/lib/openzeppelin @@ -0,0 +1 @@ +Subproject commit 8e0296096449d9b1cd7c5631e917330635244c37 diff --git a/starknet-addresses b/starknet-addresses new file mode 160000 index 000000000..b99d4b276 --- /dev/null +++ b/starknet-addresses @@ -0,0 +1 @@ +Subproject commit b99d4b276b3d7d347c934720c88eeb039bb3539c diff --git a/tests/end_to_end/CairoPrecompiles/test_dual_vm_token.py b/tests/end_to_end/CairoPrecompiles/test_dual_vm_token.py index ec56a7444..646e329bf 100644 --- a/tests/end_to_end/CairoPrecompiles/test_dual_vm_token.py +++ b/tests/end_to_end/CairoPrecompiles/test_dual_vm_token.py @@ -2,7 +2,8 @@ import pytest_asyncio from eth_utils import keccak -from kakarot_scripts.utils.kakarot import deploy as deploy_kakarot +from kakarot_scripts.deployment.dualvm_token_deployments import deploy_dualvm_token, deploy_starknet_token +from kakarot_scripts.utils.kakarot import deploy as deploy_kakarot, get_deployments as get_evm_deployments, get_contract as get_contract_evm from kakarot_scripts.utils.starknet import deploy as deploy_starknet from kakarot_scripts.utils.starknet import get_contract as get_contract_starknet from kakarot_scripts.utils.starknet import get_starknet_account, invoke @@ -18,23 +19,10 @@ async def starknet_token(owner): @pytest_asyncio.fixture(scope="function") -async def dual_vm_token(kakarot, starknet_token, owner): - dual_vm_token = await deploy_kakarot( - "CairoPrecompiles", - "DualVmToken", - kakarot.address, - starknet_token.address, - caller_eoa=owner.starknet_contract, - ) - - await invoke( - "kakarot", - "set_authorized_cairo_precompile_caller", - int(dual_vm_token.address, 16), - True, - ) - return dual_vm_token - +async def dual_vm_token(): + evm_deployments = get_evm_deployments() + ether = evm_deployments["Ether"]["address"] + return await get_contract_evm("CairoPrecompiles", "DualVmToken", address=ether) @pytest.mark.asyncio(scope="module") @pytest.mark.CairoPrecompiles From 113fd012a062a6832fa4af92aa799d67f5377078 Mon Sep 17 00:00:00 2001 From: enitrat Date: Fri, 11 Oct 2024 15:31:30 +0200 Subject: [PATCH 02/20] fmt --- kakarot_scripts/constants.py | 2 +- .../deployment/dualvm_token_deployments.py | 90 +++++++++++++------ .../CairoPrecompiles/test_dual_vm_token.py | 7 +- 3 files changed, 66 insertions(+), 33 deletions(-) diff --git a/kakarot_scripts/constants.py b/kakarot_scripts/constants.py index bccc83b93..93cb97b0c 100644 --- a/kakarot_scripts/constants.py +++ b/kakarot_scripts/constants.py @@ -136,7 +136,7 @@ class NetworkType(Enum): "type": NetworkType.DEV, "check_interval": 6, "max_wait": 30, - } + }, } if os.getenv("STARKNET_NETWORK") is not None: diff --git a/kakarot_scripts/deployment/dualvm_token_deployments.py b/kakarot_scripts/deployment/dualvm_token_deployments.py index ab1331873..5e25950de 100644 --- a/kakarot_scripts/deployment/dualvm_token_deployments.py +++ b/kakarot_scripts/deployment/dualvm_token_deployments.py @@ -1,36 +1,41 @@ # %% Imports import json import logging -from typing import List, Dict, Any +from typing import Any, Dict, List from uvloop import run -from kakarot_scripts.constants import EVM_ADDRESS, NETWORK, RPC_CLIENT, TOKEN_ADDRESSES_DIR, NetworkType -from kakarot_scripts.utils.kakarot import ( - deploy as deploy_kakarot, - deploy_and_fund_evm_address, - get_deployments as get_evm_deployments, - dump_deployments as dump_evm_deployments, -) -from kakarot_scripts.utils.starknet import ( - deploy as deploy_starknet, - get_class_hash_at, - get_deployments as get_starknet_deployments, - get_contract as get_contract_starknet, - get_starknet_account, - invoke, +from kakarot_scripts.constants import ( + EVM_ADDRESS, + NETWORK, + RPC_CLIENT, + TOKEN_ADDRESSES_DIR, + NetworkType, ) +from kakarot_scripts.utils.kakarot import deploy as deploy_kakarot +from kakarot_scripts.utils.kakarot import deploy_and_fund_evm_address +from kakarot_scripts.utils.kakarot import dump_deployments as dump_evm_deployments +from kakarot_scripts.utils.kakarot import get_deployments as get_evm_deployments +from kakarot_scripts.utils.starknet import deploy as deploy_starknet +from kakarot_scripts.utils.starknet import get_class_hash_at +from kakarot_scripts.utils.starknet import get_contract as get_contract_starknet +from kakarot_scripts.utils.starknet import get_deployments as get_starknet_deployments +from kakarot_scripts.utils.starknet import get_starknet_account, invoke logging.basicConfig() logger = logging.getLogger(__name__) logger.setLevel(logging.INFO) # %% + async def deploy_starknet_token(owner_address: str) -> Any: address = await deploy_starknet("StarknetToken", int(1e18), owner_address) return get_contract_starknet("StarknetToken", address=address) -async def deploy_dualvm_token(kakarot_address: str, starknet_token_address: str, deployer_account: Any = None) -> Any: + +async def deploy_dualvm_token( + kakarot_address: str, starknet_token_address: str, deployer_account: Any = None +) -> Any: dual_vm_token = await deploy_kakarot( "CairoPrecompiles", "DualVmToken", @@ -47,6 +52,7 @@ async def deploy_dualvm_token(kakarot_address: str, starknet_token_address: str, ) return dual_vm_token + async def deploy_dualvm_tokens() -> None: # %% Deploy DualVM Tokens kakarot = get_starknet_deployments()["kakarot"] @@ -58,7 +64,9 @@ async def deploy_dualvm_tokens() -> None: if token_name not in evm_deployments: await deploy_new_token(token_name, token, kakarot, evm_deployments) else: - await verify_and_update_existing_token(token_name, token, kakarot, evm_deployments) + await verify_and_update_existing_token( + token_name, token, kakarot, evm_deployments + ) logger.info("Finished processing all tokens") dump_evm_deployments(evm_deployments) @@ -68,8 +76,8 @@ async def deploy_dualvm_tokens() -> None: async def get_tokens(network) -> List[Dict[str, Any]]: """ - Gets the list of tokens for a given network. - If in dev mode, will return the sepolia token list. + Get the list of tokens for a given network. + If in dev mode, will return the sepolia token list. """ if network["type"] == NetworkType.DEV: return await load_tokens("sepolia") @@ -77,15 +85,21 @@ async def get_tokens(network) -> List[Dict[str, Any]]: raise ValueError(f"No known token addresses for network: {network['name']}") return await load_tokens(network["name"]) + async def load_tokens(network_name: str) -> List[Dict[str, Any]]: file_name = network_name.replace("starknet-", "") file_path = TOKEN_ADDRESSES_DIR / f"{file_name}.json" return json.loads(file_path.read_text()) -async def deploy_new_token(token_name: str, token: Dict[str, Any], kakarot: str, evm_deployments: Dict[str, Any]) -> None: +async def deploy_new_token( + token_name: str, + token: Dict[str, Any], + kakarot: str, + evm_deployments: Dict[str, Any], +) -> None: """ - Deploys a new DualVMToken for a corresponding Starknet ERC20 token. + Deploys a new DualVMToken for a corresponding Starknet ERC20 token. """ l2_token_address = await ensure_starknet_token(token_name, token) contract = await deploy_dualvm_token(kakarot, l2_token_address) @@ -93,11 +107,19 @@ async def deploy_new_token(token_name: str, token: Dict[str, Any], kakarot: str, "address": int(contract.address, 16), "starknet_address": contract.starknet_address, } - logger.info(f"Deployed new DualVMToken for {token_name} at address {contract.address}") + logger.info( + f"Deployed new DualVMToken for {token_name} at address {contract.address}" + ) -async def verify_and_update_existing_token(token_name: str, token: Dict[str, Any], kakarot: str, evm_deployments: Dict[str, Any]) -> None: + +async def verify_and_update_existing_token( + token_name: str, + token: Dict[str, Any], + kakarot: str, + evm_deployments: Dict[str, Any], +) -> None: """ - Given an existing DualVMToken, verifies it is _actually_ deployed. If not, deploys a new one. + Given an existing DualVMToken, verifies it is _actually_ deployed. If not, deploys a new one. """ dualvm_token_address = evm_deployments[token_name]["starknet_address"] if not await get_class_hash_at(dualvm_token_address): @@ -107,24 +129,32 @@ async def verify_and_update_existing_token(token_name: str, token: Dict[str, Any "address": int(contract.address, 16), "starknet_address": contract.starknet_address, } - logger.info(f"Deployed new DualVMToken for {token_name} at address {contract.address}") + logger.info( + f"Deployed new DualVMToken for {token_name} at address {contract.address}" + ) else: logger.info(f"Existing DualVMToken for {token_name} is valid") + async def ensure_starknet_token(token_name: str, token: Dict[str, Any]) -> str: """ - Ensures a Starknet ERC20 token exists for a given dualVM token. - If not, deploys a new one in dev networks, or returns the starknet address in production networks. + Ensure a Starknet ERC20 token exists for a given dualVM token. + If not, deploys a new one in dev networks, or returns the starknet address in production networks. """ if NETWORK["type"] == NetworkType.DEV: owner = await get_starknet_account() starknet_token = await deploy_starknet_token(owner.address) token["l2_token_address"] = starknet_token.address - logger.info(f"Deployed new Starknet token for {token_name} at address {starknet_token.address}") + logger.info( + f"Deployed new Starknet token for {token_name} at address {starknet_token.address}" + ) else: - logger.info(f"Using existing Starknet token for {token_name} at address {token['l2_token_address']}") + logger.info( + f"Using existing Starknet token for {token_name} at address {token['l2_token_address']}" + ) return token["l2_token_address"] + async def main() -> None: try: await RPC_CLIENT.get_class_hash_at(get_starknet_deployments()["kakarot"]) @@ -138,9 +168,11 @@ async def main() -> None: await deploy_dualvm_tokens() + def main_sync() -> None: run(main()) + if __name__ == "__main__": main_sync() diff --git a/tests/end_to_end/CairoPrecompiles/test_dual_vm_token.py b/tests/end_to_end/CairoPrecompiles/test_dual_vm_token.py index 646e329bf..52912d531 100644 --- a/tests/end_to_end/CairoPrecompiles/test_dual_vm_token.py +++ b/tests/end_to_end/CairoPrecompiles/test_dual_vm_token.py @@ -2,9 +2,8 @@ import pytest_asyncio from eth_utils import keccak -from kakarot_scripts.deployment.dualvm_token_deployments import deploy_dualvm_token, deploy_starknet_token -from kakarot_scripts.utils.kakarot import deploy as deploy_kakarot, get_deployments as get_evm_deployments, get_contract as get_contract_evm -from kakarot_scripts.utils.starknet import deploy as deploy_starknet +from kakarot_scripts.utils.kakarot import get_contract as get_contract_evm +from kakarot_scripts.utils.kakarot import get_deployments as get_evm_deployments from kakarot_scripts.utils.starknet import get_contract as get_contract_starknet from kakarot_scripts.utils.starknet import get_starknet_account, invoke from tests.utils.errors import cairo_error @@ -18,12 +17,14 @@ async def starknet_token(owner): return get_contract_starknet("StarknetToken", address=address) + @pytest_asyncio.fixture(scope="function") async def dual_vm_token(): evm_deployments = get_evm_deployments() ether = evm_deployments["Ether"]["address"] return await get_contract_evm("CairoPrecompiles", "DualVmToken", address=ether) + @pytest.mark.asyncio(scope="module") @pytest.mark.CairoPrecompiles class TestDualVmToken: From c9cc90b5df7d83ecb45dca0f6bc18c519525811f Mon Sep 17 00:00:00 2001 From: enitrat Date: Fri, 11 Oct 2024 15:43:19 +0200 Subject: [PATCH 03/20] batch some calls --- .../deployment/dualvm_token_deployments.py | 17 ++++-- kakarot_scripts/deployment/evm_deployments.py | 52 ++++++------------- kakarot_scripts/deployment/main.py | 2 + 3 files changed, 31 insertions(+), 40 deletions(-) diff --git a/kakarot_scripts/deployment/dualvm_token_deployments.py b/kakarot_scripts/deployment/dualvm_token_deployments.py index 5e25950de..47fcc3569 100644 --- a/kakarot_scripts/deployment/dualvm_token_deployments.py +++ b/kakarot_scripts/deployment/dualvm_token_deployments.py @@ -17,10 +17,15 @@ from kakarot_scripts.utils.kakarot import dump_deployments as dump_evm_deployments from kakarot_scripts.utils.kakarot import get_deployments as get_evm_deployments from kakarot_scripts.utils.starknet import deploy as deploy_starknet -from kakarot_scripts.utils.starknet import get_class_hash_at +from kakarot_scripts.utils.starknet import execute_calls, get_class_hash_at from kakarot_scripts.utils.starknet import get_contract as get_contract_starknet from kakarot_scripts.utils.starknet import get_deployments as get_starknet_deployments -from kakarot_scripts.utils.starknet import get_starknet_account, invoke +from kakarot_scripts.utils.starknet import ( + get_starknet_account, + invoke, + register_lazy_account, + remove_lazy_account, +) logging.basicConfig() logger = logging.getLogger(__name__) @@ -155,6 +160,7 @@ async def ensure_starknet_token(token_name: str, token: Dict[str, Any]) -> str: return token["l2_token_address"] +# %% Run async def main() -> None: try: await RPC_CLIENT.get_class_hash_at(get_starknet_deployments()["kakarot"]) @@ -166,14 +172,17 @@ async def main() -> None: EVM_ADDRESS, amount=100 if NETWORK["type"] is NetworkType.DEV else 0.01 ) + account = await get_starknet_account() + register_lazy_account(account) await deploy_dualvm_tokens() + await execute_calls() + remove_lazy_account(account.address) def main_sync() -> None: run(main()) +# %% if __name__ == "__main__": main_sync() - -# %% diff --git a/kakarot_scripts/deployment/evm_deployments.py b/kakarot_scripts/deployment/evm_deployments.py index ba218103a..1ed2ccb01 100644 --- a/kakarot_scripts/deployment/evm_deployments.py +++ b/kakarot_scripts/deployment/evm_deployments.py @@ -4,21 +4,19 @@ from eth_utils.address import to_checksum_address from uvloop import run -from kakarot_scripts.constants import ( - ETH_TOKEN_ADDRESS, - EVM_ADDRESS, - NETWORK, - RPC_CLIENT, - STRK_TOKEN_ADDRESS, - NetworkType, -) +from kakarot_scripts.constants import EVM_ADDRESS, NETWORK, RPC_CLIENT, NetworkType from kakarot_scripts.utils.kakarot import deploy as deploy_evm from kakarot_scripts.utils.kakarot import deploy_and_fund_evm_address from kakarot_scripts.utils.kakarot import dump_deployments as dump_evm_deployments from kakarot_scripts.utils.kakarot import get_deployments as get_evm_deployments from kakarot_scripts.utils.starknet import call, execute_calls from kakarot_scripts.utils.starknet import get_deployments as get_starknet_deployments -from kakarot_scripts.utils.starknet import invoke +from kakarot_scripts.utils.starknet import ( + get_starknet_account, + invoke, + register_lazy_account, + remove_lazy_account, +) logger = logging.getLogger(__name__) logger.setLevel(logging.INFO) @@ -33,34 +31,16 @@ async def deploy_evm_contracts(): EVM_ADDRESS, amount=100 if NETWORK["type"] is NetworkType.DEV else 0.01 ) - starknet_deployments = get_starknet_deployments() evm_deployments = get_evm_deployments() - # %% Tokens + # %% Pure EVM Tokens for ( contract_app, contract_name, deployed_name, - cairo_precompile, *deployment_args, ) in [ - ("WETH", "WETH9", "WETH9", False), - ( - "CairoPrecompiles", - "DualVmToken", - "KakarotETH", - True, - starknet_deployments["kakarot"], - ETH_TOKEN_ADDRESS, - ), - ( - "CairoPrecompiles", - "DualVmToken", - "KakarotSTRK", - True, - starknet_deployments["kakarot"], - STRK_TOKEN_ADDRESS, - ), + ("WETH", "WETH9", "WETH9"), ]: deployment = evm_deployments.get(deployed_name) if deployment is not None: @@ -76,13 +56,6 @@ async def deploy_evm_contracts(): "address": int(token.address, 16), "starknet_address": token.starknet_address, } - if cairo_precompile: - await invoke( - "kakarot", - "set_authorized_cairo_precompile_caller", - int(token.address, 16), - 1, - ) # %% Coinbase coinbase = (await call("kakarot", "get_coinbase")).coinbase @@ -110,8 +83,15 @@ async def main(): logger.error("❌ Kakarot is not deployed, exiting...") return + if not EVM_ADDRESS: + logger.warn("⚠️ No EVM address provided, skipping EVM deployments") + return + + account = await get_starknet_account() + register_lazy_account(account.address) await deploy_evm_contracts() await execute_calls() + remove_lazy_account(account.address) def main_sync(): diff --git a/kakarot_scripts/deployment/main.py b/kakarot_scripts/deployment/main.py index eb061ce0e..0f1acde12 100644 --- a/kakarot_scripts/deployment/main.py +++ b/kakarot_scripts/deployment/main.py @@ -5,6 +5,7 @@ from kakarot_scripts.constants import EVM_ADDRESS, L1_RPC_PROVIDER, NETWORK from kakarot_scripts.deployment.declarations import declare_contracts +from kakarot_scripts.deployment.dualvm_token_deployments import deploy_dualvm_tokens from kakarot_scripts.deployment.evm_deployments import deploy_evm_contracts from kakarot_scripts.deployment.kakarot_deployment import deploy_or_upgrade_kakarot from kakarot_scripts.deployment.messaging_deployments import ( @@ -52,6 +53,7 @@ async def main(): # %% EVM Deployments await deploy_pre_eip155_senders() await deploy_evm_contracts() + await deploy_dualvm_tokens() await execute_calls() await whitelist_pre_eip155_txs() From 4c186d1802be7b34de9f90640e3557ba20f80e1f Mon Sep 17 00:00:00 2001 From: enitrat Date: Fri, 11 Oct 2024 18:41:36 +0200 Subject: [PATCH 04/20] wip: fix dualvm tests --- cairo/token/src/starknet_token.cairo | 7 +++ .../deployment/dualvm_token_deployments.py | 27 +++++++---- kakarot_scripts/deployment/evm_deployments.py | 2 +- solidity_contracts/lib/openzeppelin | 1 - .../CairoPrecompiles/test_dual_vm_token.py | 46 +++++++++++++++---- tests/end_to_end/conftest.py | 3 +- 6 files changed, 65 insertions(+), 21 deletions(-) delete mode 160000 solidity_contracts/lib/openzeppelin diff --git a/cairo/token/src/starknet_token.cairo b/cairo/token/src/starknet_token.cairo index 22a9f7028..b56c0de33 100644 --- a/cairo/token/src/starknet_token.cairo +++ b/cairo/token/src/starknet_token.cairo @@ -8,6 +8,8 @@ mod StarknetToken { #[abi(embed_v0)] impl ERC20Impl = ERC20Component::ERC20Impl; #[abi(embed_v0)] + impl ERC20CamelOnlyImpl = ERC20Component::ERC20CamelOnlyImpl; + #[abi(embed_v0)] impl ERC20MetadataImpl = ERC20Component::ERC20MetadataImpl; impl ERC20InternalImpl = ERC20Component::InternalImpl; @@ -32,4 +34,9 @@ mod StarknetToken { self.erc20.initializer(name, symbol); self.erc20._mint(recipient, initial_supply); } + + #[external(v0)] + fn mint(ref self: ContractState, to: ContractAddress, amount: u256) { + self.erc20._mint(to, amount); + } } diff --git a/kakarot_scripts/deployment/dualvm_token_deployments.py b/kakarot_scripts/deployment/dualvm_token_deployments.py index 47fcc3569..d5e7c1bbb 100644 --- a/kakarot_scripts/deployment/dualvm_token_deployments.py +++ b/kakarot_scripts/deployment/dualvm_token_deployments.py @@ -6,9 +6,11 @@ from uvloop import run from kakarot_scripts.constants import ( + ETH_TOKEN_ADDRESS, EVM_ADDRESS, NETWORK, RPC_CLIENT, + STRK_TOKEN_ADDRESS, TOKEN_ADDRESSES_DIR, NetworkType, ) @@ -33,19 +35,21 @@ # %% -async def deploy_starknet_token(owner_address: str) -> Any: - address = await deploy_starknet("StarknetToken", int(1e18), owner_address) +async def deploy_starknet_token() -> Any: + owner = await get_starknet_account() + address = await deploy_starknet("StarknetToken", int(1e18), owner.address) return get_contract_starknet("StarknetToken", address=address) async def deploy_dualvm_token( kakarot_address: str, starknet_token_address: str, deployer_account: Any = None ) -> Any: + breakpoint() dual_vm_token = await deploy_kakarot( "CairoPrecompiles", "DualVmToken", kakarot_address, - starknet_token_address, + int(starknet_token_address, 16), caller_eoa=deployer_account, ) @@ -147,12 +151,17 @@ async def ensure_starknet_token(token_name: str, token: Dict[str, Any]) -> str: If not, deploys a new one in dev networks, or returns the starknet address in production networks. """ if NETWORK["type"] == NetworkType.DEV: - owner = await get_starknet_account() - starknet_token = await deploy_starknet_token(owner.address) - token["l2_token_address"] = starknet_token.address - logger.info( - f"Deployed new Starknet token for {token_name} at address {starknet_token.address}" - ) + try: + RPC_CLIENT.get_class_hash_at(token["l2_token_address"]) + logger.info( + f"Using existing Starknet token for {token_name} at address {token['l2_token_address']}" + ) + except Exception: + starknet_token = await deploy_starknet_token() + token["l2_token_address"] = f"0x{starknet_token.address:064x}" + logger.info( + f"Deployed new Starknet token for {token_name} at address {token['l2_token_address']}" + ) else: logger.info( f"Using existing Starknet token for {token_name} at address {token['l2_token_address']}" diff --git a/kakarot_scripts/deployment/evm_deployments.py b/kakarot_scripts/deployment/evm_deployments.py index 1ed2ccb01..7c934d956 100644 --- a/kakarot_scripts/deployment/evm_deployments.py +++ b/kakarot_scripts/deployment/evm_deployments.py @@ -63,7 +63,7 @@ async def deploy_evm_contracts(): contract = await deploy_evm( "Kakarot", "Coinbase", - to_checksum_address(f'{evm_deployments["KakarotETH"]["address"]:040x}'), + to_checksum_address(f'{evm_deployments["Ether"]["address"]:040x}'), ) evm_deployments["Coinbase"] = { "address": int(contract.address, 16), diff --git a/solidity_contracts/lib/openzeppelin b/solidity_contracts/lib/openzeppelin deleted file mode 160000 index 8e0296096..000000000 --- a/solidity_contracts/lib/openzeppelin +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 8e0296096449d9b1cd7c5631e917330635244c37 diff --git a/tests/end_to_end/CairoPrecompiles/test_dual_vm_token.py b/tests/end_to_end/CairoPrecompiles/test_dual_vm_token.py index 52912d531..94dddea12 100644 --- a/tests/end_to_end/CairoPrecompiles/test_dual_vm_token.py +++ b/tests/end_to_end/CairoPrecompiles/test_dual_vm_token.py @@ -2,12 +2,37 @@ import pytest_asyncio from eth_utils import keccak +from kakarot_scripts.constants import NETWORK from kakarot_scripts.utils.kakarot import get_contract as get_contract_evm from kakarot_scripts.utils.kakarot import get_deployments as get_evm_deployments -from kakarot_scripts.utils.starknet import get_contract as get_contract_starknet +from kakarot_scripts.utils.starknet import get_contract as get_contract_starknet, wait_for_transaction from kakarot_scripts.utils.starknet import get_starknet_account, invoke from tests.utils.errors import cairo_error +@pytest_asyncio.fixture(scope="function", autouse=True) +async def fund_owner(owner, starknet_token, max_fee): + breakpoint() + (balance_before,) = await starknet_token.functions["balance_of"].call( + owner.starknet_contract.address + ) + breakpoint() + + amount = int(1e16) + if balance_before > amount: + return + + tx = await starknet_token.functions["transfer"].invoke_v1( + owner.starknet_contract.address, + amount, + max_fee=max_fee, + ) + await wait_for_transaction(tx.hash) + + (balance,) = await starknet_token.functions["balance_of"].call( + owner.starknet_contract.address + ) + assert balance >= amount, f"Transfer failed. Expected min balance: {amount}, Actual balance: {balance}" + @pytest_asyncio.fixture(scope="function") async def starknet_token(owner): @@ -19,10 +44,10 @@ async def starknet_token(owner): @pytest_asyncio.fixture(scope="function") -async def dual_vm_token(): +async def dual_vm_token(owner): evm_deployments = get_evm_deployments() ether = evm_deployments["Ether"]["address"] - return await get_contract_evm("CairoPrecompiles", "DualVmToken", address=ether) + return await get_contract_evm("CairoPrecompiles", "DualVmToken", address=ether, caller_eoa=owner.starknet_contract) @pytest.mark.asyncio(scope="module") @@ -116,7 +141,7 @@ async def test_should_transfer( assert balance_other_before + amount == balance_other_after async def test_should_transfer_starknet_address( - self, starknet_token, dual_vm_token, owner, other + self, dual_vm_token, owner, other ): amount = 1 balance_owner_before = await dual_vm_token.functions["balanceOf(address)"]( @@ -161,10 +186,13 @@ async def test_should_transfer_starknet_address( async def test_should_revert_transfer_insufficient_balance( self, dual_vm_token, owner, other, signature, to_address ): + balance = await dual_vm_token.functions["balanceOf(address)"]( + other.address + ) # No wrapping of errors for OZ 0.10 contracts with cairo_error("u256_sub Overflow"): await dual_vm_token.functions[signature]( - to_address(owner), 1, caller_eoa=other.starknet_contract + to_address(owner), balance + 1, caller_eoa=other.starknet_contract ) async def test_should_revert_transfer_starknet_address_invalid_address( @@ -177,7 +205,7 @@ async def test_should_revert_transfer_starknet_address_invalid_address( ) async def test_should_approve( - self, starknet_token, dual_vm_token, owner, other + self, dual_vm_token, owner, other ): amount = 1 allowance_before = await dual_vm_token.functions[ @@ -204,10 +232,10 @@ async def test_should_approve( async def test_should_approve_starknet_address( self, starknet_token, dual_vm_token, owner, other ): - amount = 1 allowance_before = await dual_vm_token.functions[ "allowance(address,uint256)" ](owner.address, other.starknet_contract.address) + amount = 1 + allowance_before receipt = ( await dual_vm_token.functions["approve(uint256,uint256)"]( other.starknet_contract.address, amount @@ -224,7 +252,7 @@ async def test_should_approve_starknet_address( allowance_after = await dual_vm_token.functions[ "allowance(address,uint256)" ](owner.address, other.starknet_contract.address) - assert allowance_after == allowance_before + amount + assert allowance_after == amount async def test_should_revert_approve_starknet_address_invalid_address( self, starknet_token, dual_vm_token @@ -288,7 +316,7 @@ async def test_allowance_owner_and_spender_starknet_address( starknet_token.address, "approve", other.starknet_contract.address, - amount, + allowance_before + amount, 0, account=owner, ) diff --git a/tests/end_to_end/conftest.py b/tests/end_to_end/conftest.py index ec9b7200f..8c85c272d 100644 --- a/tests/end_to_end/conftest.py +++ b/tests/end_to_end/conftest.py @@ -76,7 +76,7 @@ async def _factory(amount=0): kakarot_eth = await get_solidity_contract( "CairoPrecompiles", "DualVmToken", - address=get_deployments()["KakarotETH"]["address"], + address=get_deployments()["Ether"]["address"], ) gas_price = (await call("kakarot", "get_base_fee")).base_fee gas_limit = 40_000 @@ -86,6 +86,7 @@ async def _factory(amount=0): if balance < tx_cost: continue + breakpoint() await kakarot_eth.functions["transfer(uint256,uint256)"]( deployer.address, balance - tx_cost, From 9c3f8ce50df4d03608947867f78ad9e2fa75eba4 Mon Sep 17 00:00:00 2001 From: enitrat Date: Fri, 11 Oct 2024 19:45:11 +0200 Subject: [PATCH 05/20] fmt --- cairo_zero/openzeppelin/ERC20.cairo | 59 ++++++++++--------- .../deployment/dualvm_token_deployments.py | 2 - .../CairoPrecompiles/test_dual_vm_token.py | 29 +++++---- 3 files changed, 50 insertions(+), 40 deletions(-) diff --git a/cairo_zero/openzeppelin/ERC20.cairo b/cairo_zero/openzeppelin/ERC20.cairo index dfcc48d0f..00328b2c2 100644 --- a/cairo_zero/openzeppelin/ERC20.cairo +++ b/cairo_zero/openzeppelin/ERC20.cairo @@ -6,7 +6,6 @@ from starkware.cairo.common.cairo_builtins import HashBuiltin from starkware.cairo.common.uint256 import Uint256 -from openzeppelin.access.ownable.library import Ownable from openzeppelin.token.erc20.library import ERC20 @constructor @@ -15,7 +14,6 @@ func constructor{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr ) { ERC20.initializer(name, symbol, decimals); ERC20._mint(recipient, initial_supply); - Ownable.initializer(owner); return (); } @@ -41,6 +39,13 @@ func totalSupply{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr return (totalSupply=totalSupply); } +@view +func total_supply{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> ( + total_supply: Uint256 +) { + return ERC20.total_supply(); +} + @view func decimals{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> ( decimals: felt @@ -55,6 +60,13 @@ func balanceOf{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( return ERC20.balance_of(account); } +@view +func balance_of{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(account: felt) -> ( + balance: Uint256 +) { + return ERC20.balance_of(account); +} + @view func allowance{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( owner: felt, spender: felt @@ -62,11 +74,6 @@ func allowance{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( return ERC20.allowance(owner, spender); } -@view -func owner{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (owner: felt) { - return Ownable.owner(); -} - // // Externals // @@ -85,6 +92,13 @@ func transferFrom{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_pt return ERC20.transfer_from(sender, recipient, amount); } +@external +func transfer_from{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( + sender: felt, recipient: felt, amount: Uint256 +) -> (success: felt) { + return ERC20.transfer_from(sender, recipient, amount); +} + @external func approve{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( spender: felt, amount: Uint256 @@ -100,31 +114,22 @@ func increaseAllowance{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_che } @external -func decreaseAllowance{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - spender: felt, subtracted_value: Uint256 +func increase_allowance{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( + spender: felt, added_value: Uint256 ) -> (success: felt) { - return ERC20.decrease_allowance(spender, subtracted_value); -} - -@external -func mint{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - to: felt, amount: Uint256 -) { - Ownable.assert_only_owner(); - ERC20._mint(to, amount); - return (); + return ERC20.increase_allowance(spender, added_value); } @external -func transferOwnership{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - newOwner: felt -) { - Ownable.transfer_ownership(newOwner); - return (); +func decreaseAllowance{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( + spender: felt, subtracted_value: Uint256 +) -> (success: felt) { + return ERC20.decrease_allowance(spender, subtracted_value); } @external -func renounceOwnership{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() { - Ownable.renounce_ownership(); - return (); +func decrease_allowance{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( + spender: felt, subtracted_value: Uint256 +) -> (success: felt) { + return ERC20.decrease_allowance(spender, subtracted_value); } diff --git a/kakarot_scripts/deployment/dualvm_token_deployments.py b/kakarot_scripts/deployment/dualvm_token_deployments.py index d5e7c1bbb..26690f473 100644 --- a/kakarot_scripts/deployment/dualvm_token_deployments.py +++ b/kakarot_scripts/deployment/dualvm_token_deployments.py @@ -6,11 +6,9 @@ from uvloop import run from kakarot_scripts.constants import ( - ETH_TOKEN_ADDRESS, EVM_ADDRESS, NETWORK, RPC_CLIENT, - STRK_TOKEN_ADDRESS, TOKEN_ADDRESSES_DIR, NetworkType, ) diff --git a/tests/end_to_end/CairoPrecompiles/test_dual_vm_token.py b/tests/end_to_end/CairoPrecompiles/test_dual_vm_token.py index 94dddea12..f135aa818 100644 --- a/tests/end_to_end/CairoPrecompiles/test_dual_vm_token.py +++ b/tests/end_to_end/CairoPrecompiles/test_dual_vm_token.py @@ -2,13 +2,17 @@ import pytest_asyncio from eth_utils import keccak -from kakarot_scripts.constants import NETWORK from kakarot_scripts.utils.kakarot import get_contract as get_contract_evm from kakarot_scripts.utils.kakarot import get_deployments as get_evm_deployments -from kakarot_scripts.utils.starknet import get_contract as get_contract_starknet, wait_for_transaction -from kakarot_scripts.utils.starknet import get_starknet_account, invoke +from kakarot_scripts.utils.starknet import get_contract as get_contract_starknet +from kakarot_scripts.utils.starknet import ( + get_starknet_account, + invoke, + wait_for_transaction, +) from tests.utils.errors import cairo_error + @pytest_asyncio.fixture(scope="function", autouse=True) async def fund_owner(owner, starknet_token, max_fee): breakpoint() @@ -31,7 +35,9 @@ async def fund_owner(owner, starknet_token, max_fee): (balance,) = await starknet_token.functions["balance_of"].call( owner.starknet_contract.address ) - assert balance >= amount, f"Transfer failed. Expected min balance: {amount}, Actual balance: {balance}" + assert ( + balance >= amount + ), f"Transfer failed. Expected min balance: {amount}, Actual balance: {balance}" @pytest_asyncio.fixture(scope="function") @@ -47,7 +53,12 @@ async def starknet_token(owner): async def dual_vm_token(owner): evm_deployments = get_evm_deployments() ether = evm_deployments["Ether"]["address"] - return await get_contract_evm("CairoPrecompiles", "DualVmToken", address=ether, caller_eoa=owner.starknet_contract) + return await get_contract_evm( + "CairoPrecompiles", + "DualVmToken", + address=ether, + caller_eoa=owner.starknet_contract, + ) @pytest.mark.asyncio(scope="module") @@ -186,9 +197,7 @@ async def test_should_transfer_starknet_address( async def test_should_revert_transfer_insufficient_balance( self, dual_vm_token, owner, other, signature, to_address ): - balance = await dual_vm_token.functions["balanceOf(address)"]( - other.address - ) + balance = await dual_vm_token.functions["balanceOf(address)"](other.address) # No wrapping of errors for OZ 0.10 contracts with cairo_error("u256_sub Overflow"): await dual_vm_token.functions[signature]( @@ -204,9 +213,7 @@ async def test_should_revert_transfer_starknet_address_invalid_address( 2**256 - 1, 1 ) - async def test_should_approve( - self, dual_vm_token, owner, other - ): + async def test_should_approve(self, dual_vm_token, owner, other): amount = 1 allowance_before = await dual_vm_token.functions[ "allowance(address,address)" From a4ecb517a38eec9ad01bab49c355e23347e4d4e7 Mon Sep 17 00:00:00 2001 From: enitrat Date: Tue, 22 Oct 2024 10:55:21 +0200 Subject: [PATCH 06/20] address comments --- cairo/token/src/starknet_token.cairo | 5 +-- .../deployment/dualvm_token_deployments.py | 39 +++++++++---------- .../CairoPrecompiles/test_dual_vm_token.py | 23 ++++++++++- tests/end_to_end/conftest.py | 1 - 4 files changed, 41 insertions(+), 27 deletions(-) diff --git a/cairo/token/src/starknet_token.cairo b/cairo/token/src/starknet_token.cairo index b56c0de33..c0f9a0269 100644 --- a/cairo/token/src/starknet_token.cairo +++ b/cairo/token/src/starknet_token.cairo @@ -27,10 +27,7 @@ mod StarknetToken { } #[constructor] - fn constructor(ref self: ContractState, initial_supply: u256, recipient: ContractAddress) { - let name = "MyToken"; - let symbol = "MTK"; - + fn constructor(ref self: ContractState, name: ByteArray, symbol: ByteArray, initial_supply: u256, recipient: ContractAddress) { self.erc20.initializer(name, symbol); self.erc20._mint(recipient, initial_supply); } diff --git a/kakarot_scripts/deployment/dualvm_token_deployments.py b/kakarot_scripts/deployment/dualvm_token_deployments.py index 26690f473..1960c05ab 100644 --- a/kakarot_scripts/deployment/dualvm_token_deployments.py +++ b/kakarot_scripts/deployment/dualvm_token_deployments.py @@ -35,14 +35,15 @@ async def deploy_starknet_token() -> Any: owner = await get_starknet_account() - address = await deploy_starknet("StarknetToken", int(1e18), owner.address) + address = await deploy_starknet( + "StarknetToken", "MyToken", "MTK", int(1e18), owner.address + ) return get_contract_starknet("StarknetToken", address=address) async def deploy_dualvm_token( kakarot_address: str, starknet_token_address: str, deployer_account: Any = None ) -> Any: - breakpoint() dual_vm_token = await deploy_kakarot( "CairoPrecompiles", "DualVmToken", @@ -64,16 +65,13 @@ async def deploy_dualvm_tokens() -> None: # %% Deploy DualVM Tokens kakarot = get_starknet_deployments()["kakarot"] evm_deployments = get_evm_deployments() - tokens = await get_tokens(NETWORK) + tokens = get_tokens_list(NETWORK) for token in tokens: - token_name = token["name"] - if token_name not in evm_deployments: - await deploy_new_token(token_name, token, kakarot, evm_deployments) + if token["name"] not in evm_deployments: + await deploy_new_token(token, kakarot, evm_deployments) else: - await verify_and_update_existing_token( - token_name, token, kakarot, evm_deployments - ) + await verify_and_update_existing_token(token, kakarot, evm_deployments) logger.info("Finished processing all tokens") dump_evm_deployments(evm_deployments) @@ -81,33 +79,34 @@ async def deploy_dualvm_tokens() -> None: # %% -async def get_tokens(network) -> List[Dict[str, Any]]: +def get_tokens_list(network) -> List[Dict[str, Any]]: """ Get the list of tokens for a given network. If in dev mode, will return the sepolia token list. """ if network["type"] == NetworkType.DEV: - return await load_tokens("sepolia") - if network["name"] not in ("mainnet", "sepolia"): - raise ValueError(f"No known token addresses for network: {network['name']}") - return await load_tokens(network["name"]) + return load_tokens("sepolia") + + return load_tokens(network["name"]) + +def load_tokens(network_name: str) -> List[Dict[str, Any]]: + file_path = TOKEN_ADDRESSES_DIR / f"{network_name}.json" + if not file_path.exists(): + raise ValueError(f"No known token addresses for network: {network_name}") -async def load_tokens(network_name: str) -> List[Dict[str, Any]]: - file_name = network_name.replace("starknet-", "") - file_path = TOKEN_ADDRESSES_DIR / f"{file_name}.json" return json.loads(file_path.read_text()) async def deploy_new_token( - token_name: str, token: Dict[str, Any], kakarot: str, evm_deployments: Dict[str, Any], ) -> None: """ - Deploys a new DualVMToken for a corresponding Starknet ERC20 token. + Deploy a new DualVMToken for a corresponding Starknet ERC20 token. """ + token_name = token["name"] l2_token_address = await ensure_starknet_token(token_name, token) contract = await deploy_dualvm_token(kakarot, l2_token_address) evm_deployments[token_name] = { @@ -120,7 +119,6 @@ async def deploy_new_token( async def verify_and_update_existing_token( - token_name: str, token: Dict[str, Any], kakarot: str, evm_deployments: Dict[str, Any], @@ -128,6 +126,7 @@ async def verify_and_update_existing_token( """ Given an existing DualVMToken, verifies it is _actually_ deployed. If not, deploys a new one. """ + token_name = token["name"] dualvm_token_address = evm_deployments[token_name]["starknet_address"] if not await get_class_hash_at(dualvm_token_address): l2_token_address = await ensure_starknet_token(token_name, token) diff --git a/tests/end_to_end/CairoPrecompiles/test_dual_vm_token.py b/tests/end_to_end/CairoPrecompiles/test_dual_vm_token.py index f135aa818..9cd37baf9 100644 --- a/tests/end_to_end/CairoPrecompiles/test_dual_vm_token.py +++ b/tests/end_to_end/CairoPrecompiles/test_dual_vm_token.py @@ -13,13 +13,32 @@ from tests.utils.errors import cairo_error +@pytest_asyncio.fixture(scope="session") +async def dual_vm_token(owner): + evm_deployments = get_evm_deployments() + ether = evm_deployments["Ether"]["address"] + return await get_contract_evm( + "CairoPrecompiles", + "DualVmToken", + address=ether, + caller_eoa=owner.starknet_contract, + ) + + +@pytest_asyncio.fixture(scope="session") +async def starknet_token(dual_vm_token): + starknet_address = await dual_vm_token.starknetToken() + deployer = await get_starknet_account() + return get_contract_starknet( + "StarknetToken", address=starknet_address, provider=deployer + ) + + @pytest_asyncio.fixture(scope="function", autouse=True) async def fund_owner(owner, starknet_token, max_fee): - breakpoint() (balance_before,) = await starknet_token.functions["balance_of"].call( owner.starknet_contract.address ) - breakpoint() amount = int(1e16) if balance_before > amount: diff --git a/tests/end_to_end/conftest.py b/tests/end_to_end/conftest.py index 8c85c272d..f9608783a 100644 --- a/tests/end_to_end/conftest.py +++ b/tests/end_to_end/conftest.py @@ -86,7 +86,6 @@ async def _factory(amount=0): if balance < tx_cost: continue - breakpoint() await kakarot_eth.functions["transfer(uint256,uint256)"]( deployer.address, balance - tx_cost, From 33e26db272610b76bc1a459814d97a123e8cf67a Mon Sep 17 00:00:00 2001 From: enitrat Date: Fri, 1 Nov 2024 10:10:34 +0700 Subject: [PATCH 07/20] feat: skip deployment of native token --- .env.example | 4 +-- kakarot_scripts/constants.py | 36 +++++++++---------- .../deployment/dualvm_token_deployments.py | 28 ++++++++++----- kakarot_scripts/setup/setup.py | 2 +- kakarot_scripts/utils/starknet.py | 2 +- 5 files changed, 42 insertions(+), 30 deletions(-) diff --git a/.env.example b/.env.example index 2d56de342..06b8cb6b7 100644 --- a/.env.example +++ b/.env.example @@ -23,8 +23,8 @@ STARKNET_SEPOLIA_RELAYER_PRIVATE_KEY= STARKNET_SEPOLIA_ACCOUNT_ADDRESS= STARKNET_SEPOLIA_PRIVATE_KEY= -KATANA_ACCOUNT_ADDRESS=0xb3ff441a68610b30fd5e2abbf3a1548eb6ba6f3559f2862bf2dc757e5828ca -KATANA_PRIVATE_KEY=0x2bbf4f9fd0bbb2e60b0316c1fe0b76cf7a4d0198bd493ced9b8df2a3a24d68a +KATANA_ACCOUNT_ADDRESS=0x127fd5f1fe78a71f8bcd1fec63e3fe2f0486b6ecd5c86a0466c3a21fa5cfcec +KATANA_PRIVATE_KEY=0xc5b2fcab997346f3ea1c00b002ecf6f382c5f9c9659a3894eb783c5320f912 # Kakarot Sepolia (Testnet production and Testnet staging) KAKAROT_SEPOLIA_ACCOUNT_ADDRESS= diff --git a/kakarot_scripts/constants.py b/kakarot_scripts/constants.py index 93cb97b0c..429574fe5 100644 --- a/kakarot_scripts/constants.py +++ b/kakarot_scripts/constants.py @@ -91,40 +91,40 @@ class NetworkType(Enum): "max_wait": 3, "relayers": [ { - "address": 0xE29882A1FCBA1E7E10CAD46212257FEA5C752A4F9B1B1EC683C503A2CF5C8A, - "private_key": 0x14D6672DCB4B77CA36A887E9A11CD9D637D5012468175829E9C6E770C61642, + "address": 0x13D9EE239F33FEA4F8785B9E3870ADE909E20A9599AE7CD62C1C292B73AF1B7, + "private_key": 0x1C9053C053EDF324AEC366A34C6901B1095B07AF69495BFFEC7D7FE21EFFB1B, }, { - "address": 0x29873C310FBEFDE666DC32A1554FEA6BB45EECC84F680F8A2B0A8FBB8CB89AF, - "private_key": 0xC5B2FCAB997346F3EA1C00B002ECF6F382C5F9C9659A3894EB783C5320F912, + "address": 0x17CC6CA902ED4E8BAA8463A7009FF18CC294FA85A94B4CE6AC30A9EBD6057C7, + "private_key": 0x14D6672DCB4B77CA36A887E9A11CD9D637D5012468175829E9C6E770C61642, }, { - "address": 0x2D71E9C974539BB3FFB4B115E66A23D0F62A641EA66C4016E903454C8753BBC, - "private_key": 0x33003003001800009900180300D206308B0070DB00121318D17B5E6262150B, + "address": 0x2AF9427C5A277474C079A1283C880EE8A6F0F8FBF73CE969C08D88BEFEC1BBA, + "private_key": 0x1800000000300000180000000000030000000000003006001800006600, }, { - "address": 0x3EBB4767AAE1262F8EB28D9368DB5388CFE367F50552A8244123506F0B0BCCA, - "private_key": 0x3E3979C1ED728490308054FE357A9F49CF67F80F9721F44CC57235129E090F4, + "address": 0x359B9068EADCAAA449C08B79A367C6FDFBA9448C29E96934E3552DAB0FDD950, + "private_key": 0x2BBF4F9FD0BBB2E60B0316C1FE0B76CF7A4D0198BD493CED9B8DF2A3A24D68A, }, { - "address": 0x541DA8F7F3AB8247329D22B3987D1FFB181BC8DC7F9611A6ECCEC3B0749A585, - "private_key": 0x736ADBBCDAC7CC600F89051DB1ABBC16B9996B46F6B58A9752A11C1028A8EC8, + "address": 0x4184158A64A82EB982FF702E4041A49DB16FA3A18229AAC4CE88C832BAF56E4, + "private_key": 0x6BF3604BCB41FED6C42BCCA5436EEB65083A982FF65DB0DC123F65358008B51, }, { - "address": 0x56C155B624FDF6BFC94F7B37CF1DBEBB5E186EF2E4AB2762367CD07C8F892A1, - "private_key": 0x6BF3604BCB41FED6C42BCCA5436EEB65083A982FF65DB0DC123F65358008B51, + "address": 0x42B249D1633812D903F303D640A4261F58FEAD5AA24925A9EFC1DD9D76FB555, + "private_key": 0x283D1E73776CD4AC1AC5F0B879F561BDED25ECEB2CC589C674AF0CEC41DF441, }, { - "address": 0x6162896D1D7AB204C7CCAC6DD5F8E9E7C25ECD5AE4FCB4AD32E57786BB46E03, - "private_key": 0x1800000000300000180000000000030000000000003006001800006600, + "address": 0x4E0B838810CB1A355BEB7B3D894CA0E98EE524309C3F8B7CCCB15A48E6270E2, + "private_key": 0x736ADBBCDAC7CC600F89051DB1ABBC16B9996B46F6B58A9752A11C1028A8EC8, }, { - "address": 0x66EFB28AC62686966AE85095FF3A772E014E7FBF56D4C5F6FAC5606D4DDE23A, - "private_key": 0x283D1E73776CD4AC1AC5F0B879F561BDED25ECEB2CC589C674AF0CEC41DF441, + "address": 0x5B6B8189BB580F0DF1E6D6BEC509FF0D6C9BE7365D10627E0CF222EC1B47A71, + "private_key": 0x33003003001800009900180300D206308B0070DB00121318D17B5E6262150B, }, { - "address": 0x6B86E40118F29EBE393A75469B4D926C7A44C2E2681B6D319520B7C1156D114, - "private_key": 0x1C9053C053EDF324AEC366A34C6901B1095B07AF69495BFFEC7D7FE21EFFB1B, + "address": 0x6677FE62EE39C7B07401F754138502BAB7FAC99D2D3C5D37DF7D1C6FAB10819, + "private_key": 0x3E3979C1ED728490308054FE357A9F49CF67F80F9721F44CC57235129E090F4, }, ], }, diff --git a/kakarot_scripts/deployment/dualvm_token_deployments.py b/kakarot_scripts/deployment/dualvm_token_deployments.py index 1960c05ab..6e6cb918d 100644 --- a/kakarot_scripts/deployment/dualvm_token_deployments.py +++ b/kakarot_scripts/deployment/dualvm_token_deployments.py @@ -16,6 +16,7 @@ from kakarot_scripts.utils.kakarot import deploy_and_fund_evm_address from kakarot_scripts.utils.kakarot import dump_deployments as dump_evm_deployments from kakarot_scripts.utils.kakarot import get_deployments as get_evm_deployments +from kakarot_scripts.utils.starknet import call_contract from kakarot_scripts.utils.starknet import deploy as deploy_starknet from kakarot_scripts.utils.starknet import execute_calls, get_class_hash_at from kakarot_scripts.utils.starknet import get_contract as get_contract_starknet @@ -30,9 +31,9 @@ logging.basicConfig() logger = logging.getLogger(__name__) logger.setLevel(logging.INFO) -# %% +# %% async def deploy_starknet_token() -> Any: owner = await get_starknet_account() address = await deploy_starknet( @@ -64,10 +65,15 @@ async def deploy_dualvm_token( async def deploy_dualvm_tokens() -> None: # %% Deploy DualVM Tokens kakarot = get_starknet_deployments()["kakarot"] + kakarot_native_token = ( + await call_contract("kakarot", "get_native_token") + ).native_token_address evm_deployments = get_evm_deployments() tokens = get_tokens_list(NETWORK) - for token in tokens: + if int(token["l2_token_address"], 16) == kakarot_native_token: + logger.info(f"Skipping {token['name']} as it is the native token") + continue if token["name"] not in evm_deployments: await deploy_new_token(token, kakarot, evm_deployments) else: @@ -91,11 +97,16 @@ def get_tokens_list(network) -> List[Dict[str, Any]]: def load_tokens(network_name: str) -> List[Dict[str, Any]]: + """ + Load the list of tokens for a given network, using the starknet.io token list. + Filters out entries without an l2_token_address (which are not bridged tokens). + """ file_path = TOKEN_ADDRESSES_DIR / f"{network_name}.json" if not file_path.exists(): raise ValueError(f"No known token addresses for network: {network_name}") - return json.loads(file_path.read_text()) + tokens = json.loads(file_path.read_text()) + return [token for token in tokens if "l2_token_address" in token] async def deploy_new_token( @@ -107,7 +118,7 @@ async def deploy_new_token( Deploy a new DualVMToken for a corresponding Starknet ERC20 token. """ token_name = token["name"] - l2_token_address = await ensure_starknet_token(token_name, token) + l2_token_address = await get_starknet_token(token) contract = await deploy_dualvm_token(kakarot, l2_token_address) evm_deployments[token_name] = { "address": int(contract.address, 16), @@ -129,7 +140,7 @@ async def verify_and_update_existing_token( token_name = token["name"] dualvm_token_address = evm_deployments[token_name]["starknet_address"] if not await get_class_hash_at(dualvm_token_address): - l2_token_address = await ensure_starknet_token(token_name, token) + l2_token_address = await get_starknet_token(token) contract = await deploy_dualvm_token(kakarot, l2_token_address) evm_deployments[token_name] = { "address": int(contract.address, 16), @@ -142,11 +153,12 @@ async def verify_and_update_existing_token( logger.info(f"Existing DualVMToken for {token_name} is valid") -async def ensure_starknet_token(token_name: str, token: Dict[str, Any]) -> str: +async def get_starknet_token(token: Dict[str, Any]) -> str: """ - Ensure a Starknet ERC20 token exists for a given dualVM token. - If not, deploys a new one in dev networks, or returns the starknet address in production networks. + Return the starknet address of the ERC20 token corresponding to a given dualVM token. + If it doesn't exist yet, deploys a new one in dev networks. """ + token_name = token["name"] if NETWORK["type"] == NetworkType.DEV: try: RPC_CLIENT.get_class_hash_at(token["l2_token_address"]) diff --git a/kakarot_scripts/setup/setup.py b/kakarot_scripts/setup/setup.py index 3be74886c..4ad58991a 100644 --- a/kakarot_scripts/setup/setup.py +++ b/kakarot_scripts/setup/setup.py @@ -7,7 +7,7 @@ import sys from typing import Optional -KATANA_VERSION = "v1.0.0-alpha.16" +KATANA_VERSION = "v1.0.0-rc.0" ASDF_VERSION = "v0.14.1" SHELL_CONFIG_FILES = { diff --git a/kakarot_scripts/utils/starknet.py b/kakarot_scripts/utils/starknet.py index 3d7e15b95..8be66dbb0 100644 --- a/kakarot_scripts/utils/starknet.py +++ b/kakarot_scripts/utils/starknet.py @@ -670,7 +670,7 @@ async def invoke( """ account = account or await get_starknet_account() logger.info( - f"ℹ️ Invoking {contract_id}.{function_name}({(json.dumps(calldata) if len(json.dumps(calldata)) < 100 else '...') if calldata else ''})" + f"ℹ️ Invoking {contract_id}.{function_name}({(json.dumps(calldata) if len(json.dumps(calldata)) < 50 else '...') if calldata else ''})" ) if isinstance(contract_id, int): call = Call( From f7083675d299db9d78303bea411792774527f93d Mon Sep 17 00:00:00 2001 From: enitrat Date: Fri, 1 Nov 2024 10:40:57 +0700 Subject: [PATCH 08/20] use CairoLib to transfer Coinbase funds in deploy scripts --- kakarot_scripts/deployment/evm_deployments.py | 12 ++++------ solidity_contracts/src/Kakarot/Coinbase.sol | 23 ++++++++++++------- 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/kakarot_scripts/deployment/evm_deployments.py b/kakarot_scripts/deployment/evm_deployments.py index 7c934d956..020ebf6fe 100644 --- a/kakarot_scripts/deployment/evm_deployments.py +++ b/kakarot_scripts/deployment/evm_deployments.py @@ -1,7 +1,6 @@ # %% Imports import logging -from eth_utils.address import to_checksum_address from uvloop import run from kakarot_scripts.constants import EVM_ADDRESS, NETWORK, RPC_CLIENT, NetworkType @@ -9,7 +8,7 @@ from kakarot_scripts.utils.kakarot import deploy_and_fund_evm_address from kakarot_scripts.utils.kakarot import dump_deployments as dump_evm_deployments from kakarot_scripts.utils.kakarot import get_deployments as get_evm_deployments -from kakarot_scripts.utils.starknet import call, execute_calls +from kakarot_scripts.utils.starknet import call, call_contract, execute_calls from kakarot_scripts.utils.starknet import get_deployments as get_starknet_deployments from kakarot_scripts.utils.starknet import ( get_starknet_account, @@ -60,11 +59,10 @@ async def deploy_evm_contracts(): # %% Coinbase coinbase = (await call("kakarot", "get_coinbase")).coinbase if evm_deployments.get("Coinbase", {}).get("address") != coinbase: - contract = await deploy_evm( - "Kakarot", - "Coinbase", - to_checksum_address(f'{evm_deployments["Ether"]["address"]:040x}'), - ) + kakarot_native_token = ( + await call_contract("kakarot", "get_native_token") + ).native_token_address + contract = await deploy_evm("Kakarot", "Coinbase", kakarot_native_token) evm_deployments["Coinbase"] = { "address": int(contract.address, 16), "starknet_address": contract.starknet_address, diff --git a/solidity_contracts/src/Kakarot/Coinbase.sol b/solidity_contracts/src/Kakarot/Coinbase.sol index e26f186a9..ee5aec511 100644 --- a/solidity_contracts/src/Kakarot/Coinbase.sol +++ b/solidity_contracts/src/Kakarot/Coinbase.sol @@ -1,23 +1,30 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.27; -import {DualVmToken} from "../CairoPrecompiles/DualVmToken.sol"; import {Ownable2Step, Ownable} from "@openzeppelin-contracts/access/Ownable2Step.sol"; +import {CairoLib} from "kakarot-lib/CairoLib.sol"; contract Coinbase is Ownable2Step { - /// @dev The EVM address of the DualVmToken for Kakarot ETH. - DualVmToken public immutable kakarotEth; + using CairoLib for uint256; + + uint256 public immutable nativeTokenStarknetAddress; /// Constructor sets the owner of the contract - constructor(address _kakarotEth) Ownable(msg.sender) { - kakarotEth = DualVmToken(_kakarotEth); + constructor(uint256 _nativeTokenStarknetAddress) Ownable(msg.sender) { + nativeTokenStarknetAddress = _nativeTokenStarknetAddress; } - /// @notice Withdraws ETH from the contract to a Starknet address - /// @dev DualVmToken.balanceOf(this) is the same as address(this).balance + /// @notice Withdraws the native token collected by the contract to an address + /// @dev Uses CairoLib to make a StarknetCall to transfer this contract's balance to a starknet address. /// @param toStarknetAddress The Starknet address to withdraw to function withdraw(uint256 toStarknetAddress) external onlyOwner { uint256 balance = address(this).balance; - kakarotEth.transfer(toStarknetAddress, balance); + uint128 balanceLow = uint128(balance & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + uint128 balanceHigh = uint128(balance >> 128); + uint256[] memory data = new uint256[](3); + data[0] = toStarknetAddress; // recipient + data[1] = balanceLow; + data[2] = balanceHigh; + nativeTokenStarknetAddress.callCairo("transfer", data); } } From 822026acf21c2caf9026de80c5e15af194738bde Mon Sep 17 00:00:00 2001 From: enitrat Date: Tue, 5 Nov 2024 12:55:54 +0700 Subject: [PATCH 09/20] revert katana bump --- .env.example | 4 ++-- kakarot_scripts/constants.py | 38 +++++++++++++++++----------------- kakarot_scripts/setup/setup.py | 2 +- 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/.env.example b/.env.example index 06b8cb6b7..2d56de342 100644 --- a/.env.example +++ b/.env.example @@ -23,8 +23,8 @@ STARKNET_SEPOLIA_RELAYER_PRIVATE_KEY= STARKNET_SEPOLIA_ACCOUNT_ADDRESS= STARKNET_SEPOLIA_PRIVATE_KEY= -KATANA_ACCOUNT_ADDRESS=0x127fd5f1fe78a71f8bcd1fec63e3fe2f0486b6ecd5c86a0466c3a21fa5cfcec -KATANA_PRIVATE_KEY=0xc5b2fcab997346f3ea1c00b002ecf6f382c5f9c9659a3894eb783c5320f912 +KATANA_ACCOUNT_ADDRESS=0xb3ff441a68610b30fd5e2abbf3a1548eb6ba6f3559f2862bf2dc757e5828ca +KATANA_PRIVATE_KEY=0x2bbf4f9fd0bbb2e60b0316c1fe0b76cf7a4d0198bd493ced9b8df2a3a24d68a # Kakarot Sepolia (Testnet production and Testnet staging) KAKAROT_SEPOLIA_ACCOUNT_ADDRESS= diff --git a/kakarot_scripts/constants.py b/kakarot_scripts/constants.py index 429574fe5..5787d9e02 100644 --- a/kakarot_scripts/constants.py +++ b/kakarot_scripts/constants.py @@ -89,42 +89,42 @@ class NetworkType(Enum): "type": NetworkType.DEV, "check_interval": 0.01, "max_wait": 3, - "relayers": [ + "relayers": [ { - "address": 0x13D9EE239F33FEA4F8785B9E3870ADE909E20A9599AE7CD62C1C292B73AF1B7, - "private_key": 0x1C9053C053EDF324AEC366A34C6901B1095B07AF69495BFFEC7D7FE21EFFB1B, + "address": 0xE29882A1FCBA1E7E10CAD46212257FEA5C752A4F9B1B1EC683C503A2CF5C8A, + "private_key": 0x14D6672DCB4B77CA36A887E9A11CD9D637D5012468175829E9C6E770C61642, }, { - "address": 0x17CC6CA902ED4E8BAA8463A7009FF18CC294FA85A94B4CE6AC30A9EBD6057C7, - "private_key": 0x14D6672DCB4B77CA36A887E9A11CD9D637D5012468175829E9C6E770C61642, + "address": 0x29873C310FBEFDE666DC32A1554FEA6BB45EECC84F680F8A2B0A8FBB8CB89AF, + "private_key": 0xC5B2FCAB997346F3EA1C00B002ECF6F382C5F9C9659A3894EB783C5320F912, }, { - "address": 0x2AF9427C5A277474C079A1283C880EE8A6F0F8FBF73CE969C08D88BEFEC1BBA, - "private_key": 0x1800000000300000180000000000030000000000003006001800006600, + "address": 0x2D71E9C974539BB3FFB4B115E66A23D0F62A641EA66C4016E903454C8753BBC, + "private_key": 0x33003003001800009900180300D206308B0070DB00121318D17B5E6262150B, }, { - "address": 0x359B9068EADCAAA449C08B79A367C6FDFBA9448C29E96934E3552DAB0FDD950, - "private_key": 0x2BBF4F9FD0BBB2E60B0316C1FE0B76CF7A4D0198BD493CED9B8DF2A3A24D68A, + "address": 0x3EBB4767AAE1262F8EB28D9368DB5388CFE367F50552A8244123506F0B0BCCA, + "private_key": 0x3E3979C1ED728490308054FE357A9F49CF67F80F9721F44CC57235129E090F4, }, { - "address": 0x4184158A64A82EB982FF702E4041A49DB16FA3A18229AAC4CE88C832BAF56E4, - "private_key": 0x6BF3604BCB41FED6C42BCCA5436EEB65083A982FF65DB0DC123F65358008B51, + "address": 0x541DA8F7F3AB8247329D22B3987D1FFB181BC8DC7F9611A6ECCEC3B0749A585, + "private_key": 0x736ADBBCDAC7CC600F89051DB1ABBC16B9996B46F6B58A9752A11C1028A8EC8, }, { - "address": 0x42B249D1633812D903F303D640A4261F58FEAD5AA24925A9EFC1DD9D76FB555, - "private_key": 0x283D1E73776CD4AC1AC5F0B879F561BDED25ECEB2CC589C674AF0CEC41DF441, + "address": 0x56C155B624FDF6BFC94F7B37CF1DBEBB5E186EF2E4AB2762367CD07C8F892A1, + "private_key": 0x6BF3604BCB41FED6C42BCCA5436EEB65083A982FF65DB0DC123F65358008B51, }, { - "address": 0x4E0B838810CB1A355BEB7B3D894CA0E98EE524309C3F8B7CCCB15A48E6270E2, - "private_key": 0x736ADBBCDAC7CC600F89051DB1ABBC16B9996B46F6B58A9752A11C1028A8EC8, + "address": 0x6162896D1D7AB204C7CCAC6DD5F8E9E7C25ECD5AE4FCB4AD32E57786BB46E03, + "private_key": 0x1800000000300000180000000000030000000000003006001800006600, }, { - "address": 0x5B6B8189BB580F0DF1E6D6BEC509FF0D6C9BE7365D10627E0CF222EC1B47A71, - "private_key": 0x33003003001800009900180300D206308B0070DB00121318D17B5E6262150B, + "address": 0x66EFB28AC62686966AE85095FF3A772E014E7FBF56D4C5F6FAC5606D4DDE23A, + "private_key": 0x283D1E73776CD4AC1AC5F0B879F561BDED25ECEB2CC589C674AF0CEC41DF441, }, { - "address": 0x6677FE62EE39C7B07401F754138502BAB7FAC99D2D3C5D37DF7D1C6FAB10819, - "private_key": 0x3E3979C1ED728490308054FE357A9F49CF67F80F9721F44CC57235129E090F4, + "address": 0x6B86E40118F29EBE393A75469B4D926C7A44C2E2681B6D319520B7C1156D114, + "private_key": 0x1C9053C053EDF324AEC366A34C6901B1095B07AF69495BFFEC7D7FE21EFFB1B, }, ], }, diff --git a/kakarot_scripts/setup/setup.py b/kakarot_scripts/setup/setup.py index 4ad58991a..3be74886c 100644 --- a/kakarot_scripts/setup/setup.py +++ b/kakarot_scripts/setup/setup.py @@ -7,7 +7,7 @@ import sys from typing import Optional -KATANA_VERSION = "v1.0.0-rc.0" +KATANA_VERSION = "v1.0.0-alpha.16" ASDF_VERSION = "v0.14.1" SHELL_CONFIG_FILES = { From 1294ac5d02d76f2ce37ef8bd1b39ea7aac248ce3 Mon Sep 17 00:00:00 2001 From: enitrat Date: Tue, 5 Nov 2024 14:54:30 +0700 Subject: [PATCH 10/20] dev: send remaining eoa ETH to coinbase after TX --- .../starknet-sepolia/kakarot_deployments.json | 2 +- kakarot_scripts/constants.py | 2 +- kakarot_scripts/deployment/evm_deployments.py | 1 + solidity_contracts/src/Kakarot/Coinbase.sol | 4 +- .../CairoPrecompiles/test_dual_vm_token.py | 65 ++++++++----------- tests/end_to_end/conftest.py | 14 ++-- 6 files changed, 39 insertions(+), 49 deletions(-) diff --git a/deployments/starknet-sepolia/kakarot_deployments.json b/deployments/starknet-sepolia/kakarot_deployments.json index 43a7df8c5..3aa4c909f 100644 --- a/deployments/starknet-sepolia/kakarot_deployments.json +++ b/deployments/starknet-sepolia/kakarot_deployments.json @@ -31,4 +31,4 @@ "address": "0xba5ed099633d3b313e4d5f7bdc1305d3c28ba5ed", "starknet_address": "0x2361be1b7ded312bfc16c2547eaaf2308d3c9b6aa9037d8fc9ee57329f00951" } -} \ No newline at end of file +} diff --git a/kakarot_scripts/constants.py b/kakarot_scripts/constants.py index 5787d9e02..93cb97b0c 100644 --- a/kakarot_scripts/constants.py +++ b/kakarot_scripts/constants.py @@ -89,7 +89,7 @@ class NetworkType(Enum): "type": NetworkType.DEV, "check_interval": 0.01, "max_wait": 3, - "relayers": [ + "relayers": [ { "address": 0xE29882A1FCBA1E7E10CAD46212257FEA5C752A4F9B1B1EC683C503A2CF5C8A, "private_key": 0x14D6672DCB4B77CA36A887E9A11CD9D637D5012468175829E9C6E770C61642, diff --git a/kakarot_scripts/deployment/evm_deployments.py b/kakarot_scripts/deployment/evm_deployments.py index 020ebf6fe..222f2d8a2 100644 --- a/kakarot_scripts/deployment/evm_deployments.py +++ b/kakarot_scripts/deployment/evm_deployments.py @@ -67,6 +67,7 @@ async def deploy_evm_contracts(): "address": int(contract.address, 16), "starknet_address": contract.starknet_address, } + logger.info(f"✅ Coinbase deployed at {contract.address}") await invoke("kakarot", "set_coinbase", int(contract.address, 16)) # %% Tear down diff --git a/solidity_contracts/src/Kakarot/Coinbase.sol b/solidity_contracts/src/Kakarot/Coinbase.sol index ee5aec511..90cde15b6 100644 --- a/solidity_contracts/src/Kakarot/Coinbase.sol +++ b/solidity_contracts/src/Kakarot/Coinbase.sol @@ -14,12 +14,14 @@ contract Coinbase is Ownable2Step { nativeTokenStarknetAddress = _nativeTokenStarknetAddress; } + receive() external payable {} + /// @notice Withdraws the native token collected by the contract to an address /// @dev Uses CairoLib to make a StarknetCall to transfer this contract's balance to a starknet address. /// @param toStarknetAddress The Starknet address to withdraw to function withdraw(uint256 toStarknetAddress) external onlyOwner { uint256 balance = address(this).balance; - uint128 balanceLow = uint128(balance & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + uint128 balanceLow = uint128(balance); uint128 balanceHigh = uint128(balance >> 128); uint256[] memory data = new uint256[](3); data[0] = toStarknetAddress; // recipient diff --git a/tests/end_to_end/CairoPrecompiles/test_dual_vm_token.py b/tests/end_to_end/CairoPrecompiles/test_dual_vm_token.py index 9cd37baf9..493c06223 100644 --- a/tests/end_to_end/CairoPrecompiles/test_dual_vm_token.py +++ b/tests/end_to_end/CairoPrecompiles/test_dual_vm_token.py @@ -2,8 +2,8 @@ import pytest_asyncio from eth_utils import keccak -from kakarot_scripts.utils.kakarot import get_contract as get_contract_evm -from kakarot_scripts.utils.kakarot import get_deployments as get_evm_deployments +from kakarot_scripts.utils.kakarot import deploy as deploy_kakarot +from kakarot_scripts.utils.starknet import deploy as deploy_starknet from kakarot_scripts.utils.starknet import get_contract as get_contract_starknet from kakarot_scripts.utils.starknet import ( get_starknet_account, @@ -13,25 +13,35 @@ from tests.utils.errors import cairo_error -@pytest_asyncio.fixture(scope="session") -async def dual_vm_token(owner): - evm_deployments = get_evm_deployments() - ether = evm_deployments["Ether"]["address"] - return await get_contract_evm( +@pytest_asyncio.fixture(scope="function") +async def starknet_token(owner): + address = await deploy_starknet( + "StarknetToken", + "MyToken", + "MTK", + int(2**256 - 1), + owner.starknet_contract.address, + ) + return get_contract_starknet("StarknetToken", address=address) + + +@pytest_asyncio.fixture(scope="function") +async def dual_vm_token(kakarot, starknet_token, owner): + dual_vm_token = await deploy_kakarot( "CairoPrecompiles", "DualVmToken", - address=ether, + kakarot.address, + starknet_token.address, caller_eoa=owner.starknet_contract, ) - -@pytest_asyncio.fixture(scope="session") -async def starknet_token(dual_vm_token): - starknet_address = await dual_vm_token.starknetToken() - deployer = await get_starknet_account() - return get_contract_starknet( - "StarknetToken", address=starknet_address, provider=deployer + await invoke( + "kakarot", + "set_authorized_cairo_precompile_caller", + int(dual_vm_token.address, 16), + True, ) + return dual_vm_token @pytest_asyncio.fixture(scope="function", autouse=True) @@ -54,30 +64,7 @@ async def fund_owner(owner, starknet_token, max_fee): (balance,) = await starknet_token.functions["balance_of"].call( owner.starknet_contract.address ) - assert ( - balance >= amount - ), f"Transfer failed. Expected min balance: {amount}, Actual balance: {balance}" - - -@pytest_asyncio.fixture(scope="function") -async def starknet_token(owner): - address = await deploy_starknet( - "StarknetToken", int(2**256 - 1), owner.starknet_contract.address - ) - return get_contract_starknet("StarknetToken", address=address) - - - -@pytest_asyncio.fixture(scope="function") -async def dual_vm_token(owner): - evm_deployments = get_evm_deployments() - ether = evm_deployments["Ether"]["address"] - return await get_contract_evm( - "CairoPrecompiles", - "DualVmToken", - address=ether, - caller_eoa=owner.starknet_contract, - ) + assert balance >= amount @pytest.mark.asyncio(scope="module") diff --git a/tests/end_to_end/conftest.py b/tests/end_to_end/conftest.py index f9608783a..0c1bb0657 100644 --- a/tests/end_to_end/conftest.py +++ b/tests/end_to_end/conftest.py @@ -73,10 +73,10 @@ async def _factory(amount=0): yield _factory - kakarot_eth = await get_solidity_contract( - "CairoPrecompiles", - "DualVmToken", - address=get_deployments()["Ether"]["address"], + coinbase = await get_solidity_contract( + "Kakarot", + "Coinbase", + address=get_deployments()["Coinbase"]["address"], ) gas_price = (await call("kakarot", "get_base_fee")).base_fee gas_limit = 40_000 @@ -86,10 +86,10 @@ async def _factory(amount=0): if balance < tx_cost: continue - await kakarot_eth.functions["transfer(uint256,uint256)"]( - deployer.address, - balance - tx_cost, + # Send the funds to the coinbase contract. The owner will be able to withdraw them. + await coinbase.functions["receive()"]( caller_eoa=wallet.starknet_contract, + value=balance - tx_cost, gas_limit=gas_limit, gas_price=gas_price, ) From e43669b901e4a7f00f948b8f01d52b36891c5ffd Mon Sep 17 00:00:00 2001 From: enitrat Date: Tue, 5 Nov 2024 15:05:37 +0700 Subject: [PATCH 11/20] add receiveEther function & send eoa funds to coinbase --- solidity_contracts/src/Kakarot/Coinbase.sol | 2 +- tests/end_to_end/conftest.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/solidity_contracts/src/Kakarot/Coinbase.sol b/solidity_contracts/src/Kakarot/Coinbase.sol index 90cde15b6..e673110e1 100644 --- a/solidity_contracts/src/Kakarot/Coinbase.sol +++ b/solidity_contracts/src/Kakarot/Coinbase.sol @@ -14,7 +14,7 @@ contract Coinbase is Ownable2Step { nativeTokenStarknetAddress = _nativeTokenStarknetAddress; } - receive() external payable {} + function receiveEther() external payable {} /// @notice Withdraws the native token collected by the contract to an address /// @dev Uses CairoLib to make a StarknetCall to transfer this contract's balance to a starknet address. diff --git a/tests/end_to_end/conftest.py b/tests/end_to_end/conftest.py index 0c1bb0657..9f9466f67 100644 --- a/tests/end_to_end/conftest.py +++ b/tests/end_to_end/conftest.py @@ -87,7 +87,7 @@ async def _factory(amount=0): continue # Send the funds to the coinbase contract. The owner will be able to withdraw them. - await coinbase.functions["receive()"]( + await coinbase.functions["receiveEther()"]( caller_eoa=wallet.starknet_contract, value=balance - tx_cost, gas_limit=gas_limit, From 6d0869e2f36a0c5645539ccf256444ea4376c10a Mon Sep 17 00:00:00 2001 From: enitrat Date: Tue, 5 Nov 2024 15:16:48 +0700 Subject: [PATCH 12/20] withdraw coinbase funds to deployer for each new_eoa --- tests/end_to_end/conftest.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/end_to_end/conftest.py b/tests/end_to_end/conftest.py index 9f9466f67..1a4e4232e 100644 --- a/tests/end_to_end/conftest.py +++ b/tests/end_to_end/conftest.py @@ -94,6 +94,13 @@ async def _factory(amount=0): gas_price=gas_price, ) + # Withdraw the funds to the deployer + await coinbase.functions["withdraw(uint256)"]( + toStarknetAddress=deployer.address, + gas_limit=gas_limit, + gas_price=gas_price, + ) + @pytest_asyncio.fixture(scope="session") async def owner(new_eoa): From c8bf9367a28fc971939cf98a8ced5d10a4dc8f6f Mon Sep 17 00:00:00 2001 From: enitrat Date: Tue, 5 Nov 2024 16:54:15 +0700 Subject: [PATCH 13/20] address comments --- kakarot_scripts/constants.py | 4 +- .../deployment/dualvm_token_deployments.py | 88 ++++++++----------- .../CairoPrecompiles/test_dual_vm_token.py | 33 +------ 3 files changed, 41 insertions(+), 84 deletions(-) diff --git a/kakarot_scripts/constants.py b/kakarot_scripts/constants.py index 93cb97b0c..01f7a8d58 100644 --- a/kakarot_scripts/constants.py +++ b/kakarot_scripts/constants.py @@ -59,8 +59,8 @@ class NetworkType(Enum): "voyager_api_url": "https://sepolia-api.voyager.online/beta", "argent_multisig_api": "https://cloud.argent-api.com/v1/multisig/starknet/sepolia", }, - "sepolia-staging": { - "name": "starknet-sepolia-staging", + "staging": { + "name": "staging", "explorer_url": "https://sepolia.starkscan.co/", "rpc_url": f"https://rpc.nethermind.io/sepolia-juno/?apikey={os.getenv('NETHERMIND_API_KEY')}", "l1_rpc_url": f"https://sepolia.infura.io/v3/{os.getenv('INFURA_KEY')}", diff --git a/kakarot_scripts/deployment/dualvm_token_deployments.py b/kakarot_scripts/deployment/dualvm_token_deployments.py index 6e6cb918d..11739e20a 100644 --- a/kakarot_scripts/deployment/dualvm_token_deployments.py +++ b/kakarot_scripts/deployment/dualvm_token_deployments.py @@ -34,34 +34,6 @@ # %% -async def deploy_starknet_token() -> Any: - owner = await get_starknet_account() - address = await deploy_starknet( - "StarknetToken", "MyToken", "MTK", int(1e18), owner.address - ) - return get_contract_starknet("StarknetToken", address=address) - - -async def deploy_dualvm_token( - kakarot_address: str, starknet_token_address: str, deployer_account: Any = None -) -> Any: - dual_vm_token = await deploy_kakarot( - "CairoPrecompiles", - "DualVmToken", - kakarot_address, - int(starknet_token_address, 16), - caller_eoa=deployer_account, - ) - - await invoke( - "kakarot", - "set_authorized_cairo_precompile_caller", - int(dual_vm_token.address, 16), - True, - ) - return dual_vm_token - - async def deploy_dualvm_tokens() -> None: # %% Deploy DualVM Tokens kakarot = get_starknet_deployments()["kakarot"] @@ -69,7 +41,7 @@ async def deploy_dualvm_tokens() -> None: await call_contract("kakarot", "get_native_token") ).native_token_address evm_deployments = get_evm_deployments() - tokens = get_tokens_list(NETWORK) + tokens = get_tokens_list() for token in tokens: if int(token["l2_token_address"], 16) == kakarot_native_token: logger.info(f"Skipping {token['name']} as it is the native token") @@ -77,23 +49,24 @@ async def deploy_dualvm_tokens() -> None: if token["name"] not in evm_deployments: await deploy_new_token(token, kakarot, evm_deployments) else: - await verify_and_update_existing_token(token, kakarot, evm_deployments) + is_deployed = await check_dualvm_token_deployment(token, evm_deployments) + if not is_deployed: + await deploy_new_token(token, kakarot, evm_deployments) - logger.info("Finished processing all tokens") + logger.info("Finished processing all DualVM tokens") dump_evm_deployments(evm_deployments) - logger.info("Updated EVM deployments have been saved") # %% -def get_tokens_list(network) -> List[Dict[str, Any]]: +def get_tokens_list() -> List[Dict[str, Any]]: """ Get the list of tokens for a given network. If in dev mode, will return the sepolia token list. """ - if network["type"] == NetworkType.DEV: + if NETWORK["type"] == NetworkType.DEV: return load_tokens("sepolia") - return load_tokens(network["name"]) + return load_tokens(NETWORK["name"]) def load_tokens(network_name: str) -> List[Dict[str, Any]]: @@ -111,7 +84,7 @@ def load_tokens(network_name: str) -> List[Dict[str, Any]]: async def deploy_new_token( token: Dict[str, Any], - kakarot: str, + kakarot_address: str, evm_deployments: Dict[str, Any], ) -> None: """ @@ -119,7 +92,19 @@ async def deploy_new_token( """ token_name = token["name"] l2_token_address = await get_starknet_token(token) - contract = await deploy_dualvm_token(kakarot, l2_token_address) + contract = await deploy_kakarot( + "CairoPrecompiles", + "DualVmToken", + kakarot_address, + int(l2_token_address, 16), + ) + + await invoke( + "kakarot", + "set_authorized_cairo_precompile_caller", + int(contract.address, 16), + True, + ) evm_deployments[token_name] = { "address": int(contract.address, 16), "starknet_address": contract.starknet_address, @@ -129,28 +114,19 @@ async def deploy_new_token( ) -async def verify_and_update_existing_token( +async def check_dualvm_token_deployment( token: Dict[str, Any], - kakarot: str, evm_deployments: Dict[str, Any], -) -> None: +) -> bool: """ - Given an existing DualVMToken, verifies it is _actually_ deployed. If not, deploys a new one. + Given an existing DualVMToken, verifies it is _actually_ deployed. """ token_name = token["name"] dualvm_token_address = evm_deployments[token_name]["starknet_address"] - if not await get_class_hash_at(dualvm_token_address): - l2_token_address = await get_starknet_token(token) - contract = await deploy_dualvm_token(kakarot, l2_token_address) - evm_deployments[token_name] = { - "address": int(contract.address, 16), - "starknet_address": contract.starknet_address, - } - logger.info( - f"Deployed new DualVMToken for {token_name} at address {contract.address}" - ) + if await get_class_hash_at(dualvm_token_address): + return True else: - logger.info(f"Existing DualVMToken for {token_name} is valid") + return False async def get_starknet_token(token: Dict[str, Any]) -> str: @@ -178,6 +154,14 @@ async def get_starknet_token(token: Dict[str, Any]) -> str: return token["l2_token_address"] +async def deploy_starknet_token() -> Any: + owner = await get_starknet_account() + address = await deploy_starknet( + "StarknetToken", "MyToken", "MTK", int(1e18), owner.address + ) + return get_contract_starknet("StarknetToken", address=address) + + # %% Run async def main() -> None: try: diff --git a/tests/end_to_end/CairoPrecompiles/test_dual_vm_token.py b/tests/end_to_end/CairoPrecompiles/test_dual_vm_token.py index 493c06223..bc4210d6d 100644 --- a/tests/end_to_end/CairoPrecompiles/test_dual_vm_token.py +++ b/tests/end_to_end/CairoPrecompiles/test_dual_vm_token.py @@ -5,15 +5,11 @@ from kakarot_scripts.utils.kakarot import deploy as deploy_kakarot from kakarot_scripts.utils.starknet import deploy as deploy_starknet from kakarot_scripts.utils.starknet import get_contract as get_contract_starknet -from kakarot_scripts.utils.starknet import ( - get_starknet_account, - invoke, - wait_for_transaction, -) +from kakarot_scripts.utils.starknet import get_starknet_account, invoke from tests.utils.errors import cairo_error -@pytest_asyncio.fixture(scope="function") +@pytest_asyncio.fixture(scope="module") async def starknet_token(owner): address = await deploy_starknet( "StarknetToken", @@ -25,7 +21,7 @@ async def starknet_token(owner): return get_contract_starknet("StarknetToken", address=address) -@pytest_asyncio.fixture(scope="function") +@pytest_asyncio.fixture(scope="module") async def dual_vm_token(kakarot, starknet_token, owner): dual_vm_token = await deploy_kakarot( "CairoPrecompiles", @@ -44,29 +40,6 @@ async def dual_vm_token(kakarot, starknet_token, owner): return dual_vm_token -@pytest_asyncio.fixture(scope="function", autouse=True) -async def fund_owner(owner, starknet_token, max_fee): - (balance_before,) = await starknet_token.functions["balance_of"].call( - owner.starknet_contract.address - ) - - amount = int(1e16) - if balance_before > amount: - return - - tx = await starknet_token.functions["transfer"].invoke_v1( - owner.starknet_contract.address, - amount, - max_fee=max_fee, - ) - await wait_for_transaction(tx.hash) - - (balance,) = await starknet_token.functions["balance_of"].call( - owner.starknet_contract.address - ) - assert balance >= amount - - @pytest.mark.asyncio(scope="module") @pytest.mark.CairoPrecompiles class TestDualVmToken: From d2e8725f097bba020ee5d277554d5b49d08c59cd Mon Sep 17 00:00:00 2001 From: enitrat Date: Tue, 5 Nov 2024 17:22:22 +0700 Subject: [PATCH 14/20] fix: coinbase tests --- .../CairoPrecompiles/test_dual_vm_token.py | 6 +++--- tests/end_to_end/Kakarot/test_coinbase.py | 20 ++++++------------- 2 files changed, 9 insertions(+), 17 deletions(-) diff --git a/tests/end_to_end/CairoPrecompiles/test_dual_vm_token.py b/tests/end_to_end/CairoPrecompiles/test_dual_vm_token.py index bc4210d6d..609f07127 100644 --- a/tests/end_to_end/CairoPrecompiles/test_dual_vm_token.py +++ b/tests/end_to_end/CairoPrecompiles/test_dual_vm_token.py @@ -9,7 +9,7 @@ from tests.utils.errors import cairo_error -@pytest_asyncio.fixture(scope="module") +@pytest_asyncio.fixture(scope="package") async def starknet_token(owner): address = await deploy_starknet( "StarknetToken", @@ -21,7 +21,7 @@ async def starknet_token(owner): return get_contract_starknet("StarknetToken", address=address) -@pytest_asyncio.fixture(scope="module") +@pytest_asyncio.fixture(scope="package") async def dual_vm_token(kakarot, starknet_token, owner): dual_vm_token = await deploy_kakarot( "CairoPrecompiles", @@ -40,7 +40,7 @@ async def dual_vm_token(kakarot, starknet_token, owner): return dual_vm_token -@pytest.mark.asyncio(scope="module") +@pytest.mark.asyncio(scope="package") @pytest.mark.CairoPrecompiles class TestDualVmToken: class TestMetadata: diff --git a/tests/end_to_end/Kakarot/test_coinbase.py b/tests/end_to_end/Kakarot/test_coinbase.py index 5310eba32..1c82a5496 100644 --- a/tests/end_to_end/Kakarot/test_coinbase.py +++ b/tests/end_to_end/Kakarot/test_coinbase.py @@ -5,25 +5,17 @@ from eth_utils.address import to_checksum_address from kakarot_scripts.utils.kakarot import deploy, eth_balance_of, fund_address -from kakarot_scripts.utils.starknet import invoke +from kakarot_scripts.utils.starknet import call_contract from tests.utils.errors import evm_error @pytest_asyncio.fixture(scope="package") -async def kakarot_eth(kakarot, eth): - token = await deploy( - "CairoPrecompiles", "DualVmToken", kakarot.address, eth.address - ) - await invoke( - "kakarot", "set_authorized_cairo_precompile_caller", int(token.address, 16), 1 - ) - return token - - -@pytest_asyncio.fixture(scope="package") -async def coinbase(owner, kakarot_eth): +async def coinbase(owner): + kakarot_native_token = ( + await call_contract("kakarot", "get_native_token") + ).native_token_address return await deploy( - "Kakarot", "Coinbase", kakarot_eth.address, caller_eoa=owner.starknet_contract + "Kakarot", "Coinbase", kakarot_native_token, caller_eoa=owner.starknet_contract ) From b8902cd792e6e75c79388c5706946f652d0e52a3 Mon Sep 17 00:00:00 2001 From: enitrat Date: Tue, 5 Nov 2024 17:38:59 +0700 Subject: [PATCH 15/20] dev: add receive to Coinbase, modify wrap_kakarot to enable arbitraty transactions --- kakarot_scripts/utils/kakarot.py | 20 ++++++++++++++------ solidity_contracts/src/Kakarot/Coinbase.sol | 2 +- tests/end_to_end/Kakarot/test_coinbase.py | 13 +++++++++++++ tests/end_to_end/conftest.py | 2 +- 4 files changed, 29 insertions(+), 8 deletions(-) diff --git a/kakarot_scripts/utils/kakarot.py b/kakarot_scripts/utils/kakarot.py index 9fd8de744..0654984c0 100644 --- a/kakarot_scripts/utils/kakarot.py +++ b/kakarot_scripts/utils/kakarot.py @@ -182,6 +182,9 @@ async def get_contract( except NoABIFunctionsFound: pass contract.events.parse_events = MethodType(_parse_events, contract.events) + contract.w3.eth.send_transaction = MethodType( + _wrap_kakarot(fun=None, caller_eoa=caller_eoa), contract + ) return contract @@ -399,21 +402,26 @@ def _get_matching_logs_for_event(event_abi, log_receipts) -> List[dict]: return logs -def _wrap_kakarot(fun: str, caller_eoa: Optional[Account] = None): +def _wrap_kakarot(fun: Optional[str] = None, caller_eoa: Optional[Account] = None): """Wrap a contract function call with the Kakarot contract.""" async def _wrapper(self, *args, **kwargs): - abi = self.get_function_by_signature(fun).abi gas_price = kwargs.pop("gas_price", DEFAULT_GAS_PRICE) gas_limit = kwargs.pop("gas_limit", TRANSACTION_GAS_LIMIT) value = kwargs.pop("value", 0) caller_eoa_ = kwargs.pop("caller_eoa", caller_eoa) max_fee = kwargs.pop("max_fee", None) - calldata = self.get_function_by_signature(fun)( - *args, **kwargs - )._encode_transaction_data() - if abi["stateMutability"] in ["pure", "view"]: + if fun is not None: + abi = self.get_function_by_signature(fun).abi + calldata = self.get_function_by_signature(fun)( + *args, **kwargs + )._encode_transaction_data() + else: + calldata = b"" + abi = {} + + if abi.get("stateMutability") in ["pure", "view"]: origin = ( int(caller_eoa_.signer.public_key.to_address(), 16) if caller_eoa_ diff --git a/solidity_contracts/src/Kakarot/Coinbase.sol b/solidity_contracts/src/Kakarot/Coinbase.sol index e673110e1..90cde15b6 100644 --- a/solidity_contracts/src/Kakarot/Coinbase.sol +++ b/solidity_contracts/src/Kakarot/Coinbase.sol @@ -14,7 +14,7 @@ contract Coinbase is Ownable2Step { nativeTokenStarknetAddress = _nativeTokenStarknetAddress; } - function receiveEther() external payable {} + receive() external payable {} /// @notice Withdraws the native token collected by the contract to an address /// @dev Uses CairoLib to make a StarknetCall to transfer this contract's balance to a starknet address. diff --git a/tests/end_to_end/Kakarot/test_coinbase.py b/tests/end_to_end/Kakarot/test_coinbase.py index 1c82a5496..4cffb370e 100644 --- a/tests/end_to_end/Kakarot/test_coinbase.py +++ b/tests/end_to_end/Kakarot/test_coinbase.py @@ -3,6 +3,7 @@ from eth_abi import encode from eth_utils import keccak from eth_utils.address import to_checksum_address +from web3.contract import Contract as Web3Contract from kakarot_scripts.utils.kakarot import deploy, eth_balance_of, fund_address from kakarot_scripts.utils.starknet import call_contract @@ -40,6 +41,18 @@ async def test_should_revert_when_not_owner(self, coinbase, other): with evm_error(error): await coinbase.withdraw(0xDEAD, caller_eoa=other.starknet_contract) + class TestReceive: + async def test_should_receive_ether(self, coinbase: Web3Contract, owner): + amount = 0.001 + amount_wei = int(amount * 1e18) + await fund_address(owner.address, 0.001) + balance_coinbase_prev = await eth_balance_of(coinbase.address) + await coinbase.w3.eth.send_transaction( + caller_eoa=owner.starknet_contract, value=amount_wei + ) + balance_coinbase_after = await eth_balance_of(coinbase.address) + assert balance_coinbase_after == balance_coinbase_prev + amount_wei + class TestTransferOwnership: async def test_should_transfer_ownership(self, coinbase, owner, other): diff --git a/tests/end_to_end/conftest.py b/tests/end_to_end/conftest.py index 1a4e4232e..8ece86771 100644 --- a/tests/end_to_end/conftest.py +++ b/tests/end_to_end/conftest.py @@ -87,7 +87,7 @@ async def _factory(amount=0): continue # Send the funds to the coinbase contract. The owner will be able to withdraw them. - await coinbase.functions["receiveEther()"]( + await coinbase.w3.eth.send_transaction( caller_eoa=wallet.starknet_contract, value=balance - tx_cost, gas_limit=gas_limit, From e21c3d01075e59a91812e4c028fa736a61ee6cba Mon Sep 17 00:00:00 2001 From: enitrat Date: Tue, 5 Nov 2024 18:43:32 +0700 Subject: [PATCH 16/20] remove usage of KakarotEth in tests --- tests/end_to_end/test_kakarot.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/end_to_end/test_kakarot.py b/tests/end_to_end/test_kakarot.py index 632440db8..1f7834d94 100644 --- a/tests/end_to_end/test_kakarot.py +++ b/tests/end_to_end/test_kakarot.py @@ -341,13 +341,13 @@ async def test_should_return_transaction_count(self, new_eoa): ).tx_count assert tx_count == 0 - kakarot_eth = await get_solidity_contract( - "CairoPrecompiles", - "DualVmToken", - address=get_deployments()["KakarotETH"]["address"], + weth9 = await get_solidity_contract( + "WETH", + "WETH9", + address=get_deployments()["WETH9"]["address"], ) - await kakarot_eth.functions["transfer(address,uint256)"]( - ZERO_ADDRESS, 1, caller_eoa=eoa.starknet_contract + await weth9.functions["deposit()"]( + caller_eoa=eoa.starknet_contract, value=1 ) tx_count = ( From 107561b4b76fb55444aff68edba8b439fa7b9504 Mon Sep 17 00:00:00 2001 From: enitrat Date: Tue, 5 Nov 2024 21:01:46 +0700 Subject: [PATCH 17/20] make deploy flow more readable + add custom decimals to StarknetToken --- cairo/token/src/starknet_token.cairo | 33 ++- kakarot_scripts/constants.py | 7 +- .../deployment/dualvm_token_deployments.py | 220 ++++++++---------- kakarot_scripts/deployment/main.py | 4 +- kakarot_scripts/utils/kakarot.py | 2 +- .../CairoPrecompiles/test_dual_vm_token.py | 1 + tests/end_to_end/test_kakarot.py | 2 +- 7 files changed, 138 insertions(+), 131 deletions(-) diff --git a/cairo/token/src/starknet_token.cairo b/cairo/token/src/starknet_token.cairo index c0f9a0269..ddd4ee728 100644 --- a/cairo/token/src/starknet_token.cairo +++ b/cairo/token/src/starknet_token.cairo @@ -1,6 +1,7 @@ #[starknet::contract] mod StarknetToken { use openzeppelin::token::erc20::ERC20Component; + use openzeppelin::token::erc20::interface::IERC20Metadata; use starknet::ContractAddress; component!(path: ERC20Component, storage: erc20, event: ERC20Event); @@ -9,14 +10,13 @@ mod StarknetToken { impl ERC20Impl = ERC20Component::ERC20Impl; #[abi(embed_v0)] impl ERC20CamelOnlyImpl = ERC20Component::ERC20CamelOnlyImpl; - #[abi(embed_v0)] - impl ERC20MetadataImpl = ERC20Component::ERC20MetadataImpl; impl ERC20InternalImpl = ERC20Component::InternalImpl; #[storage] struct Storage { #[substorage(v0)] - erc20: ERC20Component::Storage + erc20: ERC20Component::Storage, + decimals: u8, } #[event] @@ -27,7 +27,10 @@ mod StarknetToken { } #[constructor] - fn constructor(ref self: ContractState, name: ByteArray, symbol: ByteArray, initial_supply: u256, recipient: ContractAddress) { + fn constructor(ref self: ContractState, name: ByteArray, symbol: ByteArray, decimals: u8, initial_supply: u256, recipient: ContractAddress) { + self._set_decimals(decimals); + + // ERC20 initialization self.erc20.initializer(name, symbol); self.erc20._mint(recipient, initial_supply); } @@ -36,4 +39,26 @@ mod StarknetToken { fn mint(ref self: ContractState, to: ContractAddress, amount: u256) { self.erc20._mint(to, amount); } + + #[abi(embed_v0)] + impl ERC20MetadataImpl of IERC20Metadata { + fn name(self: @ContractState) -> ByteArray { + self.erc20.name() + } + + fn symbol(self: @ContractState) -> ByteArray { + self.erc20.symbol() + } + + fn decimals(self: @ContractState) -> u8 { + self.decimals.read() + } + } + + #[generate_trait] + impl InternalImpl of InternalTrait { + fn _set_decimals(ref self: ContractState, decimals: u8) { + self.decimals.write(decimals); + } + } } diff --git a/kakarot_scripts/constants.py b/kakarot_scripts/constants.py index 01f7a8d58..b52d921a9 100644 --- a/kakarot_scripts/constants.py +++ b/kakarot_scripts/constants.py @@ -25,6 +25,8 @@ # see https://gist.github.com/rekmarks/a47bd5f2525936c4b8eee31a16345553 MAX_SAFE_CHAIN_ID = 4503599627370476 +TOKEN_ADDRESSES_DIR = Path("starknet-addresses/bridged_tokens") + class NetworkType(Enum): PROD = "prod" @@ -45,6 +47,7 @@ class NetworkType(Enum): "class_hash": 0x061DAC032F228ABEF9C6626F995015233097AE253A7F72D68552DB02F2971B8F, "voyager_api_url": "https://api.voyager.online/beta", "argent_multisig_api": "https://cloud.argent-api.com/v1/multisig/starknet/mainnet", + "token_addresses_file": TOKEN_ADDRESSES_DIR / "mainnet.json", }, "sepolia": { "name": "sepolia", @@ -58,6 +61,7 @@ class NetworkType(Enum): "class_hash": 0x061DAC032F228ABEF9C6626F995015233097AE253A7F72D68552DB02F2971B8F, "voyager_api_url": "https://sepolia-api.voyager.online/beta", "argent_multisig_api": "https://cloud.argent-api.com/v1/multisig/starknet/sepolia", + "token_addresses_file": TOKEN_ADDRESSES_DIR / "sepolia.json", }, "staging": { "name": "staging", @@ -71,6 +75,7 @@ class NetworkType(Enum): "class_hash": 0x061DAC032F228ABEF9C6626F995015233097AE253A7F72D68552DB02F2971B8F, "voyager_api_url": "https://sepolia-api.voyager.online/beta", "argent_multisig_api": "https://cloud.argent-api.com/v1/multisig/starknet/sepolia", + "token_addresses_file": TOKEN_ADDRESSES_DIR / "sepolia.json", }, "starknet-devnet": { "name": "starknet-devnet", @@ -89,6 +94,7 @@ class NetworkType(Enum): "type": NetworkType.DEV, "check_interval": 0.01, "max_wait": 3, + "token_addresses_file": TOKEN_ADDRESSES_DIR / "sepolia.json", "relayers": [ { "address": 0xE29882A1FCBA1E7E10CAD46212257FEA5C752A4F9B1B1EC683C503A2CF5C8A, @@ -211,7 +217,6 @@ class ChainId(IntEnum): CAIRO_DIR = Path("cairo") TESTS_DIR_CAIRO_ZERO = Path("cairo_zero/tests") TESTS_DIR_END_TO_END = Path("tests") -TOKEN_ADDRESSES_DIR = Path("starknet-addresses/bridged_tokens") CONTRACTS = { p.stem: p diff --git a/kakarot_scripts/deployment/dualvm_token_deployments.py b/kakarot_scripts/deployment/dualvm_token_deployments.py index 11739e20a..d884f73ff 100644 --- a/kakarot_scripts/deployment/dualvm_token_deployments.py +++ b/kakarot_scripts/deployment/dualvm_token_deployments.py @@ -1,25 +1,20 @@ # %% Imports import json import logging +from pathlib import Path from typing import Any, Dict, List from uvloop import run -from kakarot_scripts.constants import ( - EVM_ADDRESS, - NETWORK, - RPC_CLIENT, - TOKEN_ADDRESSES_DIR, - NetworkType, -) +from kakarot_scripts.constants import EVM_ADDRESS, NETWORK, RPC_CLIENT, NetworkType from kakarot_scripts.utils.kakarot import deploy as deploy_kakarot from kakarot_scripts.utils.kakarot import deploy_and_fund_evm_address from kakarot_scripts.utils.kakarot import dump_deployments as dump_evm_deployments +from kakarot_scripts.utils.kakarot import get_contract as get_solidity_contract from kakarot_scripts.utils.kakarot import get_deployments as get_evm_deployments from kakarot_scripts.utils.starknet import call_contract from kakarot_scripts.utils.starknet import deploy as deploy_starknet -from kakarot_scripts.utils.starknet import execute_calls, get_class_hash_at -from kakarot_scripts.utils.starknet import get_contract as get_contract_starknet +from kakarot_scripts.utils.starknet import execute_calls from kakarot_scripts.utils.starknet import get_deployments as get_starknet_deployments from kakarot_scripts.utils.starknet import ( get_starknet_account, @@ -36,130 +31,113 @@ # %% async def deploy_dualvm_tokens() -> None: # %% Deploy DualVM Tokens - kakarot = get_starknet_deployments()["kakarot"] - kakarot_native_token = ( - await call_contract("kakarot", "get_native_token") - ).native_token_address - evm_deployments = get_evm_deployments() - tokens = get_tokens_list() - for token in tokens: - if int(token["l2_token_address"], 16) == kakarot_native_token: - logger.info(f"Skipping {token['name']} as it is the native token") - continue - if token["name"] not in evm_deployments: - await deploy_new_token(token, kakarot, evm_deployments) - else: - is_deployed = await check_dualvm_token_deployment(token, evm_deployments) - if not is_deployed: - await deploy_new_token(token, kakarot, evm_deployments) - logger.info("Finished processing all DualVM tokens") - dump_evm_deployments(evm_deployments) - # %% - - -def get_tokens_list() -> List[Dict[str, Any]]: - """ - Get the list of tokens for a given network. - If in dev mode, will return the sepolia token list. - """ - if NETWORK["type"] == NetworkType.DEV: - return load_tokens("sepolia") - - return load_tokens(NETWORK["name"]) + # The lazy execution must be done before we check the deployments succeeded, as the l2 contracts + # need to be deployed first + register_lazy_account(await get_starknet_account()) + kakarot_address = get_starknet_deployments()["kakarot"] + evm_deployments = get_evm_deployments() -def load_tokens(network_name: str) -> List[Dict[str, Any]]: - """ - Load the list of tokens for a given network, using the starknet.io token list. - Filters out entries without an l2_token_address (which are not bridged tokens). - """ - file_path = TOKEN_ADDRESSES_DIR / f"{network_name}.json" + file_path = Path(NETWORK["token_addresses_file"]) if not file_path.exists(): - raise ValueError(f"No known token addresses for network: {network_name}") + raise ValueError( + f"Token addresses file not found for network: {NETWORK['name']}" + ) tokens = json.loads(file_path.read_text()) - return [token for token in tokens if "l2_token_address" in token] - - -async def deploy_new_token( - token: Dict[str, Any], - kakarot_address: str, - evm_deployments: Dict[str, Any], -) -> None: - """ - Deploy a new DualVMToken for a corresponding Starknet ERC20 token. - """ - token_name = token["name"] - l2_token_address = await get_starknet_token(token) - contract = await deploy_kakarot( - "CairoPrecompiles", - "DualVmToken", - kakarot_address, - int(l2_token_address, 16), - ) + kakarot_native_token = ( + await call_contract("kakarot", "get_native_token") + ).native_token_address - await invoke( - "kakarot", - "set_authorized_cairo_precompile_caller", - int(contract.address, 16), - True, - ) - evm_deployments[token_name] = { - "address": int(contract.address, 16), - "starknet_address": contract.starknet_address, - } - logger.info( - f"Deployed new DualVMToken for {token_name} at address {contract.address}" - ) + # Filter tokens based on deployment criteria + tokens_to_deploy: List[Dict[str, Any]] = [] + for token in tokens: + token_name = token["name"] + + # Skip tokens without L2 address + if "l2_token_address" not in token: + logger.info("Skipping %s: missing l2_token_address", token_name) + continue + l2_token_address = int(token["l2_token_address"], 16) -async def check_dualvm_token_deployment( - token: Dict[str, Any], - evm_deployments: Dict[str, Any], -) -> bool: - """ - Given an existing DualVMToken, verifies it is _actually_ deployed. - """ - token_name = token["name"] - dualvm_token_address = evm_deployments[token_name]["starknet_address"] - if await get_class_hash_at(dualvm_token_address): - return True - else: - return False - - -async def get_starknet_token(token: Dict[str, Any]) -> str: - """ - Return the starknet address of the ERC20 token corresponding to a given dualVM token. - If it doesn't exist yet, deploys a new one in dev networks. - """ - token_name = token["name"] - if NETWORK["type"] == NetworkType.DEV: + # Skip native token + if l2_token_address == kakarot_native_token: + logger.info("Skipping %s: native token", token_name) + continue + + # Skip if token is already deployed + if dualvm_token_deployment := evm_deployments.get(token_name): + try: + await RPC_CLIENT.get_class_hash_at( + dualvm_token_deployment["starknet_address"] + ) + logger.info("Skipping %s: already deployed on Starknet", token_name) + continue + except Exception: + # Token not deployed, include it in candidates + pass + + tokens_to_deploy.append(token) + + # Deploy tokens + for token in tokens_to_deploy: + l2_token_address = int(token["l2_token_address"], 16) try: - RPC_CLIENT.get_class_hash_at(token["l2_token_address"]) - logger.info( - f"Using existing Starknet token for {token_name} at address {token['l2_token_address']}" + await RPC_CLIENT.get_class_hash_at(l2_token_address) + except Exception as e: + if NETWORK["type"] != NetworkType.DEV: + raise ValueError( + f"Starknet token for {token['name']} doesn't exist on L2" + ) from e + + logger.info(f"⏳ {token['name']} doesn't exist on Starknet, deploying...") + owner = await get_starknet_account() + l2_token_address = await deploy_starknet( + "StarknetToken", + token["name"], + token["symbol"], + token["decimals"], + int(2**256 - 1), + owner.address, ) - except Exception: - starknet_token = await deploy_starknet_token() - token["l2_token_address"] = f"0x{starknet_token.address:064x}" - logger.info( - f"Deployed new Starknet token for {token_name} at address {token['l2_token_address']}" + token["l2_token_address"] = hex(l2_token_address) + + if token["name"] not in evm_deployments: + contract = await deploy_kakarot( + "CairoPrecompiles", "DualVmToken", kakarot_address, l2_token_address ) - else: - logger.info( - f"Using existing Starknet token for {token_name} at address {token['l2_token_address']}" - ) - return token["l2_token_address"] + await invoke( + "kakarot", + "set_authorized_cairo_precompile_caller", + int(contract.address, 16), + True, + ) + evm_deployments[token["name"]] = { + "address": int(contract.address, 16), + "starknet_address": contract.starknet_address, + } + await execute_calls() + dump_evm_deployments(evm_deployments) + remove_lazy_account(await get_starknet_account()) -async def deploy_starknet_token() -> Any: - owner = await get_starknet_account() - address = await deploy_starknet( - "StarknetToken", "MyToken", "MTK", int(1e18), owner.address - ) - return get_contract_starknet("StarknetToken", address=address) + # Check deployments + # Reload evm deployments to get the proper formatting of addresses. + evm_deployments = get_evm_deployments() + for token in tokens_to_deploy: + token_contract = await get_solidity_contract( + "CairoPrecompiles", "DualVmToken", evm_deployments[token["name"]]["address"] + ) + assert await token_contract.starknetToken() == int( + token["l2_token_address"], 16 + ) + assert await token_contract.kakarot() == kakarot_address + assert await token_contract.name() == token["name"] + assert await token_contract.symbol() == token["symbol"] + assert await token_contract.decimals() == token["decimals"] + logger.info("Finished processing all DualVM tokens") # %% Run @@ -174,11 +152,7 @@ async def main() -> None: EVM_ADDRESS, amount=100 if NETWORK["type"] is NetworkType.DEV else 0.01 ) - account = await get_starknet_account() - register_lazy_account(account) await deploy_dualvm_tokens() - await execute_calls() - remove_lazy_account(account.address) def main_sync() -> None: diff --git a/kakarot_scripts/deployment/main.py b/kakarot_scripts/deployment/main.py index 0f1acde12..f7451f897 100644 --- a/kakarot_scripts/deployment/main.py +++ b/kakarot_scripts/deployment/main.py @@ -53,9 +53,11 @@ async def main(): # %% EVM Deployments await deploy_pre_eip155_senders() await deploy_evm_contracts() - await deploy_dualvm_tokens() await execute_calls() + # DualVM Tokens deployment have their own invoke batching strategy + await deploy_dualvm_tokens() + await whitelist_pre_eip155_txs() await execute_calls() diff --git a/kakarot_scripts/utils/kakarot.py b/kakarot_scripts/utils/kakarot.py index 0654984c0..aba235833 100644 --- a/kakarot_scripts/utils/kakarot.py +++ b/kakarot_scripts/utils/kakarot.py @@ -318,7 +318,7 @@ def dump_deployments(deployments): { name: { **deployment, - "address": hex(deployment["address"]), + "address": Web3.to_checksum_address(f"0x{deployment['address']:040x}"), "starknet_address": hex(deployment["starknet_address"]), } for name, deployment in deployments.items() diff --git a/tests/end_to_end/CairoPrecompiles/test_dual_vm_token.py b/tests/end_to_end/CairoPrecompiles/test_dual_vm_token.py index 609f07127..756757f46 100644 --- a/tests/end_to_end/CairoPrecompiles/test_dual_vm_token.py +++ b/tests/end_to_end/CairoPrecompiles/test_dual_vm_token.py @@ -15,6 +15,7 @@ async def starknet_token(owner): "StarknetToken", "MyToken", "MTK", + 18, int(2**256 - 1), owner.starknet_contract.address, ) diff --git a/tests/end_to_end/test_kakarot.py b/tests/end_to_end/test_kakarot.py index 1f7834d94..8ee484515 100644 --- a/tests/end_to_end/test_kakarot.py +++ b/tests/end_to_end/test_kakarot.py @@ -16,7 +16,7 @@ wait_for_transaction, ) from tests.end_to_end.bytecodes import test_cases -from tests.utils.constants import TRANSACTION_GAS_LIMIT, ZERO_ADDRESS +from tests.utils.constants import TRANSACTION_GAS_LIMIT from tests.utils.helpers import ( extract_memory_from_execute, generate_random_evm_address, From 8a7cb724a38a2abe7ee1c139c7fbc4c63a9db48b Mon Sep 17 00:00:00 2001 From: enitrat Date: Tue, 5 Nov 2024 22:04:57 +0700 Subject: [PATCH 18/20] fix issues with to_checksum_address where input is >40bytes --- kakarot_scripts/deployment/dualvm_token_deployments.py | 7 +++---- kakarot_scripts/deployment/main.py | 4 +--- kakarot_scripts/utils/kakarot.py | 10 ++++++++-- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/kakarot_scripts/deployment/dualvm_token_deployments.py b/kakarot_scripts/deployment/dualvm_token_deployments.py index d884f73ff..a482e43cc 100644 --- a/kakarot_scripts/deployment/dualvm_token_deployments.py +++ b/kakarot_scripts/deployment/dualvm_token_deployments.py @@ -34,7 +34,8 @@ async def deploy_dualvm_tokens() -> None: # The lazy execution must be done before we check the deployments succeeded, as the l2 contracts # need to be deployed first - register_lazy_account(await get_starknet_account()) + account = await get_starknet_account() + register_lazy_account(account) kakarot_address = get_starknet_deployments()["kakarot"] evm_deployments = get_evm_deployments() @@ -121,11 +122,9 @@ async def deploy_dualvm_tokens() -> None: await execute_calls() dump_evm_deployments(evm_deployments) - remove_lazy_account(await get_starknet_account()) + remove_lazy_account(account) # Check deployments - # Reload evm deployments to get the proper formatting of addresses. - evm_deployments = get_evm_deployments() for token in tokens_to_deploy: token_contract = await get_solidity_contract( "CairoPrecompiles", "DualVmToken", evm_deployments[token["name"]]["address"] diff --git a/kakarot_scripts/deployment/main.py b/kakarot_scripts/deployment/main.py index f7451f897..09c1ad601 100644 --- a/kakarot_scripts/deployment/main.py +++ b/kakarot_scripts/deployment/main.py @@ -76,9 +76,7 @@ async def main(): logger.error("❌ Coinbase is set to 0, all transaction fees will be lost") else: logger.info(f"✅ Coinbase set to: 0x{coinbase_address:040x}") - coinbase = await get_contract( - "Kakarot", "Coinbase", address=f"0x{coinbase_address:040x}" - ) + coinbase = await get_contract("Kakarot", "Coinbase", address=coinbase_address) coinbase_balance = await eth_balance_of(coinbase_address) if coinbase_balance / 1e18 > 0.001: logger.info( diff --git a/kakarot_scripts/utils/kakarot.py b/kakarot_scripts/utils/kakarot.py index aba235833..e2d8f2177 100644 --- a/kakarot_scripts/utils/kakarot.py +++ b/kakarot_scripts/utils/kakarot.py @@ -151,17 +151,23 @@ def process_link_references( async def get_contract( contract_app: str, contract_name: str, - address=None, + address: Optional[int | str] = None, caller_eoa: Optional[Account] = None, ) -> Web3Contract: artifacts = get_solidity_artifacts(contract_app, contract_name) + address = int(address, 16) if isinstance(address, str) else address + bytecode, bytecode_runtime = await link_libraries(artifacts) contract = cast( Web3Contract, WEB3.eth.contract( - address=to_checksum_address(address) if address is not None else address, + address=( + to_checksum_address(f"{address:040x}") + if address is not None + else address + ), abi=artifacts["abi"], bytecode=bytecode, ), From aea1b83f0951ea2fda7ef271d2a81c6642a01457 Mon Sep 17 00:00:00 2001 From: enitrat Date: Wed, 6 Nov 2024 18:33:57 +0700 Subject: [PATCH 19/20] apply pair-reviewd changes --- .../deployment/dualvm_token_deployments.py | 62 ++++++++++--------- tests/utils/helpers.py | 8 +++ 2 files changed, 41 insertions(+), 29 deletions(-) diff --git a/kakarot_scripts/deployment/dualvm_token_deployments.py b/kakarot_scripts/deployment/dualvm_token_deployments.py index a482e43cc..170d1f3d8 100644 --- a/kakarot_scripts/deployment/dualvm_token_deployments.py +++ b/kakarot_scripts/deployment/dualvm_token_deployments.py @@ -2,7 +2,6 @@ import json import logging from pathlib import Path -from typing import Any, Dict, List from uvloop import run @@ -14,7 +13,6 @@ from kakarot_scripts.utils.kakarot import get_deployments as get_evm_deployments from kakarot_scripts.utils.starknet import call_contract from kakarot_scripts.utils.starknet import deploy as deploy_starknet -from kakarot_scripts.utils.starknet import execute_calls from kakarot_scripts.utils.starknet import get_deployments as get_starknet_deployments from kakarot_scripts.utils.starknet import ( get_starknet_account, @@ -22,6 +20,7 @@ register_lazy_account, remove_lazy_account, ) +from tests.utils.helpers import int_to_string logging.basicConfig() logger = logging.getLogger(__name__) @@ -35,7 +34,10 @@ async def deploy_dualvm_tokens() -> None: # The lazy execution must be done before we check the deployments succeeded, as the l2 contracts # need to be deployed first account = await get_starknet_account() - register_lazy_account(account) + + # Remove lazy account before we check the deployments succeeded, as the l2 contracts + # need to be deployed sequentially. + remove_lazy_account(account.address) kakarot_address = get_starknet_deployments()["kakarot"] evm_deployments = get_evm_deployments() @@ -50,41 +52,50 @@ async def deploy_dualvm_tokens() -> None: kakarot_native_token = ( await call_contract("kakarot", "get_native_token") ).native_token_address + kakarot_native_token_name = int_to_string( + (await call_contract("ERC20", "name", address=kakarot_native_token)).name + ) + kakarot_native_token_symbol = int_to_string( + (await call_contract("ERC20", "symbol", address=kakarot_native_token)).symbol + ) # Filter tokens based on deployment criteria - tokens_to_deploy: List[Dict[str, Any]] = [] for token in tokens: - token_name = token["name"] - # Skip tokens without L2 address + # Skip if entry is not a token if "l2_token_address" not in token: - logger.info("Skipping %s: missing l2_token_address", token_name) + logger.info("Skipping %s: missing l2_token_address", token["name"]) continue l2_token_address = int(token["l2_token_address"], 16) # Skip native token - if l2_token_address == kakarot_native_token: - logger.info("Skipping %s: native token", token_name) + if ( + token["name"] == kakarot_native_token_name + and token["symbol"] == kakarot_native_token_symbol + ): + logger.info("Skipping %s: native token", token["name"]) continue - # Skip if token is already deployed - if dualvm_token_deployment := evm_deployments.get(token_name): + # Check if DualVM token is a deployed contract on Starknet + if dualvm_token_deployment := evm_deployments.get(token["name"]): try: await RPC_CLIENT.get_class_hash_at( dualvm_token_deployment["starknet_address"] ) - logger.info("Skipping %s: already deployed on Starknet", token_name) + token_contract = await get_solidity_contract( + "CairoPrecompiles", + "DualVmToken", + evm_deployments[token["name"]]["address"], + ) + assert await token_contract.kakarot() == kakarot_address + logger.info("Skipping %s: already deployed on Starknet", token["name"]) continue except Exception: - # Token not deployed, include it in candidates pass - tokens_to_deploy.append(token) - - # Deploy tokens - for token in tokens_to_deploy: - l2_token_address = int(token["l2_token_address"], 16) + # DualVM token is not deployed, deploy one + # Check if the L2 token exists, if not deploy one try: await RPC_CLIENT.get_class_hash_at(l2_token_address) except Exception as e: @@ -103,7 +114,6 @@ async def deploy_dualvm_tokens() -> None: int(2**256 - 1), owner.address, ) - token["l2_token_address"] = hex(l2_token_address) if token["name"] not in evm_deployments: contract = await deploy_kakarot( @@ -120,23 +130,17 @@ async def deploy_dualvm_tokens() -> None: "starknet_address": contract.starknet_address, } - await execute_calls() - dump_evm_deployments(evm_deployments) - remove_lazy_account(account) - - # Check deployments - for token in tokens_to_deploy: token_contract = await get_solidity_contract( "CairoPrecompiles", "DualVmToken", evm_deployments[token["name"]]["address"] ) - assert await token_contract.starknetToken() == int( - token["l2_token_address"], 16 - ) - assert await token_contract.kakarot() == kakarot_address + assert await token_contract.starknetToken() == l2_token_address assert await token_contract.name() == token["name"] assert await token_contract.symbol() == token["symbol"] assert await token_contract.decimals() == token["decimals"] + + dump_evm_deployments(evm_deployments) logger.info("Finished processing all DualVM tokens") + register_lazy_account(account.address) # %% Run diff --git a/tests/utils/helpers.py b/tests/utils/helpers.py index c6a44e16e..c33d76531 100644 --- a/tests/utils/helpers.py +++ b/tests/utils/helpers.py @@ -20,6 +20,14 @@ ) +def int_to_bytes(num: int) -> bytes: + return num.to_bytes((num.bit_length() + 7) // 8 or 1, "big") + + +def int_to_string(num: int) -> str: + return int_to_bytes(num).decode("utf-8") + + def to_int(v: Union[str, int]) -> int: if isinstance(v, str): if v.startswith("0x"): From 57b287c1cb1c3a2136e23f69fec28f7cd31e251d Mon Sep 17 00:00:00 2001 From: enitrat Date: Thu, 7 Nov 2024 11:49:27 +0700 Subject: [PATCH 20/20] withdraw coinbase funds only once --- tests/end_to_end/conftest.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/end_to_end/conftest.py b/tests/end_to_end/conftest.py index 8ece86771..b45c2993c 100644 --- a/tests/end_to_end/conftest.py +++ b/tests/end_to_end/conftest.py @@ -94,12 +94,12 @@ async def _factory(amount=0): gas_price=gas_price, ) - # Withdraw the funds to the deployer - await coinbase.functions["withdraw(uint256)"]( - toStarknetAddress=deployer.address, - gas_limit=gas_limit, - gas_price=gas_price, - ) + # Withdraw the funds to the deployer + await coinbase.functions["withdraw(uint256)"]( + toStarknetAddress=deployer.address, + gas_limit=gas_limit, + gas_price=gas_price, + ) @pytest_asyncio.fixture(scope="session")