Skip to content

Commit

Permalink
Better documentation and install triggers
Browse files Browse the repository at this point in the history
  • Loading branch information
DanielSchiavini committed Apr 12, 2024
1 parent 79b3c09 commit 4d6f100
Show file tree
Hide file tree
Showing 6 changed files with 150 additions and 58 deletions.
14 changes: 4 additions & 10 deletions .github/workflows/main.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ jobs:
run: |
pip install -r dev-requirements.txt
pip install .
echo "$PATH"
echo "Installing zkvyper and era_test_node"
# Install zkvyper and era_test_node from binary repositories
curl --location https://raw.githubusercontent.com/matter-labs/zkvyper-bin/66cc159d9b6af3b5616f6ed7199bd817bf42bf0a/linux-amd64/zkvyper-linux-amd64-musl-v1.4.0 \
--silent --output /usr/local/bin/zkvyper && \
Expand All @@ -37,14 +37,8 @@ jobs:
curl --location https://github.com/matter-labs/era-test-node/releases/download/v0.1.0-alpha.19/era_test_node-v0.1.0-alpha.19-x86_64-unknown-linux-gnu.tar.gz \
--silent --output era_test_node.tar.gz && \
tar --extract --file=era_test_node.tar.gz && \
mv era_test_node /usr/local/bin/era_test_node &&
mv era_test_node /usr/local/bin/era_test_node && \
era_test_node --version && \
rm era_test_node.tar.gz
- name: Run Unit Tests
env:
PYTHONPATH: ${{ github.workspace }}
run: make test

- name: Run Lint
run: make lint
- run: make lint coverage
92 changes: 92 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,94 @@
# titanoboa-zksync
A Zksync plugin for the Titanoboa Vyper interpreter


## Installation

First install the following dependencies, depending on your system:

- [era-compiler-vyper]() a.k.a. `zkvyper`: to compile Vyper code to ZkSync-compatible bytecode.
- [era-test-node]( https://github.com/matter-labs/era-test-node/releases) for testing and forking.

For Google Colab: These dependencies should be downloaded automatically.

Then, install the package:

```bash
pip install git+https://github.com/DanielSchiavini/titanoboa-zksync.git@main
```

## Usage
The usage of this plugin is similar to the original [Titanoboa interpreter](https://github.com/vyperlang/titanoboa).

Note that the boa_zksync plugin must be imported to install the hooks in the `boa` object.
The same functions are also available in the `boa_zksync` module.


### Configuring the environment
#### In Python:
```python
import boa, boa_zksync

boa.set_zksync_env("<rpc-url>")
```

#### In JupyterLab or Google Colab:
```python
import boa, boa_zksync

boa.set_zksync_browser_env()
boa.env.set_chain_id(324) # Set the chain ID to the ZkSync network
```

Some cell magic is also provided after the extension is loaded:
```jupyter
%load_ext boa_zksync.ipython
```

Instead of `loads_zksync_partial` you can use:
```jupyter
%zkvyper ContractName
# put your source code here, a deployer object with this name is created.
```

Instead of `load_zksync` you can then use:
```jupyter
%zkcontract
# put your source code here, a contract will be deployed to ZkSync
```

Instead of `eval_zksync` you can use:
```jupyter
%zkeval
# put some code to be evaluated here
```

### Interacting with the network

```python
import boa, boa_zksync

constructor_args, address = [], "0x1234..."

# Compile a contract from source file
boa.compile_zksync("path/to/contract.vy")

# Load a contract from source code and deploy
boa.loads_zksync("contract source code", *constructor_args)

# Load a contract from file and deploy
contract = boa.load_zksync("path/to/contract.vy", *constructor_args)

# Load a contract from source file but don't deploy yet
deployer = boa.load_zksync_partial("source code")
deployer.deploy(*constructor_args) # Deploy the contract
deployer.at(address) # Connect a contract to an existing address

# Load a contract from source file but don't deploy yet
deployer = boa.loads_zksync_partial("source code")
deployer.deploy(*constructor_args) # Deploy the contract
deployer.at(address) # Connect a contract to an existing address

# Run the given source code directly
boa.eval_zksync("source code")
```
26 changes: 17 additions & 9 deletions boa_zksync/__init__.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,28 @@
import boa

from boa_zksync.env import ZksyncEnv
from boa_zksync.interpret import compile_zksync, load_zksync, loads_zksync, load_zksync_partial, loads_zksync_partial, eval_zksync

boa.compile_zksync = compile_zksync
boa.load_zksync = load_zksync
boa.loads_zksync = loads_zksync
boa.load_zksync_partial = load_zksync_partial
boa.loads_zksync_partial = loads_zksync_partial
boa.eval_zksync = eval_zksync


def set_zksync_env(url):
boa.env = ZksyncEnv.from_url(url)
boa.set_env(ZksyncEnv.from_url(url))


def set_zksync_browser_env(address=None):
# import locally because jupyter is generally not installed
from boa_zksync.browser import ZksyncBrowserEnv
boa.env = ZksyncBrowserEnv(address)
from boa.integrations.jupyter import browser

# Set a larger shared memory as the zkSync transactions are larger
browser.SHARED_MEMORY_LENGTH = 100 * 1024 + 1
boa.set_env(ZksyncBrowserEnv(address))


boa.compile_zksync = compile_zksync
boa.load_zksync = load_zksync
boa.loads_zksync = loads_zksync
boa.load_zksync_partial = load_zksync_partial
boa.loads_zksync_partial = loads_zksync_partial
boa.eval_zksync = eval_zksync
boa.set_zksync_env = set_zksync_env
boa.set_zksync_browser_env = set_zksync_browser_env
64 changes: 30 additions & 34 deletions boa_zksync/compile.py
Original file line number Diff line number Diff line change
@@ -1,42 +1,38 @@
import json
import subprocess
from collections import namedtuple
from dataclasses import dataclass
from shutil import which

ZksyncCompilerData = namedtuple(
"ZksyncCompilerData",
[
"method_identifiers",
"abi",
"bytecode",
"bytecode_runtime",
"warnings",
"factory_deps",
],
)

@dataclass
class ZksyncCompilerData:
"""
Represents the output of the Zksync Vyper compiler (combined_json format).
"""
method_identifiers: dict
abi: list
bytecode: str
bytecode_runtime: str
warnings: list
factory_deps: list

def compile_zksync(file_name: str, compiler_args=None) -> ZksyncCompilerData:
output = json.loads(
_call_zkvyper(
# make sure zkvyper uses the same vyper as boa
"--vyper",
which("vyper"),
# request JSON output
"-f",
"combined_json",
# pass any extra compiler args
*(compiler_args or []),
# pass the file name
"--",
file_name,
)
)
return ZksyncCompilerData(**output[file_name])

def compile_zksync(file_name: str, compiler_args=None) -> ZksyncCompilerData:
compile_result = subprocess.run([
"zkvyper",
# make sure zkvyper uses the same vyper as boa
"--vyper",
which("vyper"),
# request JSON output
"-f",
"combined_json",
# pass any extra compiler args
*(compiler_args or []),
# pass the file name
"--",
file_name,
], capture_output=True)

def _call_zkvyper(*args):
result = subprocess.run(["zkvyper", *args], capture_output=True)
if result.returncode == 0:
return result.stdout.decode()
raise Exception(result.stderr.decode())
assert compile_result.returncode == 0, compile_result.stderr.decode()
output = json.loads(compile_result.stdout.decode())
return ZksyncCompilerData(**output[file_name])
2 changes: 2 additions & 0 deletions boa_zksync/deployer.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from boa.util.abi import Address

from boa_zksync.compile import ZksyncCompilerData
from boa_zksync.env import _ZksyncEnvMixin


class ZksyncDeployer(ABIContractFactory):
Expand All @@ -31,6 +32,7 @@ def deploy(self, *args, value=0, **kwargs):
else b""
)

assert isinstance(env, _ZksyncEnvMixin)
address, _ = env.deploy_code(
bytecode=initcode, value=value, constructor_calldata=constructor_calldata
)
Expand Down
10 changes: 5 additions & 5 deletions boa_zksync/ipython.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,22 @@
@magics_class
class TitanoboaZksyncMagic(Magics):
@line_cell_magic
def vyper(self, line, cell=None):
def zkvyper(self, line, cell=None):
if cell is None:
return eval_zksync(line)
return self.deployer(line, cell)
return self.zkdeployer(line, cell)

# unsure about "vyper" vs "contract" cell magic; keep both until decided
@cell_magic
def deployer(self, line, cell):
def zkdeployer(self, line, cell):
line = line or None
c = loads_zksync_partial(cell, name=line)
if line:
self.shell.user_ns[line] = c # ret available in user ipython locals
return c

@cell_magic
def contract(self, line, cell):
def zkcontract(self, line, cell):
line = line or None
c = loads_zksync(cell, name=line)
if line:
Expand All @@ -30,7 +30,7 @@ def contract(self, line, cell):

# unsure about "vyper" vs "eval" line magic; keep both until decided
@line_magic
def eval(self, line):
def zkeval(self, line):
return eval_zksync(line)


Expand Down

0 comments on commit 4d6f100

Please sign in to comment.