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

Commit

Permalink
tests: add univ3 svg generation test
Browse files Browse the repository at this point in the history
  • Loading branch information
enitrat committed Jul 22, 2024
1 parent 7bc70ad commit 7f4402e
Show file tree
Hide file tree
Showing 12 changed files with 1,047 additions and 13 deletions.
10 changes: 9 additions & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
[submodule "solidity_contracts/lib/forge-std"]
path = solidity_contracts/lib/forge-std
url = https://github.com/foundry-rs/forge-std
branch = v1.3.0
[submodule "solidity_contracts/lib/kakarot-lib"]
path = solidity_contracts/lib/kakarot-lib
url = https://github.com/kkrt-labs/kakarot-lib
[submodule "solidity_contracts/lib/v3-core"]
path = solidity_contracts/lib/v3-core
url = https://github.com/Uniswap/v3-core
[submodule "solidity_contracts/lib/openzeppelin"]
path = solidity_contracts/lib/openzeppelin
url = https://github.com/OpenZeppelin/openzeppelin-contracts
[submodule "solidity_contracts/lib/base64-sol"]
path = solidity_contracts/lib/base64-sol
url = https://github.com/Brechtpd/base64
5 changes: 3 additions & 2 deletions kakarot_scripts/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ class NetworkType(Enum):
"l1_rpc_url": "http://127.0.0.1:8545",
"type": NetworkType.DEV,
"check_interval": 0.01,
"max_wait": 1,
"max_wait": 3,
},
"katana": {
"name": "katana",
Expand All @@ -64,7 +64,7 @@ class NetworkType(Enum):
"l1_rpc_url": "http://127.0.0.1:8545",
"type": NetworkType.DEV,
"check_interval": 0.01,
"max_wait": 2,
"max_wait": 3,
},
"madara": {
"name": "madara",
Expand Down Expand Up @@ -182,6 +182,7 @@ class ChainId(IntEnum):
16,
)
SOURCE_DIR = Path("src")
SOURCE_PATH = Path("solidity_contracs/src")
SOURCE_DIR_FIXTURES = Path("tests/fixtures")
CONTRACTS = {p.stem: p for p in list(SOURCE_DIR.glob("**/*.cairo"))}
CONTRACTS_FIXTURES = {p.stem: p for p in list(SOURCE_DIR_FIXTURES.glob("**/*.cairo"))}
Expand Down
95 changes: 87 additions & 8 deletions kakarot_scripts/utils/kakarot.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import asyncio
import functools
import json
import logging
from pathlib import Path
from types import MethodType
from typing import List, Optional, Union, cast
from typing import Any, Dict, List, Optional, Tuple, Union, cast

import rlp
from eth_abi import decode
Expand Down Expand Up @@ -34,6 +35,7 @@
EVM_PRIVATE_KEY,
NETWORK,
RPC_CLIENT,
SOURCE_PATH,
WEB3,
ChainId,
)
Expand All @@ -53,6 +55,8 @@
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)

LIBRARY_PLACEHOLDER_PREFIX_BYTES = 17


class EvmTransactionError(Exception):
pass
Expand Down Expand Up @@ -115,21 +119,24 @@ def get_solidity_artifacts(
def get_contract(
contract_app: str,
contract_name: str,
deployed_libraries: List[Dict[str, str]] = None,
address=None,
caller_eoa: Optional[Account] = None,
) -> Web3Contract:

artifacts = get_solidity_artifacts(contract_app, contract_name)
bytecode, bytecode_runtime = replace_library_placeholders(
artifacts, deployed_libraries or []
)

contract = cast(
Web3Contract,
WEB3.eth.contract(
address=to_checksum_address(address) if address is not None else address,
abi=artifacts["abi"],
bytecode=artifacts["bytecode"],
bytecode=bytecode,
),
)
contract.bytecode_runtime = HexBytes(artifacts["bytecode_runtime"])
contract.bytecode_runtime = HexBytes(bytecode_runtime)

try:
for fun in contract.functions:
Expand All @@ -140,12 +147,31 @@ def get_contract(
return contract


def replace_library_placeholders(
artifacts: Dict[str, str], deployed_libraries: List[Dict[str, str]]
) -> Tuple[str, str]:
bytecode = artifacts["bytecode"]
bytecode_runtime = artifacts["bytecode_runtime"]

for library in deployed_libraries:
placeholder = f"__${library['identifier'].hex()}$__"
address = Web3.to_checksum_address(library["address"]).lstrip("0x")
bytecode = bytecode.replace(placeholder, address)
bytecode_runtime = bytecode_runtime.replace(placeholder, address)
logger.info(f"ℹ️ Replaced {library['identifier'].hex()} in bytecode")

return bytecode, bytecode_runtime


def compute_library_identifier(library_app: str, library_name: str) -> bytes:
return keccak(
f"{SOURCE_PATH}/{library_app}/{library_name}.sol:{library_name}".encode("utf-8")
)[:LIBRARY_PLACEHOLDER_PREFIX_BYTES]


async def deploy(
contract_app: str, contract_name: str, *args, **kwargs
contract: Web3Contract, *args, caller_eoa: Optional[Account] = None, **kwargs
) -> Web3Contract:
logger.info(f"⏳ Deploying {contract_name}")
caller_eoa = kwargs.pop("caller_eoa", None)
contract = get_contract(contract_app, contract_name, caller_eoa=caller_eoa)
max_fee = kwargs.pop("max_fee", None)
value = kwargs.pop("value", 0)
receipt, response, success, _ = await eth_send_transaction(
Expand All @@ -166,6 +192,59 @@ async def deploy(
).contract_address
else:
starknet_address, evm_address = response

return receipt, starknet_address, evm_address


async def deploy_library(
library_app: str, library_name: str, *args: Any, **kwargs: Any
) -> Dict[str, Any]:
logger.info(f"⏳ Deploying {library_name}")

caller_eoa = kwargs.pop("caller_eoa", None)
library = get_contract(library_app, library_name, caller_eoa=caller_eoa)

_, _, evm_address = await deploy(library, *args, **kwargs)

library.address = Web3.to_checksum_address(f"0x{evm_address:040x}")
library_identifier = compute_library_identifier(library_app, library_name)

logger.info(f"✅ Library {library_name} deployed at address {library.address}")

return {
"address": library.address,
"identifier": library_identifier,
}


async def deploy_contract(
contract_app: str,
contract_name: str,
*args: Any,
**kwargs: Any,
) -> Web3Contract:
logger.info(f"⏳ Deploying {contract_name}")
associated_libraries = kwargs.pop("associated_libraries", [])
deployed_libraries = (
await asyncio.gather(
*(deploy_library(app, name) for app, name in associated_libraries)
)
if associated_libraries
else []
)

caller_eoa = kwargs.pop("caller_eoa", None)
contract = get_contract(
contract_app,
contract_name,
deployed_libraries=deployed_libraries,
caller_eoa=caller_eoa,
)

_, starknet_address, evm_address = await deploy(
contract, *args, caller_eoa=caller_eoa, **kwargs
)

contract.address = Web3.to_checksum_address(f"0x{evm_address:040x}")
contract.starknet_address = starknet_address
logger.info(f"✅ {contract_name} deployed at address {contract.address}")
Expand Down
1 change: 1 addition & 0 deletions solidity_contracts/lib/base64-sol
Submodule base64-sol added at dcbf85
1 change: 1 addition & 0 deletions solidity_contracts/lib/openzeppelin
Submodule openzeppelin added at 8e0296
1 change: 1 addition & 0 deletions solidity_contracts/lib/v3-core
Submodule v3-core added at e3589b
29 changes: 29 additions & 0 deletions solidity_contracts/src/UniswapV3/HexStrings.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// SPDX-License-Identifier: MIT
pragma solidity =0.7.6;

library HexStrings {
bytes16 internal constant ALPHABET = "0123456789abcdef";

/// @notice Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
/// @dev Credit to Open Zeppelin under MIT license https://github.com/OpenZeppelin/openzeppelin-contracts/blob/243adff49ce1700e0ecb99fe522fb16cff1d1ddc/contracts/utils/Strings.sol#L55
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = ALPHABET[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}

function toHexStringNoPrefix(uint256 value, uint256 length) internal pure returns (string memory) {
bytes memory buffer = new bytes(2 * length);
for (uint256 i = buffer.length; i > 0; i--) {
buffer[i - 1] = ALPHABET[value & 0xf];
value >>= 4;
}
return string(buffer);
}
}
Loading

0 comments on commit 7f4402e

Please sign in to comment.