Skip to content

Commit

Permalink
fix: deployments db and boa updates
Browse files Browse the repository at this point in the history
  • Loading branch information
DanielSchiavini committed Oct 9, 2024
1 parent 22f01d2 commit efbb44c
Show file tree
Hide file tree
Showing 13 changed files with 131 additions and 147 deletions.
1 change: 1 addition & 0 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
name: release
on:
release:
types: [published]
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
name: test
on:
push:

Expand Down
8 changes: 4 additions & 4 deletions boa_zksync/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,24 @@


def set_zksync_env(url, nickname=None):
boa.set_env(ZksyncEnv.from_url(url, nickname=nickname))
return boa.set_env(ZksyncEnv.from_url(url, nickname=nickname))


def set_zksync_test_env(node_args=(), nickname=None):
boa.set_env(ZksyncEnv(rpc=EraTestNode(node_args=node_args), nickname=nickname))
return boa.set_env(ZksyncEnv(rpc=EraTestNode(node_args=node_args), nickname=nickname))


def set_zksync_fork(url, nickname=None, *args, **kwargs):
env = ZksyncEnv.from_url(url, nickname=nickname)
env.fork(*args, **kwargs)
boa.set_env(env)
return boa.set_env(env)


def set_zksync_browser_env(*args, **kwargs):
# import locally because jupyter is generally not installed
from boa_zksync.browser import ZksyncBrowserEnv

boa.set_env(ZksyncBrowserEnv(*args, **kwargs))
return boa.set_env(ZksyncBrowserEnv(*args, **kwargs))


boa.set_zksync_env = set_zksync_env
Expand Down
83 changes: 52 additions & 31 deletions boa_zksync/contract.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import textwrap
from contextlib import contextmanager
from typing import TYPE_CHECKING, Optional

from boa import Env
from boa.contracts.abi.abi_contract import ABIContract, ABIFunction
from boa.environment import Env
from boa.contracts.vyper.vyper_contract import VyperContract
from boa.rpc import to_bytes, to_int
from boa.util.abi import Address
Expand All @@ -17,7 +18,9 @@
generate_source_for_arbitrary_stmt,
generate_source_for_internal_fn,
)
from boa_zksync.types import ZksyncCompilerData, DEFAULT_SALT
from boa_zksync.types import ZksyncCompilerData
if TYPE_CHECKING:
from boa_zksync import ZksyncEnv


class ZksyncContract(ABIContract):
Expand All @@ -28,40 +31,55 @@ class ZksyncContract(ABIContract):
def __init__(
self,
compiler_data: ZksyncCompilerData,
name: str,
functions: list[ABIFunction],
*args,
name="VyperContract",
abi=None,
functions=None,
filename=None,
address=None,
value=0,
env: Env = None,
env: "ZksyncEnv" = None,
override_address: Address = None,
# whether to skip constructor
skip_initcode=False,
created_from: Address = None,
filename: str = None,
gas=None,
dependency_bytecodes=(),
salt=DEFAULT_SALT,
constructor_calldata=b"",
max_priority_fee_per_gas=None,
**kwargs,
):
self.compiler_data = compiler_data
self.env = env or Env.get_singleton()
self.created_from = created_from
self._abi = compiler_data.abi
self.env = Env.get_singleton() if env is None else env
self.filename = filename

if address is None:
address, _ = self.env.deploy_code(
bytecode=self.compiler_data.bytecode,
value=value,
gas=gas,
dependency_bytecodes=dependency_bytecodes,
salt=salt,
max_priority_fee_per_gas=max_priority_fee_per_gas,
# TODO: Users shouldn't have to pass this in, the args should be converted
# We should get the constructor from the deployer
constructor_calldata=constructor_calldata,
contract=self,
if skip_initcode:
if value:
raise Exception("nonzero value but initcode is being skipped")
address = Address(override_address)
else:
address = self._run_init(
*args, value=value, override_address=override_address, gas=gas
)
super().__init__(name, abi, functions, address)
self.env.register_contract(address, self)
super().__init__(name=name, abi=compiler_data.abi, functions=functions, address=address, filename=filename, env=env)

def _run_init(self, *args, value=0, override_address=None, gas=None):
constructor_calldata = self._ctor.prepare_calldata(*args) if self._ctor else b""
address, bytecode = self.env.deploy_code(
override_address=override_address,
gas=gas,
contract=self,
bytecode=self.compiler_data.bytecode,
value=value,
constructor_calldata=constructor_calldata,
)
self.bytecode = bytecode
return address

@cached_property
def _ctor(self) -> Optional[ABIFunction]:
"""
Get the constructor function of the contract.
:raises: StopIteration if the constructor is not found.
"""
ctor_abi = next((i for i in self.abi if i["type"] == "constructor"), None)
if ctor_abi:
return ABIFunction(ctor_abi, contract_name=self.contract_name)

def eval(self, code):
return ZksyncEval(code, self)()
Expand All @@ -74,8 +92,11 @@ def override_vyper_namespace(self):
@cached_property
def deployer(self):
from boa_zksync.deployer import ZksyncDeployer

return ZksyncDeployer(self.compiler_data, filename=self.filename)
return ZksyncDeployer(
self.compiler_data.vyper,
filename=self.filename,
zkvyper_data=self.compiler_data
)

@cached_property
def vyper_contract(self):
Expand Down
74 changes: 14 additions & 60 deletions boa_zksync/deployer.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,25 @@
from typing import TYPE_CHECKING

from boa import Env
from boa.contracts.abi.abi_contract import ABIContractFactory, ABIFunction
from boa.contracts.abi.abi_contract import ABIContractFactory
from boa.util.abi import Address
from vyper.compiler import CompilerData
from vyper.compiler.output import build_solc_json

from boa_zksync.compile import compile_zksync, compile_zksync_source
from boa_zksync.contract import ZksyncContract
from boa_zksync.types import ZksyncCompilerData, DEFAULT_SALT
from boa_zksync.types import ZksyncCompilerData

if TYPE_CHECKING:
from boa_zksync.environment import ZksyncEnv


class ZksyncDeployer(ABIContractFactory):
def __init__(self, compiler_data: CompilerData, filename=None):
def __init__(self, compiler_data: CompilerData, filename=None, zkvyper_data=None):
contract_name = Path(compiler_data.contract_path).stem
self.zkvyper_data = self._compile(compiler_data, contract_name, filename)
if zkvyper_data is None:
zkvyper_data = self._compile(compiler_data, contract_name, filename)
self.zkvyper_data = zkvyper_data
super().__init__(
contract_name, self.zkvyper_data.abi, compiler_data.contract_path
)
Expand All @@ -40,50 +43,18 @@ def _compile(
def from_abi_dict(cls, abi, name="<anonymous contract>", filename=None):
raise NotImplementedError("ZksyncDeployer does not support loading from ABI")

def deploy(
self,
*args,
value=0,
gas=None,
dependency_bytecodes=(),
salt=DEFAULT_SALT,
max_priority_fee_per_gas=None,
**kwargs,
) -> ZksyncContract:
def deploy(self, *args, **kwargs) -> ZksyncContract:
return ZksyncContract(
self.zkvyper_data,
*args,
name=self._name,
abi=self.abi,
functions=self.functions,
value=value,
filename=self.filename,
gas=gas,
constructor_calldata=(
self.constructor.prepare_calldata(*args, **kwargs)
if args or kwargs
else b""
),
dependency_bytecodes=dependency_bytecodes,
salt=salt,
max_priority_fee_per_gas=max_priority_fee_per_gas,
**kwargs,
self.zkvyper_data, self._name, self.functions, *args, filename=self.filename, **kwargs
)

def at(self, address: Address | str) -> ZksyncContract:
"""
Create an ABI contract object for a deployed contract at `address`.
"""
address = Address(address)
contract = ZksyncContract(
self.zkvyper_data,
name=self._name,
abi=self.abi,
functions=self.functions,
address=address,
filename=self.filename,
env=self.env,
)
contract = self.deploy(override_address=address, skip_initcode=True)
contract.env.register_contract(address, contract)
return contract

def deploy_as_blueprint(self, *args, **kwargs) -> ZksyncContract:
Expand All @@ -93,15 +64,6 @@ def deploy_as_blueprint(self, *args, **kwargs) -> ZksyncContract:
"""
return self.deploy(*args, **kwargs)

@cached_property
def constructor(self) -> ABIFunction:
"""
Get the constructor function of the contract.
:raises: StopIteration if the constructor is not found.
"""
ctor_abi = next(i for i in self.abi if i["type"] == "constructor")
return ABIFunction(ctor_abi, contract_name=self._name)

@property
def env(self) -> "ZksyncEnv":
"""
Expand All @@ -116,18 +78,10 @@ def env(self) -> "ZksyncEnv":
), "ZksyncDeployer can only be used in zkSync environments"
return env

# TODO, this breakpoint isnt' hitting in our tests, and it should be
@cached_property
def solc_json(self):
"""
A ZKsync compatible solc-json. Generates a solc "standard json" representation of the Vyper contract.
This is different from running `zkvyper --combined-json` because the block explorers are looking for something else.
The boa version of this method just does this, where build_solc_json comes from the vyper compiler itself. The zkvyper has no such method.
return build_solc_json(self.compiler_data)
A ZKsync compatible solc-json. Generates a solc "standard json" representation
of the Vyper contract.
"""
breakpoint()
# return {
# "contractAddress": self.address,
# "sourceCode":
# }
return build_solc_json(self.zkvyper_data.vyper)
40 changes: 7 additions & 33 deletions boa_zksync/environment.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
from contextlib import contextmanager
import time

from contextlib import contextmanager
from functools import cached_property
from hashlib import sha256
from pathlib import Path
from typing import Any, Iterable, Optional, Type

from boa.contracts.abi.abi_contract import ABIContract, ABIContractFactory
from boa.deployments import get_deployments_db
from boa.environment import _AddressType
from boa.interpret import json
from boa.network import NetworkEnv, _EstimateGasFailed
Expand All @@ -16,11 +16,6 @@
from eth_account import Account
from requests import HTTPError

from boa.deployments import get_deployments_db, Deployment
from boa.verifiers import get_verification_bundle

import warnings

from boa_zksync.deployer import ZksyncDeployer
from boa_zksync.node import EraTestNode
from boa_zksync.types import (
Expand Down Expand Up @@ -168,6 +163,9 @@ def execute_code(

return traced_computation

def deploy(self, *args, **kwargs):
raise NotImplementedError("Please use `deploy_code` instead")

def deploy_code(
self,
sender=None,
Expand Down Expand Up @@ -253,33 +251,9 @@ def deploy_code(

print(f"Contract deployed at {create_address}")

breakpoint()
if (deployments_db := get_deployments_db()) is not None:
contract_name = getattr(contract, "contract_name", None)
try:
source_bundle = get_verification_bundle(contract)
except Exception as e:
# there was a problem constructing the verification bundle.
# assume the user cares more about continuing, than getting
# the bundle into the db
msg = "While saving deployment data, couldn't construct"
msg += f" verification bundle for {contract_name}! Full stack"
msg += f" trace:\n```\n{e}\n```\nContinuing.\n"
warnings.warn(msg, stacklevel=2)
source_bundle = None
abi = getattr(contract, "abi", None)

deployment_data = Deployment(
create_address,
contract_name,
self._rpc.name,
sender,
receipt["transactionHash"],
broadcast_ts,
tx.to_dict(),
receipt,
source_bundle,
abi,
deployment_data = tx.to_deployment(
contract, receipt, broadcast_ts, create_address, self._rpc.name
)
deployments_db.insert_deployment(deployment_data)

Expand Down
Loading

0 comments on commit efbb44c

Please sign in to comment.