Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tests: add univ3 svg generation test #1292

Merged
merged 5 commits into from
Jul 25, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
tests: add univ3 svg generation test
  • Loading branch information
enitrat committed Jul 25, 2024
commit 041729b0e1ea5e73999ac9475a55a60bb830a648
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")
enitrat marked this conversation as resolved.
Show resolved Hide resolved
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:
enitrat marked this conversation as resolved.
Show resolved Hide resolved
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: {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