├── .github ├── CODEOWNERS ├── CONTRIBUTING.md ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_report.md ├── RELEASE.md ├── pull_request_template.md └── workflows │ ├── publish.yaml │ ├── release.yaml │ ├── test.yml │ └── validate.yml ├── .gitignore ├── .releaserc ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── LICENSE-APACHE ├── LICENSE-MIT ├── MANIFEST.in ├── Makefile ├── README.md ├── SECURITY.md ├── logo.svg ├── pyproject.toml ├── requirements.txt ├── scripts └── setup.py ├── setup.cfg ├── setup.py ├── tests ├── __init__.py ├── contracts │ ├── Counter.json │ ├── CustomAccount.json │ ├── CustomPaymaster.json │ ├── Foo.json │ ├── Import.json │ ├── Paymaster.json │ ├── SimpleConstructor.json │ ├── SomeERC20.json │ ├── Token.json │ ├── TwoUserMultisig.json │ ├── __init__.py │ └── utils.py ├── integration │ ├── __init__.py │ ├── test_config.py │ ├── test_contract_factory.py │ ├── test_paymaster.py │ ├── test_smart_account.py │ ├── test_smart_account_multisig.py │ ├── test_wallet.py │ ├── test_zksync_contract.py │ ├── test_zksync_web3.py │ └── token.json └── unit │ ├── __init__.py │ ├── test_config.py │ ├── test_contract_deploy.py │ ├── test_eip712.py │ ├── test_eth_signer.py │ ├── test_transaction712.py │ └── test_utils.py └── zksync2 ├── __init__.py ├── account ├── __init__.py ├── smart_account.py ├── smart_account_utils.py ├── utils.py ├── wallet.py ├── wallet_l1.py └── wallet_l2.py ├── core ├── __init__.py ├── types.py └── utils.py ├── eip712 ├── __init__.py ├── domain_separator.py ├── struct.py └── types.py ├── manage_contracts ├── __init__.py ├── contract_abi │ ├── IBridgehub.json │ ├── IContractDeployer.json │ ├── IERC1271.json │ ├── IERC20.json │ ├── IEthToken.json │ ├── IL1Bridge.json │ ├── IL1ERC20Bridge.json │ ├── IL1Messenger.json │ ├── IL1SharedBridge.json │ ├── IL2Bridge.json │ ├── IL2SharedBridge.json │ ├── INonceHolder.json │ ├── IPaymasterFlow.json │ ├── ITestnetERC20Token.json │ ├── IZkSync.json │ ├── IZkSyncHyperchain.json │ └── __init__.py ├── contract_encoder_base.py ├── contract_factory.py ├── deploy_addresses.py ├── paymaster_utils.py ├── precompute_contract_deployer.py └── utils.py ├── module ├── __init__.py ├── middleware.py ├── module_builder.py ├── request_types.py ├── response_types.py ├── zksync_module.py └── zksync_provider.py ├── signer ├── __init__.py └── eth_signer.py └── transaction ├── __init__.py ├── transaction712.py └── transaction_builders.py /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # This CODEOWNERS file sets the individuals responsible for code in the zksync2-js JavaScript SDK repository. 2 | 3 | # These users are the default owners for everything in the repo. 4 | # They will be requested for review when someone opens a pull request. 5 | * @zksync-sdk/txfusion 6 | 7 | # You can also specify code owners for specific directories or files. 8 | # For example: 9 | # /src/ @developer1 @developer2 10 | # /docs/ @documenter 11 | 12 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | ## Welcome! 👋 4 | 5 | Hello there, contributor! We're delighted that you're considering contributing to the `zksync2` project. This document is here to guide you through the steps and best practices for contributing to this Python-based repository. 6 | 7 | Please take a moment to review this document to ensure a smooth and efficient contribution process for everyone involved. 8 | 9 | ## Getting Started 10 | 11 | - **Fork the repository.** Begin by forking the main `zksync2-python` repository to your personal GitHub account. 12 | 13 | - **Clone the repository.** After forking, clone the repository to your local machine: 14 | 15 | ```bash 16 | git clone https://github.com//zksync2-python.git 17 | ``` 18 | 19 | - **Create a new branch.** Use descriptive names for your branches to help identify the feature, bugfix, or enhancement you're addressing: 20 | 21 | ```bash 22 | git checkout -b feature/description-of-your-feature 23 | ``` 24 | 25 | ## Making Changes 26 | 27 | - **Write your code.** Ensure your code is thoroughly tested and functions as expected. Clear, well-commented code is always appreciated. 28 | 29 | - **Compile and test.** Before submitting a pull request, ensure your code compiles, passes lint checks, and all tests are successful. You should also write unit tests for your contributions. Use the following command for these checks: 30 | 31 | 32 | - **Commit your changes.** Adhere to the [Conventional Commits](https://www.conventionalcommits.org/) standard when writing commit messages. 33 | 34 | - **Push your changes.** Push the changes to your forked repository: 35 | 36 | ```bash 37 | git push origin feature/description-of-your-feature 38 | ``` 39 | 40 | ## Submitting a Pull Request 41 | 42 | - **Initiate a pull request (PR).** Go to the main `zksync2-python` repository. Your recently pushed branch should be highlighted, showing a "Compare & pull request" button. Click on it and provide a clear, detailed description of your changes in the PR. 43 | 44 | - **Await a review.** Our maintainers will review your PR. They might request changes or clarifications, so be ready to address any feedback. 45 | 46 | ## Code Style Guide 47 | 48 | We follow basic coding style guidelines. Before committing, ensure your code is formatted 49 | 50 | ## Need Assistance? 51 | 52 | If you're unsure about something or have questions, don't hesitate to open an issue or initiate a discussion in our [ZKsync Community Hub](https://github.com/zkSync-Community-Hub/zkSync-developers/discussions). We're here to assist! 53 | 54 | ## What's Next? 55 | 56 | Once your PR is approved and merged, your contribution will be integrated into the `zksync2-python` repository. Congratulations, and thank you! We value your contribution and look forward to future collaborations. 57 | 58 | Remember, the best contributions come from enjoying the process, being respectful, and continuously learning. Thanks for being a part of our community! 59 | 60 | --- 61 | 62 | *Last updated: Dec 22, 2023* 63 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Use this template for reporting issues 4 | title: "" 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | ### 🐛 Bug Report for zksync2-pyton Python SDK 11 | 12 | #### 📝 Description 13 | 14 | Provide a clear and concise description of the bug. 15 | 16 | 17 | #### 🔄 Reproduction Steps 18 | 19 | 1. Step 1 20 | 2. Step 2 21 | 3. ... 22 | 23 | #### 🤔 Expected Behavior 24 | 25 | Describe what you expected to happen. 26 | 27 | #### 😯 Current Behavior 28 | 29 | Describe what actually happened. 30 | 31 | #### 🖥️ Environment 32 | 33 | - **Python version**: [e.g., Python 3.9] 34 | - **Operating System & Version**: [e.g., Ubuntu 20.04] 35 | - **Other relevant environment details**: 36 | 37 | #### 📋 Additional Context 38 | 39 | Add any other context about the problem here. If applicable, add screenshots to help explain. 40 | 41 | #### 📎 Log Output 42 | 43 | ``` 44 | Paste any relevant log output here. 45 | ``` 46 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Use this template for requesting features 4 | title: "" 5 | labels: feat 6 | assignees: '' 7 | 8 | --- 9 | 10 | ### 🌟 Feature Request 11 | 12 | #### 📝 Description 13 | 14 | Provide a clear and concise description of the feature you'd like to see. 15 | 16 | #### 🤔 Rationale 17 | 18 | Explain why this feature is important and how it benefits the project. 19 | 20 | #### 🖼️ Mockups/Examples 21 | 22 | If applicable, provide mockups or examples of how the feature would work. 23 | 24 | #### 📋 Additional Context 25 | 26 | Add any other context or information about the feature request here. 27 | -------------------------------------------------------------------------------- /.github/RELEASE.md: -------------------------------------------------------------------------------- 1 | # Release Process 2 | 3 | This document provides a comprehensive guide on the steps to execute a release for this project. 4 | 5 | ## Prerequisites 6 | 7 | Before initiating the release process, ensure the following prerequisites are met: 8 | 9 | - Commit messages must adhere to the [conventional commit specification](https://www.conventionalcommits.org/). 10 | - Proper permissions are in place to create and manage releases. 11 | 12 | ## Steps 13 | 14 | ### 1. Create Release 15 | 16 | 1. **Merge Pull Request to appropriate branch:** 17 | - Ensure that the changes intended for release are encapsulated in a Pull Request. 18 | - Merge the approved Pull Request into the `main`. Currently, 19 | only the `main` branch is allowed for releasing. 20 | 21 | 2. **Manual execution of [Release](workflows/release.yaml) Action:** 22 | - The `Release` GitHub Action automates versioning based on conventional commit messages. Pipeline creates tag, release, 23 | and pushes new commit in which updates `CHANGELOG.md` and version in `pyproject.toml`. 24 | - Click on the `Run workflow` button and select the desired branch or run the following command: 25 | `gh workflow run --ref release.yml`. 26 | 27 | ### 2. Publish Release 28 | 29 | 1. Releases on GitHub are automatically uploaded (it requires some time to registry index the release). -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | # What :computer: 2 | * First thing updated with this PR 3 | * Second thing updated with this PR 4 | * Third thing updated with this PR 5 | 6 | # Why :hand: 7 | * Reason why first thing was added to PR 8 | * Reason why second thing was added to PR 9 | * Reason why third thing was added to PR 10 | 11 | # Evidence :camera: 12 | Include screenshots, screen recordings, or `console` output here demonstrating that your changes work as intended 13 | 14 | 15 | 16 | # Notes :memo: 17 | * Any notes/thoughts that the reviewers should know prior to reviewing the code? 18 | 19 | -------------------------------------------------------------------------------- /.github/workflows/publish.yaml: -------------------------------------------------------------------------------- 1 | name: Publish Python library 2 | 3 | on: 4 | workflow_dispatch: 5 | 6 | env: 7 | GITHUB_REF: "${{ github.ref }}" 8 | 9 | jobs: 10 | build_and_publish: 11 | name: Build distribution of library 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v4 15 | - name: Set up Python 3 16 | uses: actions/setup-python@v4 17 | with: 18 | python-version: '3.8' 19 | cache: 'pip' # caching pip dependencies 20 | - name: Prepare build 21 | run: python3 -m pip install --upgrade build 22 | - name: Install Twine 23 | run: python3 -m pip install --upgrade twine 24 | - name: Build package 25 | run: python3 -m build 26 | - name: Check distribution 27 | run: python3 -m twine check --strict dist/* 28 | - name: Publish package 29 | run: python3 -m twine upload dist/* 30 | env: 31 | TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }} 32 | TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }} -------------------------------------------------------------------------------- /.github/workflows/release.yaml: -------------------------------------------------------------------------------- 1 | name: Release 2 | on: 3 | workflow_dispatch: 4 | 5 | permissions: 6 | contents: read # for checkout 7 | 8 | jobs: 9 | release: 10 | name: Release 11 | runs-on: ubuntu-latest 12 | permissions: 13 | contents: write # to be able to publish a GitHub release 14 | issues: write # to be able to comment on released issues 15 | pull-requests: write # to be able to comment on released pull requests 16 | steps: 17 | - name: Checkout 18 | uses: actions/checkout@v4 19 | with: 20 | fetch-depth: 0 21 | - name: Setup Node.js 22 | uses: actions/setup-node@v4 23 | with: 24 | node-version: "lts/*" 25 | - name: Install dependencies 26 | run: | 27 | npm install -g "semantic-release@21.0.7" \ 28 | "@semantic-release/commit-analyzer@11.1.0" \ 29 | "@semantic-release/changelog@6.0.3" \ 30 | "@semantic-release/git@10.0.1" \ 31 | "@semantic-release/github@9.0.4" \ 32 | "semantic-release-pypi@3.0.0" 33 | - name: Release 34 | env: 35 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 36 | run: npx semantic-release -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Run tests 2 | on: 3 | push: 4 | branches: [ master, beta ] 5 | workflow_dispatch: 6 | pull_request: 7 | branches: [ master, beta ] 8 | types: [ opened, reopened, synchronize ] 9 | 10 | permissions: 11 | contents: read # for checkout 12 | 13 | jobs: 14 | test: 15 | name: Test 16 | runs-on: ubuntu-latest 17 | steps: 18 | - name: Checkout 19 | uses: actions/checkout@v4 20 | with: 21 | fetch-depth: 0 22 | - name: Set up Python 3 23 | uses: actions/setup-python@v4 24 | with: 25 | python-version: '3.8' 26 | cache: 'pip' # caching pip dependencies 27 | - name: Install dependencies 28 | run: pip install -r requirements.txt 29 | - name: Run local-setup 30 | run: | 31 | git clone https://github.com/matter-labs/local-setup.git 32 | pushd local-setup 33 | ./start-zk-chains.sh 34 | popd 35 | - name: Prepare environment 36 | run: make prepare-environment 37 | - name: Run tests 38 | run: make run-tests 39 | -------------------------------------------------------------------------------- /.github/workflows/validate.yml: -------------------------------------------------------------------------------- 1 | name: Validate 2 | on: 3 | pull_request: 4 | branch: main 5 | types: [ opened, reopened, synchronize ] 6 | 7 | permissions: 8 | contents: read # for checkout 9 | 10 | jobs: 11 | lint: 12 | name: Check code format 13 | runs-on: ubuntu-latest 14 | steps: 15 | - name: Checkout 16 | uses: actions/checkout@v4 17 | with: 18 | fetch-depth: 0 19 | - name: Set up Python 3 20 | uses: actions/setup-python@v4 21 | with: 22 | python-version: '3.8' 23 | cache: 'pip' # caching pip dependencies 24 | - name: Install dependencies 25 | run: pip install black 26 | - name: Check code format 27 | run: make check-code-format 28 | commits: 29 | name: Check commits 30 | runs-on: ubuntu-latest 31 | if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository 32 | steps: 33 | - name: Checkout 34 | uses: actions/checkout@v4 35 | - name: Setup Node.js 36 | uses: actions/setup-node@v4 37 | with: 38 | node-version: "lts/*" 39 | - name: Install dependencies 40 | run: npm install -g @commitlint/cli@18.6.1 @commitlint/config-conventional@18.6.2 41 | - name: Configure 42 | run: | 43 | echo 'module.exports = {"extends": ["@commitlint/config-conventional"]}' > commitlint.config.js 44 | - name: Validate 45 | run: | 46 | git fetch 47 | npx commitlint \ 48 | --from ${{ github.event.pull_request.head.sha }}~${{ github.event.pull_request.commits }} \ 49 | --to ${{ github.event.pull_request.head.sha }} \ 50 | --verbose 51 | commits-fork: 52 | name: Check commits from forks 53 | runs-on: ubuntu-latest 54 | if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository 55 | steps: 56 | - name: Checkout 57 | uses: actions/checkout@v4 58 | - name: Setup Node.js 59 | uses: actions/setup-node@v4 60 | with: 61 | node-version: "lts/*" 62 | - name: Install dependencies 63 | run: npm install -g @commitlint/cli@18.6.1 @commitlint/config-conventional@18.6.2 64 | - name: Configure 65 | run: | 66 | echo 'module.exports = {"extends": ["@commitlint/config-conventional"]}' > commitlint.config.js 67 | - name: Validate 68 | run: | 69 | git fetch origin "+refs/pull/${{ github.event.pull_request.number }}/head:refs/pull/${{ github.event.pull_request.number }}/head" 70 | git checkout "refs/pull/${{ github.event.pull_request.number }}/head" 71 | npx commitlint \ 72 | --from HEAD~${{ github.event.pull_request.commits }} \ 73 | --to HEAD \ 74 | --verbose -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | share/python-wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | MANIFEST 28 | 29 | # PyInstaller 30 | # Usually these files are written by a python script from a template 31 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 32 | *.manifest 33 | *.spec 34 | 35 | # Installer logs 36 | pip-log.txt 37 | pip-delete-this-directory.txt 38 | 39 | # Unit test / coverage reports 40 | htmlcov/ 41 | .tox/ 42 | .nox/ 43 | .coverage 44 | .coverage.* 45 | .cache 46 | nosetests.xml 47 | coverage.xml 48 | *.cover 49 | *.py,cover 50 | .hypothesis/ 51 | .pytest_cache/ 52 | cover/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | .pybuilder/ 76 | target/ 77 | 78 | # Jupyter Notebook 79 | .ipynb_checkpoints 80 | 81 | # IPython 82 | profile_default/ 83 | ipython_config.py 84 | 85 | # pyenv 86 | # For a library or package, you might want to ignore these files since the code is 87 | # intended to run in multiple environments; otherwise, check them in: 88 | # .python-version 89 | 90 | # pipenv 91 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 92 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 93 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 94 | # install all needed dependencies. 95 | #Pipfile.lock 96 | 97 | # poetry 98 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. 99 | # This is especially recommended for binary packages to ensure reproducibility, and is more 100 | # commonly ignored for libraries. 101 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control 102 | #poetry.lock 103 | 104 | # pdm 105 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. 106 | #pdm.lock 107 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it 108 | # in version control. 109 | # https://pdm.fming.dev/#use-with-ide 110 | .pdm.toml 111 | 112 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm 113 | __pypackages__/ 114 | 115 | # Celery stuff 116 | celerybeat-schedule 117 | celerybeat.pid 118 | 119 | # SageMath parsed files 120 | *.sage.py 121 | 122 | # Environments 123 | .env 124 | .venv 125 | env/ 126 | venv/ 127 | ENV/ 128 | env.bak/ 129 | venv.bak/ 130 | 131 | # Spyder project settings 132 | .spyderproject 133 | .spyproject 134 | 135 | # Rope project settings 136 | .ropeproject 137 | 138 | # mkdocs documentation 139 | /site 140 | 141 | # mypy 142 | .mypy_cache/ 143 | .dmypy.json 144 | dmypy.json 145 | 146 | # Pyre type checker 147 | .pyre/ 148 | 149 | # pytype static type analyzer 150 | .pytype/ 151 | 152 | # Cython debug symbols 153 | cython_debug/ 154 | 155 | # PyCharm 156 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can 157 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore 158 | # and can be added to the global gitignore or merged into this file. For a more nuclear 159 | # option (not recommended) you can uncomment the following to ignore the entire idea folder. 160 | .idea/ 161 | 162 | !examples/*/*/build 163 | 164 | .DS_Store 165 | 166 | -------------------------------------------------------------------------------- /.releaserc: -------------------------------------------------------------------------------- 1 | { 2 | "repositoryUrl": "https://github.com/zksync-sdk/zksync2-python.git", 3 | "branches": "master", 4 | "debug": true, 5 | "addReleases": "top", 6 | "preset": "angular", 7 | "plugins": [ 8 | "@semantic-release/commit-analyzer", 9 | "@semantic-release/release-notes-generator", 10 | [ 11 | "@semantic-release/changelog", 12 | { 13 | "changelogFile": "CHANGELOG.md" 14 | } 15 | ], 16 | [ 17 | "semantic-release-pypi", 18 | { 19 | "pypiPublish": false 20 | } 21 | ], 22 | [ 23 | "@semantic-release/git", 24 | { 25 | "assets": ["CHANGELOG.md", "pyproject.toml"], 26 | "message": "${nextRelease.version} version bump [skip ci]\n\n${nextRelease.notes}" 27 | } 28 | ], 29 | "@semantic-release/github" 30 | ] 31 | } -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # [2.0.0](https://github.com/zksync-sdk/zksync2-python/compare/v1.2.0...v2.0.0) (2024-11-08) 2 | 3 | 4 | ### Bug Fixes 5 | 6 | * `estimate_default_bridge_deposit_l2_gas` use correct token ([a173430](https://github.com/zksync-sdk/zksync2-python/commit/a173430e30f40e3cbc93cceca3581cec99b8e0c0)) 7 | * **wallet:** fix custom bridge support ([a095d5a](https://github.com/zksync-sdk/zksync2-python/commit/a095d5a21e92baaa58adde5a5e4f7f90a8f0bcfc)) 8 | * **wallet:** use `l2BridgeAddress` in `_get_l2_gas_limit_from_custom_bridge` ([b94636a](https://github.com/zksync-sdk/zksync2-python/commit/b94636a75ff3949256f8764bf658ba1f4cbfcbc8)) 9 | 10 | 11 | ### Features 12 | 13 | * `LegacyContractFactory` add `createAccount` and `create2Account` ([2daa365](https://github.com/zksync-sdk/zksync2-python/commit/2daa365ccc937721dcf647bd65afb28a307b4f8f)) 14 | * add `SmartAccount` feature ([15eb303](https://github.com/zksync-sdk/zksync2-python/commit/15eb303d5959d97348b4a81a007071a9dbd0c215)) 15 | * improve `provider` typing ([215168c](https://github.com/zksync-sdk/zksync2-python/commit/215168c4654a2f3f8ccea3952f3dbbd0808434c5)) 16 | * **provider:** add `is_l2_bridge_legacy` ([5cb4eb8](https://github.com/zksync-sdk/zksync2-python/commit/5cb4eb8b8f312a2e19a61d994254abe5604360db)) 17 | * **provider:** add `zks_get_confirmed_tokens` ([fc72cf9](https://github.com/zksync-sdk/zksync2-python/commit/fc72cf9ed637b0843e1f7bc784d94a7b31310cb6)) 18 | * **provider:** add `zks_get_fee_params` ([82848dc](https://github.com/zksync-sdk/zksync2-python/commit/82848dccd1807e7dcff3f095dc711b77f4514b03)) 19 | * **provider:** add `zks_get_protocol_version` ([5005ef1](https://github.com/zksync-sdk/zksync2-python/commit/5005ef13db214c909dccecc796477b0ccaaa76eb)) 20 | * **provider:** add `zks_send_raw_transaction_with_detailed_output` ([b306242](https://github.com/zksync-sdk/zksync2-python/commit/b3062420992c80d5534a380981e1097be447961d)) 21 | * update `web3` to the latest version ([cd0c34c](https://github.com/zksync-sdk/zksync2-python/commit/cd0c34cb3c3afd48a75bab692ad23dc8a3e52d1c)) 22 | * **wallet:** add `l1_token_address` ([b6c49d3](https://github.com/zksync-sdk/zksync2-python/commit/b6c49d3d9acc0bb5dcb60ab9092278498dc6c699)) 23 | 24 | 25 | ### BREAKING CHANGES 26 | 27 | * update to `web3` `v7` 28 | 29 | # [1.2.0](https://github.com/zksync-sdk/zksync2-python/compare/v1.1.0...v1.2.0) (2024-06-07) 30 | 31 | 32 | ### Bug Fixes 33 | 34 | * fix abi contract cache ([81b9e4c](https://github.com/zksync-sdk/zksync2-python/commit/81b9e4c8bec9cd2fc258669edeb8012ccafa0c80)) 35 | * non zero gas limit in options breaks transfer function ([d739a60](https://github.com/zksync-sdk/zksync2-python/commit/d739a604f7ff43bc372586377d861d66745980b4)) 36 | * zks_l1_chain_id not returning int type ([0ebd1b8](https://github.com/zksync-sdk/zksync2-python/commit/0ebd1b8499d22b1c83a1051b77a461841e1a4f0d)) 37 | 38 | 39 | ### Features 40 | 41 | * provide support for Bridgehub ([dabbfc0](https://github.com/zksync-sdk/zksync2-python/commit/dabbfc0c95f11e79e6683101b20fae3c851506e8)) 42 | 43 | # [1.2.0](https://github.com/zksync-sdk/zksync2-python/compare/v1.1.0...v1.2.0) (2024-06-07) 44 | 45 | 46 | ### Bug Fixes 47 | 48 | * fix abi contract cache ([81b9e4c](https://github.com/zksync-sdk/zksync2-python/commit/81b9e4c8bec9cd2fc258669edeb8012ccafa0c80)) 49 | * non zero gas limit in options breaks transfer function ([d739a60](https://github.com/zksync-sdk/zksync2-python/commit/d739a604f7ff43bc372586377d861d66745980b4)) 50 | * zks_l1_chain_id not returning int type ([0ebd1b8](https://github.com/zksync-sdk/zksync2-python/commit/0ebd1b8499d22b1c83a1051b77a461841e1a4f0d)) 51 | 52 | 53 | ### Features 54 | 55 | * provide support for Bridgehub ([dabbfc0](https://github.com/zksync-sdk/zksync2-python/commit/dabbfc0c95f11e79e6683101b20fae3c851506e8)) 56 | 57 | # [1.1.0](https://github.com/zksync-sdk/zksync2-python/compare/v1.0.0...v1.1.0) (2024-02-18) 58 | 59 | 60 | ### Features 61 | 62 | * paymster withdraw and transfer support ([66f7761](https://github.com/zksync-sdk/zksync2-python/commit/66f7761bf4a1677ed50a6bf995e0fde6515b76b7)) 63 | * **provider:** add zks_logProof ([6d48dff](https://github.com/zksync-sdk/zksync2-python/commit/6d48dff8e7e81709b637d2117ba6a2c843e9d740)) 64 | 65 | # [1.0.0](https://github.com/zksync-sdk/zksync2-python/compare/v0.6.0...v1.0.0) (2024-01-19) 66 | 67 | 68 | ### Bug Fixes 69 | 70 | * `withdraw` bridge address ([6334874](https://github.com/zksync-sdk/zksync2-python/commit/6334874c8022407ce360b0bd35118fb7cbad66d1)) 71 | * `withdraw` token bridge address ([6d5b45c](https://github.com/zksync-sdk/zksync2-python/commit/6d5b45c334dde44ad9bdc83642f458950fd722a6)) 72 | * `withdraw` token bridge address ([279bfd8](https://github.com/zksync-sdk/zksync2-python/commit/279bfd874f7b998b4dd2e00165433e9990d29c74)) 73 | * relax web3 version restriction ([5d50182](https://github.com/zksync-sdk/zksync2-python/commit/5d5018242c3d4cae1957c99a43944eb4652b9cc1)) 74 | * resolve issue relate to `wETH` bridge ([48ac8cd](https://github.com/zksync-sdk/zksync2-python/commit/48ac8cd5aac80214a9be399bcade222f8d97dd2c)) 75 | 76 | 77 | ### Features 78 | 79 | * add `WalletL1`, `WalletL2` and `Wallet` ([b189068](https://github.com/zksync-sdk/zksync2-python/commit/b1890685638192edc7279a2273ae14ee41e2c904)) 80 | * remove deprications ([d2f2ce7](https://github.com/zksync-sdk/zksync2-python/commit/d2f2ce707847404787539a88ee0f573fe6d806f2)) 81 | 82 | 83 | ### BREAKING CHANGES 84 | 85 | * remove all deprications 86 | 87 | ## [0.6.0](https://github.com/zksync-sdk/zksync2-python/compare/v0.5.0...v0.6.0) (2023-07-07) 88 | 89 | ### Features 90 | 91 | * add account abstraction and paymaster features ([28f930c](https://github.com/zksync-sdk/zksync2-python/commit/28f930ce6e68f11110c0afc7c8c0f5fc2253ab28)) 92 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | Version: 1.1 4 | 5 | Apache 2.0 license, derived from the Apache Foundation Code of Conduct. 6 | Also, CC BY-SA 3.0 derived from the Mozilla Community Participation Guidelines. 7 | 8 | Our goal is to cultivate a safe, friendly, and inclusive space that benefits all participants in the ZKsync ecosystem. 9 | This Code of Conduct outlines our shared values and expectations to help ensure that the community remains a positive and enriching environment for everyone. 10 | 11 | ## When and how to use this Code of Conduct 12 | 13 | This is your guide for engaging as a participant in the ZKsync ecosystem. 14 | It applies to all physical and digital spaces related to ZKsync. 15 | 16 | ## Expected behaviors 17 | 18 | **Be ethical**: 19 | We endeavor to enrich the ZKsync ecosystem, while not infringing on the rights and wellbeing of others. 20 | We also endeavor to enrich ourselves without causing harm to the ZKsync community. 21 | We do not encourage tax evasion, promoting information leaks, speculating on tokens or token prices, or otherwise breaking the law. 22 | 23 | **Be kind and respectful**: 24 | Treat everyone with kindness, empathy, and respect. 25 | We all come from different backgrounds, perspectives and experiences, 26 | so let's celebrate our differences and foster a culture of openness and understanding. 27 | We may have strong feelings about other layer 1 and layer 2 blockchains, 28 | but that is no reason to disparage, defame, or slander any competitor to ZKsync or what other chains are doing. 29 | Feel free to compare metrics and features, but keep to the facts and be respectful of all the builders in web3 30 | trying to advance freedom through blockchain technology! 31 | 32 | **Share and learn**: 33 | Our community is a space for sharing knowledge, experiences, and ideas. 34 | Positively contribute to discussions, offer helpful feedback, 35 | be willing to educate others on your work and remain open to learning from others. 36 | 37 | **Give credit**: 38 | When sharing content or ideas that aren't your own, ensure you give proper credit to the original creator. 39 | Plagiarism and intellectual property infringement are strictly prohibited. 40 | 41 | **Respect privacy**: 42 | Always seek consent before sharing personal information about yourself or others. 43 | Respecting each other's privacy is vital to building trust within our community. 44 | 45 | **Be inquisitive and embrace continuous improvement**: 46 | We strive to improve from each experience, and are open to constructive criticism. 47 | We encourage questions, and redirect them to the appropriate channel if we do not have the answer. 48 | 49 | **Mind your language**: 50 | Communication is key. 51 | Use clear and considerate language in your interactions. 52 | We aim to create a welcoming environment for users of all ages, so please avoid excessive profanity or explicit content. 53 | Remember that ZKsync community members are a diverse bunch. 54 | English is our primary working language, but to help others where English is not their first language, 55 | be succinct and avoid acronyms where possible. 56 | 57 | **Stay on topic**: 58 | While we encourage friendly conversations, please ensure your discussions remain relevant to the community's purpose. 59 | To keep our space focused and valuable, off-topic or irrelevant content may be redirected or removed. 60 | Specific topics that are not appropriate include offering to buy or sell any cryptocurrency or engage in price speculation. 61 | 62 | **No hate speech or harassment**: 63 | Let's maintain a constructive and uplifting atmosphere in all interactions. 64 | We have a zero-tolerance policy for any form of hate speech, bullying, harassment, or discrimination. 65 | This includes, but is not limited to: 66 | 67 | - Violent threats or language directed against another person. 68 | - Sexist, racist, or otherwise discriminatory jokes and language. 69 | - Posting sexually explicit or violent material. 70 | - Posting (or threatening to post) other people's personally identifying information ("doxing"). 71 | - Sharing private content without explicit consent, such as messages sent privately or non-publicly. 72 | - Personal insults. 73 | - Unwelcome sexual attention. 74 | - Excessive or unnecessary profanity. 75 | - Repeated harassment of others. In general, if someone asks you to stop, then stop. 76 | - Advocating for, or encouraging, any of the above behavior. 77 | 78 | **Have fun and connect**: 79 | Finally, remember that ZK Squad and the ZKsync community is a place to connect, learn, and enjoy. 80 | Participate in a manner that encourages positive interactions and enhances the experiences of all. 81 | 82 | ## Managing violations 83 | 84 | If you come across inappropriate content or behavior, please report it without delay. 85 | By working together, we can maintain a positive and safe environment. 86 | 87 | If you are the subject of, or witness to, any violations of this Code of Conduct, please contact us at community@zksync.io. -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 zkSync SDK 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include README.md 2 | include requirements.txt 3 | recursive-exclude * __pycache__ 4 | recursive-include zksync2/manage_contracts/contract_abi/* 5 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | run-tests: 2 | python -m unittest discover -s tests 3 | 4 | prepare-environment: 5 | python scripts/setup.py 6 | 7 | check-code-format: 8 | black --check zksync2 scripts tests 9 | 10 | format-code: 11 | black zksync2 scripts tests -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 🚀 zksync2 Python SDK 🚀 2 | 3 | [![License](https://img.shields.io/badge/license-MIT-blue)](LICENSE-MIT) 4 | [![License: Apache 2.0](https://img.shields.io/badge/license-Apache%202.0-orange)](LICENSE-APACHE) 5 | [![Contributor Covenant](https://img.shields.io/badge/Contributor%20Covenant-2.1-4baaaa.svg)](https://www.contributor-covenant.org/) 6 | [![Contributions Welcome](https://img.shields.io/badge/contributions-welcome-orange)](.github/CONTRIBUTING.md) 7 | [![X (formerly Twitter) Follow](https://badgen.net/badge/twitter/@zksyncDevs/1DA1F2?icon&label)](https://x.com/zksyncDevs) 8 | [![Code Style: Google](https://img.shields.io/badge/code%20style-google-blueviolet.svg)](https://github.com/google/gts) 9 | 10 | [![ZKsync Era Logo](logo.svg)](https://zksync.io/) 11 | 12 | In order to provide easy access to all the features of ZKsync Era, the `zksync2` Python SDK was created, 13 | which is made in a way that has an interface very similar to those of [web3.py](https://web3py.readthedocs.io/en/v6.6.1/). In 14 | fact, `web3.py` is a peer dependency of our library and most of the objects exported by `zksync2` inherit from the corresponding `web3.py` objects and override only the fields that need 15 | to be changed. 16 | 17 | While most of the existing SDKs functionalities should work out of the box, deploying smart contracts or using unique ZKsync Era features, 18 | like account abstraction, requires providing additional fields to those that Ethereum transactions have by default. 19 | 20 | The library is made in such a way that after replacing `web3.py` with `zksync2` most client apps will work out of 21 | box. 22 | 23 | 🔗 For a detailed walkthrough, refer to the [official documentation](https://docs.zksync.io/sdk/python/getting-started). 24 | 25 | ## 📌 Overview 26 | 27 | To begin, it is useful to have a basic understanding of the types of objects available and what they are responsible for, at a high level: 28 | 29 | - `Provider` provides connection to the ZKsync Era blockchain, which allows querying the blockchain state, such as account, block or transaction details, 30 | querying event logs or evaluating read-only code using call. Additionally, the client facilitates writing to the blockchain by sending 31 | transactions. 32 | - `Wallet` wraps all operations that interact with an account. An account generally has a private key, which can be used to sign a variety of 33 | types of payloads. It provides easy usage of the most common features. 34 | 35 | ## 🛠 Prerequisites 36 | | Tool | Required | 37 | |-----------------|----------------| 38 | | python | 3.8, 3.9, 3.10 | 39 | | package manager | pip | 40 | 41 | ## 📥 Installation & Setup 42 | 43 | ```console 44 | pip install zksync2 45 | ``` 46 | ## 📝 Examples 47 | 48 | The complete examples with various use cases are available [here](https://github.com/zksync-sdk/zksync2-examples/tree/main/python). 49 | 50 | ### Connect to the ZKsync Era network: 51 | 52 | ```python 53 | from zksync2.module.module_builder import ZkSyncBuilder 54 | ... 55 | web3 = ZkSyncBuilder.build("ZKSYNC_NET_URL") 56 | ``` 57 | 58 | ### Account 59 | 60 | Account encapsulate private key and, frequently based on it, the unique user identifier in the network.
This unique identifier also mean by wallet address. 61 | 62 | #### Account construction 63 | 64 | ZkSync2 Python SDK account is compatible with `eth_account` package 65 | In most cases user has its private key and gets account instance by using it. 66 | 67 | ```python 68 | from eth_account import Account 69 | from eth_account.signers.local import LocalAccount 70 | ... 71 | account: LocalAccount = Account.from_key("PRIVATE_KEY") 72 | 73 | ``` 74 | 75 | The base property that is used directly of account is: `Account.address` 76 | 77 | 78 | ### Signer 79 | 80 | Signer is used to generate signature of provided transaction based on your account(your private key)
81 | This signature is added to the final EIP712 transaction for its validation 82 | 83 | 84 | #### Signer construction 85 | 86 | zkSync2 already has implementation of signer. For constructing the instance it needs only account and chain_id 87 | 88 | Example: 89 | 90 | ```python 91 | from zksync2.signer.eth_signer import PrivateKeyEthSigner 92 | from eth_account import Account 93 | from zksync2.module.module_builder import ZkSyncBuilder 94 | 95 | 96 | account = Account.from_key("PRIVATE_KEY") 97 | zksync_web3 = ZkSyncBuilder.build("ZKSYNC_NETWORK_URL") 98 | ... 99 | chain_id = zksync_web3.zksync.chain_id 100 | signer = PrivateKeyEthSigner(account, chain_id) 101 | ``` 102 | 103 | ### Create a wallet 104 | 105 | ```python 106 | PRIVATE_KEY = HexStr("") 107 | account: LocalAccount = Account.from_key(env_key.key) 108 | wallet = Wallet(zk_sync, eth_web3, account) 109 | ``` 110 | 111 | ### Check account balances 112 | 113 | ```python 114 | eth_balance = wallet.getBalance() # balance on ZKsync Era network 115 | 116 | eth_balance_l1 = wallet.getBalanceL1() # balance on goerli network 117 | ``` 118 | 119 | ### Transfer funds 120 | 121 | Transfer funds among accounts on L2 network. 122 | 123 | ```python 124 | receiver = account.create().address 125 | 126 | transfer = wallet.transfer( 127 | TransferTransaction(to=Web3.to_checksum_address(receiver), 128 | token_address=ADDRESS_DEFAULT, 129 | amount=Web3.to_wei(0.1, "ether"))) 130 | ``` 131 | 132 | ### Deposit funds 133 | 134 | Transfer funds from L1 to L2 network. 135 | 136 | ```python 137 | transfer = wallet.deposit( 138 | DepositTransaction(token_address=ADDRESS_DEFAULT, 139 | amount=Web3.to_wei(0.1, "ether"))) 140 | ``` 141 | 142 | ### Withdraw funds 143 | 144 | Transfer funds from L2 to L1 network. 145 | 146 | ```python 147 | transfer = wallet.deposit( 148 | WithdrawTransaction(token_address=ADDRESS_DEFAULT, 149 | amount=Web3.to_wei(0.1, "ether"))) 150 | ``` 151 | 152 | ## 🤖Running Tests 153 | 154 | In order to run test you need to run local-setup on your machine. For running tests, use: 155 | ```console 156 | make wait 157 | make prepare-tests 158 | make run-tests 159 | ``` 160 | 161 | ## 🤝 Contributing 162 | 163 | We welcome contributions from the community! If you're interested in contributing to the `zksync2` Python SDK, 164 | please take a look at our [CONTRIBUTING.md](./.github/CONTRIBUTING.md) for guidelines and details on the process. 165 | 166 | Thank you for making `zksync2` Python SDK better! 🙌 167 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | We truly appreciate efforts to discover and disclose security issues responsibly! 4 | 5 | ## Vulnerabilities 6 | 7 | If you'd like to report a security issue in the repositories of matter-labs organization, please proceed to our 8 | [Bug Bounty Program on Immunefi](https://era.zksync.io/docs/reference/troubleshooting/audit-bug-bounty.html#bug-bounty-program). 9 | 10 | ## Other Security Issues 11 | 12 | We take an impact-first approach instead of a rules-first approach. Therefore, if you believe you found the impactful 13 | issue but can't report it via the Bug Bounty, please email us at 14 | [security@matterlabs.dev](mailto:security@matterlabs.dev). 15 | 16 | ### PGP Key 17 | 18 | The following PGP key may be used to communicate sensitive information to developers: 19 | 20 | Fingerprint: `5FED B2D0 EA2C 4906 DD66 71D7 A2C5 0B40 CE3C F297` 21 | 22 | ```text 23 | -----BEGIN PGP PUBLIC KEY BLOCK----- 24 | 25 | mQINBGEBmQkBEAD6tlkBEZFMvR8kOgxXX857nC2+oTik6TopJz4uCskuqDaeldMy 26 | l+26BBzLkIeO1loS+bzVgnNFJRrGt9gv98MzNEHJVv6D7GsSLlUX/pz7Lxn0J4ry 27 | o5XIk3MQTCUBdaXGs6GBLl5Xe8o+zNj4MKd4zjgDLinITNlE/YZCDsXyvYS3YFTQ 28 | cwaUTNlawkKgw4BLaEqwB2JuyEhI9wx5X7ibjFL32sWMolYsNAlzFQzM09HCurTn 29 | q0DYau9kPJARcEk9/DK2iq0z3gMCQ8iRTDaOWd8IbSP3HxcEoM5j5ZVAlULmjmUE 30 | StDaMPLj0Kh01Tesh/j+vjchPXHT0n4zqi1+KOesAOk7SIwLadHfQMTpkU7G2fR1 31 | BrA5MtlzY+4Rm6o7qu3dpZ+Nc4iM3FUnaQRpvn4g5nTh8vjG94OCzX8DXWrCKyxx 32 | amCs9PLDYOpx84fXYv4frkWpKh2digDSUGKhoHaOSnqyyvu3BNWXBCQZJ20rqEIu 33 | sXOQMxWIoWCOOPRRvrHrKDA2hpoKjs3pGsProfpVRzb9702jhWpTfbDp9WjQlFtX 34 | 2ZIDxlwAxcugClgrp5JiUxvhg2A9lDNwCF7r1e68uNv5usBZQVKPJmnvS2nWgKy8 35 | x9oJsnwrEjxwiRHd34UvfMkwY9RENSJ+NoXqBdS7Lwz4m6vgbzq6K56WPQARAQAB 36 | tCRaa1N5bmMgU2VjdXJpdHkgPHNlY3VyaXR5QHprc3luYy5pbz6JAk4EEwEKADgW 37 | IQRf7bLQ6ixJBt1mcdeixQtAzjzylwUCYQGZCQIbAwULCQgHAgYVCgkICwIEFgID 38 | AQIeAQIXgAAKCRCixQtAzjzyl5y8EAC/T3oq88Dak2b+5TlWdU2Gpm6924eAqlMt 39 | y1KksDezzNQUlPiCUVllpin2PIjU/S+yzMWKXJA04LoVkEPfPOWjAaavLOjRumxu 40 | MR6P2dVUg1InqzYVsJuRhKSpeexzNA5qO2BPM7/I2Iea1IoJPjogGbfXCo0r5kne 41 | KU7a5GEa9eDHxpHTsbphQe2vpQ1239mUJrFpzAvILn6jV1tawMn5pNCXbsa8l6l2 42 | gtlyQPdOQECy77ZJxrgzaUBcs/RPzUGhwA/qNuvpF0whaCvZuUFMVuCTEu5LZka2 43 | I9Rixy+3jqBeONBgb+Fiz5phbiMX33M9JQwGONFaxdvpFTerLwPK2N1T8zcufa01 44 | ypzkWGheScFZemBxUwXwK4x579wjsnfrY11w0p1jtDgPTnLlXUA2mom4+7MyXPg0 45 | F75qh6vU1pdXaCVkruFgPVtIw+ccw2AxD50iZQ943ZERom9k165dR9+QxOVMXQ4P 46 | VUxsFZWvK70/s8TLjsGljvSdSOa85iEUqSqh0AlCwIAxLMiDwh5s/ZgiHoIM6Xih 47 | oCpuZyK9p0dn+DF/XkgAZ/S91PesMye3cGm6M5r0tS26aoc2Pk6X37Hha1pRALwo 48 | MOHyaGjc/jjcXXxv6o55ALrOrzS0LQmLZ+EHuteCT15kmeY3kqYJ3og62KgiDvew 49 | dKHENvg7d7kCDQRhAZleARAA6uD6WfdqGeKV5i170+kLsxR3QGav0qGNAbxpSJyn 50 | iHQ8u7mQk3S+ziwN2AAopfBk1je+vCWtEGC3+DWRRfJSjLbtaBG8e6kLP3/cGA75 51 | qURz6glTG4nl5fcEAa6B1st0OxjVWiSLX3g/yjz8lznQb9awuRjdeHMnyx5DsJUN 52 | d+Iu5KxGupQvKGOMKivSvC8VWk9taaQRpRF+++6stLCDk3ZtlxiopMs3X2jAp6xG 53 | sOBbix1cv9BTsfaiL7XDL/gviqBPXYY5L42x6+jnPo5lROfnlLYkWrv6KZr7HD4k 54 | tRXeaSwxLD2EkUyb16Jpp0be/ofvBtITGUDDLCGBiaXtx/v8d52MARjsyLJSYloj 55 | 1yiW01LfAiWHUC4z5jl2T7E7sicrlLH1M8Z6WbuqjdeaYwtfyPA2YCKr/3fn6pIo 56 | D+pYaBSESmhA92P+XVaf5y2BZ6Qf8LveDpWwsVGdBGh9T0raA1ooe1GESLjmIjUa 57 | z5AeQ/uXL5Md9I6bpMUUJYQiH19RPcFlJriI3phXyyf6Wlkk8oVEeCWyzcmw+x1V 58 | deRTvE2x4WIwKGLXRNjin2j1AP7vU2HaNwlPrLijqdyi68+0irRQONoH7Qonr4ca 59 | xWgL+pAaa3dWxf0xqK7uZFp4aTVWlr2uXtV/eaUtLmGMCU0jnjb109wg5L0F7WRT 60 | PfEAEQEAAYkCNgQYAQoAIBYhBF/tstDqLEkG3WZx16LFC0DOPPKXBQJhAZleAhsM 61 | AAoJEKLFC0DOPPKXAAEP/jK7ch9GkoaYlsuqY/aHtxEwVddUDOxjyn3FMDoln85L 62 | /n8AmLQb2bcpKSqpaJwMbmfEyr5MDm8xnsBTfx3u6kgaLOWfKxjLQ6PM7kgIMdi4 63 | bfaRRuSEI1/R6c/hNpiGnzAeeexldH1we+eH1IVmh4crdat49S2xh7Qlv9ahvgsP 64 | LfKl3rJ+aaX/Ok0AHzhvSfhFpPr1gAaGeaRt+rhlZsx2QyG4Ez8p2nDAcAzPiB3T 65 | 73ENoBIX6mTPfPm1UgrRyFKBqtUzAodz66j3r6ebBlWzIRg8iZenVMAxzjINAsxN 66 | w1Bzfgsi5ZespfsSlmEaa7jJkqqDuEcLa2YuiFAue7Euqwz1aGeq1GfTicQioSCb 67 | Ur/LGyz2Mj3ykbaP8p5mFVcUN51yQy6OcpvR/W1DfRT9SHFT/bCf9ixsjB2HlZGo 68 | uxPJowwqmMgHd755ZzPDUM9YDgLI1yXdcYshObv3Wq537JAxnZJCGRK4Y8SwrMSh 69 | 8WRxlaM0AGWXiJFIDD4bQPIdnF3X8w0cGWE5Otkb8mMHOT+rFTVlDODwm1zF6oIG 70 | PTwfVrpiZBwiUtfJol1exr/MzSPyGoJnYs3cRf2E3O+D1LbcR8w0LbjGuUy38Piz 71 | ZO/vCeyJ3JZC5kE8nD+XBA4idwzh0BKEfH9t+WchQ3Up9rxyzLyQamoqt5Xby4pY 72 | =xkM3 73 | -----END PGP PUBLIC KEY BLOCK----- 74 | ``` -------------------------------------------------------------------------------- /logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["setuptools>=61.0"] 3 | build-backend = "setuptools.build_meta" 4 | 5 | [project] 6 | name = "zksync2" 7 | version = "2.0.0" 8 | authors = [ 9 | { name="Matter Labs", email= "hello@matterlabs.io" }, 10 | ] 11 | description = "ZKsync python client sdk" 12 | readme = "README.md" 13 | requires-python = ">=3.8" 14 | classifiers = [ 15 | "Programming Language :: Python :: 3", 16 | "License :: OSI Approved :: MIT License", 17 | "Operating System :: OS Independent", 18 | ] 19 | 20 | dynamic = ["dependencies", "license", "optional-dependencies"] 21 | 22 | [project.urls] 23 | "Homepage" = "https://github.com/zksync-sdk/zksync2-python" 24 | "Bug Tracker" = "https://github.com/zksync-sdk/zksync2-python/issues" 25 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | web3>=7.3.0 2 | eth-tester 3 | black -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [metadata] 2 | name = zksync2 3 | description = ZKsync python client sdk 4 | long_description = file: README.md 5 | author = Danijel Radakovic 6 | url = https://zksync.io 7 | license = MIT 8 | 9 | [options] 10 | packages = find: 11 | install_requires = 12 | web3>=6.10.0 13 | 14 | python_requires = >=3.8 15 | setup_requires = 16 | setuptools_scm >= v7.0.5 17 | 18 | [options.extras_require] 19 | test = 20 | mypy >= 0.8 21 | 22 | [options.packages.find] 23 | include = 24 | zksync2 25 | zksync2.* 26 | 27 | [options.package_data] 28 | zksync2.manage_contracts.contract_abi = 29 | ContractDeployer.json 30 | IERC20.json 31 | IEthToken.json 32 | IL1Bridge.json 33 | IL2Bridge.json 34 | INonceHolder.json 35 | IPaymasterFlow.json 36 | IZkSync.json 37 | 38 | # [tox:tox] 39 | # envlist = py{38,39},mypy 40 | 41 | # [testenv:py{38,39}] 42 | # deps = coverage 43 | # setenv = ZK_SYNC_LIBRARY_PATH=/lib/zks-crypto-linux-x64.so 44 | # commands = coverage run -m unittest 45 | # 46 | # [testenv:mypy] 47 | # extras = test 48 | # commands = mypy . 49 | # 50 | # [mypy] 51 | # show_error_codes = True 52 | # no_implicit_optional = True 53 | # 54 | # [mypy-setuptools.*] 55 | # ignore_missing_imports = True 56 | # 57 | # [mypy-eth_account.*] 58 | # ignore_missing_imports = True 59 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | 3 | setup( 4 | use_scm_version=True, 5 | ) 6 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zksync-sdk/zksync2-python/a8118a7c1938a32c88ef2de3bea790b40278e26e/tests/__init__.py -------------------------------------------------------------------------------- /tests/contracts/Counter.json: -------------------------------------------------------------------------------- 1 | { 2 | "_format": "hh-zksolc-artifact-1", 3 | "contractName": "Counter", 4 | "sourceName": "contracts/counter/counter.sol", 5 | "abi": [ 6 | { 7 | "inputs": [], 8 | "name": "get", 9 | "outputs": [ 10 | { 11 | "internalType": "uint256", 12 | "name": "", 13 | "type": "uint256" 14 | } 15 | ], 16 | "stateMutability": "view", 17 | "type": "function" 18 | }, 19 | { 20 | "inputs": [ 21 | { 22 | "internalType": "uint256", 23 | "name": "x", 24 | "type": "uint256" 25 | } 26 | ], 27 | "name": "increment", 28 | "outputs": [], 29 | "stateMutability": "nonpayable", 30 | "type": "function" 31 | }, 32 | { 33 | "inputs": [ 34 | { 35 | "internalType": "uint256", 36 | "name": "x", 37 | "type": "uint256" 38 | }, 39 | { 40 | "internalType": "bool", 41 | "name": "shouldRevert", 42 | "type": "bool" 43 | } 44 | ], 45 | "name": "incrementWithRevert", 46 | "outputs": [], 47 | "stateMutability": "nonpayable", 48 | "type": "function" 49 | }, 50 | { 51 | "inputs": [ 52 | { 53 | "internalType": "uint256", 54 | "name": "x", 55 | "type": "uint256" 56 | } 57 | ], 58 | "name": "set", 59 | "outputs": [], 60 | "stateMutability": "nonpayable", 61 | "type": "function" 62 | } 63 | ], 64 | "bytecode": "0x000200000000000200010000000103550000006001100270000000340010019d0000008001000039000000400010043f00000001012001900000003f0000c13d0000000001000031000000040110008c0000008e0000413d0000000101000367000000000101043b000000e001100270000000360210009c000000620000613d000000370210009c000000490000613d000000380210009c0000007d0000613d000000390110009c0000008e0000c13d0000000001000416000000000110004c0000008e0000c13d000000040100008a00000000011000310000003a02000041000000400310008c000000000300001900000000030240190000003a01100197000000000410004c000000000200a0190000003a0110009c00000000010300190000000001026019000000000110004c0000008e0000c13d00000001010003670000002402100370000000000202043b000000000320004c0000000003000019000000010300c039000000000332004b0000008e0000c13d0000000401100370000000000301043b000000000100041a0000000001130019000000000331004b000000000300001900000001030040390000000103300190000000970000613d0000003d0100004100000000001004350000001101000039000000040010043f0000002402000039000000000100001900cc00b50000040f0000000001000416000000000110004c0000008e0000c13d00000020010000390000010000100443000001200000044300000100010000390000004002000039000000350300004100cc00ab0000040f0000000001000416000000000110004c0000008e0000c13d000000040100008a00000000011000310000003a02000041000000200310008c000000000300001900000000030240190000003a01100197000000000410004c000000000200a0190000003a0110009c00000000010300190000000001026019000000000110004c0000008e0000c13d00000004010000390000000101100367000000000101043b000000000010041b000000400100043d0000000002000019000000000300001900cc00ab0000040f0000000001000416000000000110004c0000008e0000c13d000000040100008a00000000011000310000003a02000041000000200310008c000000000300001900000000030240190000003a01100197000000000410004c000000000200a0190000003a0110009c00000000010300190000000001026019000000000110004c0000008e0000c13d00000004010000390000000101100367000000000201043b000000000100041a00cc00be0000040f000000000010041b000000400100043d0000000002000019000000000300001900cc00ab0000040f0000000001000416000000000110004c0000008e0000c13d000000040100008a00000000011000310000003a02000041000000000310004c000000000300001900000000030240190000003a01100197000000000410004c000000000200a0190000003a0110009c00000000010300190000000001026019000000000110004c000000910000613d0000000001000019000000000200001900cc00b50000040f000000400100043d000000000200041a00000000002104350000002002000039000000000300001900cc00ab0000040f000000000010041b000000400100043d000000000220004c0000009e0000c13d0000000002000019000000000300001900cc00ab0000040f00000044021000390000003b03000041000000000032043500000024021000390000001a0300003900000000003204350000003c020000410000000000210435000000040210003900000020030000390000000000320435000000640200003900cc00b50000040f0000003404000041000000340510009c000000000104801900000040011002100000000001310019000000340320009c000000000204801900000060022002100000000001210019000000cd0001042e0000003403000041000000340420009c0000000002038019000000340410009c000000000103801900000040011002100000006002200210000000000112019f000000ce000104300000000001120019000000000221004b000000000200001900000001020040390000000102200190000000c50000c13d000000000001042d0000003d0100004100000000001004350000001101000039000000040010043f0000002402000039000000000100001900cc00b50000040f000000cc00000432000000cd0001042e000000ce00010430000000000000000000000000000000000000000000000000000000000000000000000000ffffffff0000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007cf5dab00000000000000000000000000000000000000000000000000000000060fe47b1000000000000000000000000000000000000000000000000000000006d4ce63c000000000000000000000000000000000000000000000000000000000436dad6800000000000000000000000000000000000000000000000000000000000000054686973206d6574686f6420616c77617973207265766572747300000000000008c379a0000000000000000000000000000000000000000000000000000000004e487b71000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 65 | "deployedBytecode": "0x000200000000000200010000000103550000006001100270000000340010019d0000008001000039000000400010043f00000001012001900000003f0000c13d0000000001000031000000040110008c0000008e0000413d0000000101000367000000000101043b000000e001100270000000360210009c000000620000613d000000370210009c000000490000613d000000380210009c0000007d0000613d000000390110009c0000008e0000c13d0000000001000416000000000110004c0000008e0000c13d000000040100008a00000000011000310000003a02000041000000400310008c000000000300001900000000030240190000003a01100197000000000410004c000000000200a0190000003a0110009c00000000010300190000000001026019000000000110004c0000008e0000c13d00000001010003670000002402100370000000000202043b000000000320004c0000000003000019000000010300c039000000000332004b0000008e0000c13d0000000401100370000000000301043b000000000100041a0000000001130019000000000331004b000000000300001900000001030040390000000103300190000000970000613d0000003d0100004100000000001004350000001101000039000000040010043f0000002402000039000000000100001900cc00b50000040f0000000001000416000000000110004c0000008e0000c13d00000020010000390000010000100443000001200000044300000100010000390000004002000039000000350300004100cc00ab0000040f0000000001000416000000000110004c0000008e0000c13d000000040100008a00000000011000310000003a02000041000000200310008c000000000300001900000000030240190000003a01100197000000000410004c000000000200a0190000003a0110009c00000000010300190000000001026019000000000110004c0000008e0000c13d00000004010000390000000101100367000000000101043b000000000010041b000000400100043d0000000002000019000000000300001900cc00ab0000040f0000000001000416000000000110004c0000008e0000c13d000000040100008a00000000011000310000003a02000041000000200310008c000000000300001900000000030240190000003a01100197000000000410004c000000000200a0190000003a0110009c00000000010300190000000001026019000000000110004c0000008e0000c13d00000004010000390000000101100367000000000201043b000000000100041a00cc00be0000040f000000000010041b000000400100043d0000000002000019000000000300001900cc00ab0000040f0000000001000416000000000110004c0000008e0000c13d000000040100008a00000000011000310000003a02000041000000000310004c000000000300001900000000030240190000003a01100197000000000410004c000000000200a0190000003a0110009c00000000010300190000000001026019000000000110004c000000910000613d0000000001000019000000000200001900cc00b50000040f000000400100043d000000000200041a00000000002104350000002002000039000000000300001900cc00ab0000040f000000000010041b000000400100043d000000000220004c0000009e0000c13d0000000002000019000000000300001900cc00ab0000040f00000044021000390000003b03000041000000000032043500000024021000390000001a0300003900000000003204350000003c020000410000000000210435000000040210003900000020030000390000000000320435000000640200003900cc00b50000040f0000003404000041000000340510009c000000000104801900000040011002100000000001310019000000340320009c000000000204801900000060022002100000000001210019000000cd0001042e0000003403000041000000340420009c0000000002038019000000340410009c000000000103801900000040011002100000006002200210000000000112019f000000ce000104300000000001120019000000000221004b000000000200001900000001020040390000000102200190000000c50000c13d000000000001042d0000003d0100004100000000001004350000001101000039000000040010043f0000002402000039000000000100001900cc00b50000040f000000cc00000432000000cd0001042e000000ce00010430000000000000000000000000000000000000000000000000000000000000000000000000ffffffff0000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007cf5dab00000000000000000000000000000000000000000000000000000000060fe47b1000000000000000000000000000000000000000000000000000000006d4ce63c000000000000000000000000000000000000000000000000000000000436dad6800000000000000000000000000000000000000000000000000000000000000054686973206d6574686f6420616c77617973207265766572747300000000000008c379a0000000000000000000000000000000000000000000000000000000004e487b71000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 66 | "linkReferences": {}, 67 | "deployedLinkReferences": {}, 68 | "factoryDeps": {} 69 | } 70 | -------------------------------------------------------------------------------- /tests/contracts/Foo.json: -------------------------------------------------------------------------------- 1 | { 2 | "_format": "hh-zksolc-artifact-1", 3 | "contractName": "Foo", 4 | "sourceName": "contracts/create/Foo.sol", 5 | "abi": [ 6 | { 7 | "inputs": [], 8 | "name": "name", 9 | "outputs": [ 10 | { 11 | "internalType": "string", 12 | "name": "", 13 | "type": "string" 14 | } 15 | ], 16 | "stateMutability": "view", 17 | "type": "function" 18 | } 19 | ], 20 | "bytecode": "0x0001000000000002000100000000000200000000030100190000006003300270000000310030019d00000031033001970000000102200190000000400000c13d000000040230008c000000570000413d000000000101043b0000003401100197000000350110009c000000570000c13d0000000001000416000000000110004c000000570000c13d000000040100008a00000000011000310000003602000041000000000310004c000000000300001900000000030240190000003601100197000000000410004c000000000200a019000000360110009c00000000010300190000000001026019000000000110004c000000570000c13d000000000200041a000000010320019000000001012002700000007f0410018f00000000010460190000001f0410008c00000000040000190000000104002039000000000442013f0000000104400190000000500000c13d000000800010043f000000000330004c000000720000c13d000001000300008a000000000232016f000000a00020043f000000000110004c000000c004000039000000a0040060390000001f01400039000000200200008a000000000121016f0000003803100041000000390330009c0000007d0000813d0000003a0100004100000000001004350000004101000039000000040010043f0000002402000039000000000100001900be00b00000040f0000008001000039000000400010043f0000000001000416000000000110004c000000570000c13d000000000100041a000000010210019000000001011002700000007f0310018f000000000301c0190000001f0130008c00000000010000190000000101002039000000010110018f000000000112004b0000005a0000613d0000003a0100004100000000001004350000002201000039000000040010043f0000002402000039000000000100001900be00b00000040f0000000001000019000000000200001900be00b00000040f000000200130008c000000690000413d00000000000004350000000001000019000100000003001d00be00930000040f00000001020000290000001f0220003900000005022002700000000002210019000000000321004b000000690000813d000000000001041b0000000101100039000000640000013d0000003201000041000000000010041b00000020010000390000010000100443000001200000044300000100010000390000004002000039000000330300004100be00a60000040f000000370200004100000000000004350000000003000019000000a004300039000000000513004b000000330000813d000000000502041a000000000054043500000020033000390000000102200039000000750000013d000000400010043f000000200300003900000000003104350000002004100039000000800300043d000000000034043500000040041000390000000005000019000000000635004b0000008d0000813d0000000006450019000000a007500039000000000707043300000000007604350000002005500039000000850000013d000000000443001900000000000404350000005f03300039000000000223016f000000000300001900be00a60000040f00000031020000410000000003000414000000310430009c0000000003028019000000310410009c00000000010280190000004001100210000000c002300210000000000112019f0000003b011001c7000080100200003900be00b90000040f0000000102200190000000a30000613d000000000101043b000000000001042d0000000001000019000000000200001900be00b00000040f0000003104000041000000310510009c000000000104801900000040011002100000000001310019000000310320009c000000000204801900000060022002100000000001210019000000bf0001042e0000003103000041000000310420009c0000000002038019000000310410009c000000000103801900000040011002100000006002200210000000000112019f000000c000010430000000bc002104230000000102000039000000000001042d0000000002000019000000bb0000013d000000be00000432000000bf0001042e000000c00001043000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffff466f6f00000000000000000000000000000000000000000000000000000000060000000200000000000000000000000000000000000000000000000000000000ffffffff0000000000000000000000000000000000000000000000000000000006fdde03000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563ffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffffffffffffffffffffffffffffffffffff00000000000000804e487b710000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 21 | "deployedBytecode": "0x0001000000000002000100000000000200000000030100190000006003300270000000310030019d00000031033001970000000102200190000000400000c13d000000040230008c000000570000413d000000000101043b0000003401100197000000350110009c000000570000c13d0000000001000416000000000110004c000000570000c13d000000040100008a00000000011000310000003602000041000000000310004c000000000300001900000000030240190000003601100197000000000410004c000000000200a019000000360110009c00000000010300190000000001026019000000000110004c000000570000c13d000000000200041a000000010320019000000001012002700000007f0410018f00000000010460190000001f0410008c00000000040000190000000104002039000000000442013f0000000104400190000000500000c13d000000800010043f000000000330004c000000720000c13d000001000300008a000000000232016f000000a00020043f000000000110004c000000c004000039000000a0040060390000001f01400039000000200200008a000000000121016f0000003803100041000000390330009c0000007d0000813d0000003a0100004100000000001004350000004101000039000000040010043f0000002402000039000000000100001900be00b00000040f0000008001000039000000400010043f0000000001000416000000000110004c000000570000c13d000000000100041a000000010210019000000001011002700000007f0310018f000000000301c0190000001f0130008c00000000010000190000000101002039000000010110018f000000000112004b0000005a0000613d0000003a0100004100000000001004350000002201000039000000040010043f0000002402000039000000000100001900be00b00000040f0000000001000019000000000200001900be00b00000040f000000200130008c000000690000413d00000000000004350000000001000019000100000003001d00be00930000040f00000001020000290000001f0220003900000005022002700000000002210019000000000321004b000000690000813d000000000001041b0000000101100039000000640000013d0000003201000041000000000010041b00000020010000390000010000100443000001200000044300000100010000390000004002000039000000330300004100be00a60000040f000000370200004100000000000004350000000003000019000000a004300039000000000513004b000000330000813d000000000502041a000000000054043500000020033000390000000102200039000000750000013d000000400010043f000000200300003900000000003104350000002004100039000000800300043d000000000034043500000040041000390000000005000019000000000635004b0000008d0000813d0000000006450019000000a007500039000000000707043300000000007604350000002005500039000000850000013d000000000443001900000000000404350000005f03300039000000000223016f000000000300001900be00a60000040f00000031020000410000000003000414000000310430009c0000000003028019000000310410009c00000000010280190000004001100210000000c002300210000000000112019f0000003b011001c7000080100200003900be00b90000040f0000000102200190000000a30000613d000000000101043b000000000001042d0000000001000019000000000200001900be00b00000040f0000003104000041000000310510009c000000000104801900000040011002100000000001310019000000310320009c000000000204801900000060022002100000000001210019000000bf0001042e0000003103000041000000310420009c0000000002038019000000310410009c000000000103801900000040011002100000006002200210000000000112019f000000c000010430000000bc002104230000000102000039000000000001042d0000000002000019000000bb0000013d000000be00000432000000bf0001042e000000c00001043000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffff466f6f00000000000000000000000000000000000000000000000000000000060000000200000000000000000000000000000000000000000000000000000000ffffffff0000000000000000000000000000000000000000000000000000000006fdde03000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563ffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffffffffffffffffffffffffffffffffffff00000000000000804e487b710000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 22 | "linkReferences": {}, 23 | "deployedLinkReferences": {}, 24 | "factoryDeps": {} 25 | } 26 | -------------------------------------------------------------------------------- /tests/contracts/SimpleConstructor.json: -------------------------------------------------------------------------------- 1 | { 2 | "_format": "hh-zksolc-artifact-1", 3 | "contractName": "SimpleConstructor", 4 | "sourceName": "contracts/basic-constructor/basic-constructor.sol", 5 | "abi": [ 6 | { 7 | "inputs": [ 8 | { 9 | "internalType": "uint256", 10 | "name": "a", 11 | "type": "uint256" 12 | }, 13 | { 14 | "internalType": "uint256", 15 | "name": "b", 16 | "type": "uint256" 17 | }, 18 | { 19 | "internalType": "bool", 20 | "name": "shouldRevert", 21 | "type": "bool" 22 | } 23 | ], 24 | "stateMutability": "nonpayable", 25 | "type": "constructor" 26 | }, 27 | { 28 | "inputs": [], 29 | "name": "get", 30 | "outputs": [ 31 | { 32 | "internalType": "uint256", 33 | "name": "", 34 | "type": "uint256" 35 | } 36 | ], 37 | "stateMutability": "view", 38 | "type": "function" 39 | } 40 | ], 41 | "bytecode": "0x000200000000000200010000000103550000006001100270000000260010019d0000000101200190000000270000c13d0000008001000039000000400010043f0000000001000031000000040110008c000000790000413d0000000101000367000000000101043b0000002a011001970000002b0110009c000000790000c13d0000000001000416000000000110004c000000790000c13d000000040100008a00000000011000310000002702000041000000000310004c000000000300001900000000030240190000002701100197000000000410004c000000000200a019000000270110009c00000000010300190000000001026019000000000110004c000000790000c13d000000000100041a000000800010043f000000800100003900000020020000390000000003000019009100830000040f0000000001000416000000000110004c000000790000c13d00000000010000310000009f02100039000000200300008a000000000232016f0000007f0320008c000000370000213d000000280100004100000000001004350000004101000039000000040010043f00000024020000390000000001000019009100880000040f000000400020043f0000001f0210018f00000001030003670000000504100272000000450000613d00000000050000190000000506500210000000000763034f000000000707043b000000800660003900000000007604350000000105500039000000000645004b0000003d0000413d000000000520004c000000540000613d0000000504400210000000000343034f00000003022002100000008004400039000000000504043300000000052501cf000000000525022f000000000303043b0000010002200089000000000323022f00000000022301cf000000000252019f00000000002404350000002702000041000000600310008c000000000300001900000000030240190000002701100197000000000410004c000000000200a019000000270110009c00000000010300190000000001026019000000000110004c000000790000c13d000000c00100043d000000000210004c0000000002000019000000010200c039000000000221004b000000790000c13d000000a00200043d000000800300043d000000000430004c000000750000613d000000010400008a00000000543400d9000000000442004b000000750000a13d000000280100004100000000001004350000001101000039000000040010043f00000024020000390000000001000019009100880000040f00000000323200a9000000000020041b000000000110004c0000007c0000613d00000000010000190000000002000019009100880000040f000000200100003900000100001004430000012000000443000001000100003900000040020000390000002903000041009100830000040f0000004001100210000000600220021000000000011200190000000001310019000000920001042e0000002603000041000000260420009c0000000002038019000000260410009c000000000103801900000040011002100000006002200210000000000112019f00000093000104300000009100000432000000920001042e0000009300010430000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffff80000000000000000000000000000000000000000000000000000000000000004e487b71000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000ffffffff000000000000000000000000000000000000000000000000000000006d4ce63c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 42 | "deployedBytecode": "0x000200000000000200010000000103550000006001100270000000260010019d0000000101200190000000270000c13d0000008001000039000000400010043f0000000001000031000000040110008c000000790000413d0000000101000367000000000101043b0000002a011001970000002b0110009c000000790000c13d0000000001000416000000000110004c000000790000c13d000000040100008a00000000011000310000002702000041000000000310004c000000000300001900000000030240190000002701100197000000000410004c000000000200a019000000270110009c00000000010300190000000001026019000000000110004c000000790000c13d000000000100041a000000800010043f000000800100003900000020020000390000000003000019009100830000040f0000000001000416000000000110004c000000790000c13d00000000010000310000009f02100039000000200300008a000000000232016f0000007f0320008c000000370000213d000000280100004100000000001004350000004101000039000000040010043f00000024020000390000000001000019009100880000040f000000400020043f0000001f0210018f00000001030003670000000504100272000000450000613d00000000050000190000000506500210000000000763034f000000000707043b000000800660003900000000007604350000000105500039000000000645004b0000003d0000413d000000000520004c000000540000613d0000000504400210000000000343034f00000003022002100000008004400039000000000504043300000000052501cf000000000525022f000000000303043b0000010002200089000000000323022f00000000022301cf000000000252019f00000000002404350000002702000041000000600310008c000000000300001900000000030240190000002701100197000000000410004c000000000200a019000000270110009c00000000010300190000000001026019000000000110004c000000790000c13d000000c00100043d000000000210004c0000000002000019000000010200c039000000000221004b000000790000c13d000000a00200043d000000800300043d000000000430004c000000750000613d000000010400008a00000000543400d9000000000442004b000000750000a13d000000280100004100000000001004350000001101000039000000040010043f00000024020000390000000001000019009100880000040f00000000323200a9000000000020041b000000000110004c0000007c0000613d00000000010000190000000002000019009100880000040f000000200100003900000100001004430000012000000443000001000100003900000040020000390000002903000041009100830000040f0000004001100210000000600220021000000000011200190000000001310019000000920001042e0000002603000041000000260420009c0000000002038019000000260410009c000000000103801900000040011002100000006002200210000000000112019f00000093000104300000009100000432000000920001042e0000009300010430000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffff80000000000000000000000000000000000000000000000000000000000000004e487b71000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000ffffffff000000000000000000000000000000000000000000000000000000006d4ce63c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 43 | "linkReferences": {}, 44 | "deployedLinkReferences": {}, 45 | "factoryDeps": {} 46 | } 47 | -------------------------------------------------------------------------------- /tests/contracts/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zksync-sdk/zksync2-python/a8118a7c1938a32c88ef2de3bea790b40278e26e/tests/contracts/__init__.py -------------------------------------------------------------------------------- /tests/contracts/utils.py: -------------------------------------------------------------------------------- 1 | import importlib.resources as pkg_resources 2 | from tests import contracts 3 | 4 | 5 | def contract_path(contract_name: str): 6 | return pkg_resources.path(contracts, contract_name) 7 | -------------------------------------------------------------------------------- /tests/integration/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zksync-sdk/zksync2-python/a8118a7c1938a32c88ef2de3bea790b40278e26e/tests/integration/__init__.py -------------------------------------------------------------------------------- /tests/integration/test_config.py: -------------------------------------------------------------------------------- 1 | import os 2 | from dataclasses import dataclass 3 | from enum import IntEnum, auto 4 | from eth_typing import HexStr 5 | from eth_utils import remove_0x_prefix 6 | from web3 import Web3 7 | 8 | from tests.unit.test_config import TestEnvironment 9 | 10 | DAI_L1 = Web3.to_checksum_address("0x70a0F165d6f8054d0d0CF8dFd4DD2005f0AF6B55") 11 | approval_token = Web3.to_checksum_address("0x0183Fe07a98bc036d6eb23C3943d823bcD66a90F") 12 | paymaster_address = Web3.to_checksum_address( 13 | "0x594E77D36eB367b3AbAb98775c99eB383079F966" 14 | ) 15 | multisig_address = Web3.to_checksum_address( 16 | "0xe56070305f425AC6F19aa319fAe11BaD25cF19A9" 17 | ) 18 | address_1 = Web3.to_checksum_address("0x36615Cf349d7F6344891B1e7CA7C72883F5dc049") 19 | address_2 = Web3.to_checksum_address("0xa61464658AfeAf65CccaaFD3a512b69A83B77618") 20 | private_key_1 = "0x7726827caac94a7f9e1b160f7ea819f172f7b6f9d2a97f992c38edeab82d4110" 21 | private_key_2 = "0xac1e735be8536c6534bb4f17f06f6afc73b2b5ba84ac2cfb12f7461b20c0bbe3" 22 | 23 | 24 | class EnvPrivateKey: 25 | def __init__(self, env: str): 26 | env = "0x7726827caac94a7f9e1b160f7ea819f172f7b6f9d2a97f992c38edeab82d4110" 27 | if env is None: 28 | raise LookupError(f"Can't build key from {env}") 29 | self._key = bytes.fromhex(remove_0x_prefix(HexStr(env))) 30 | 31 | @property 32 | def key(self) -> bytes: 33 | return self._key 34 | 35 | 36 | class EnvURL: 37 | def __init__(self): 38 | env: bool = os.getenv("IS_ETH_CHAIN", False) 39 | if env: 40 | self._env = LOCAL_ETH_ENV 41 | else: 42 | self._env = LOCAL_NON_ETH_ENV 43 | 44 | @property 45 | def env(self) -> TestEnvironment: 46 | return self._env 47 | 48 | 49 | class EnvType(IntEnum): 50 | LOCAL_HOST = auto() 51 | TESTNET = auto() 52 | UNKNOWN = auto() 53 | 54 | 55 | @dataclass 56 | class TestEnvironment: 57 | type: EnvType 58 | zksync_server: str 59 | eth_server: str 60 | 61 | 62 | LOCAL_ETH_ENV = TestEnvironment( 63 | EnvType.LOCAL_HOST, "http://127.0.0.1:15100", "http://127.0.0.1:15045" 64 | ) 65 | LOCAL_NON_ETH_ENV = TestEnvironment( 66 | EnvType.LOCAL_HOST, "http://127.0.0.1:15200", "http://127.0.0.1:15045" 67 | ) 68 | -------------------------------------------------------------------------------- /tests/integration/test_contract_factory.py: -------------------------------------------------------------------------------- 1 | import os 2 | from pathlib import Path 3 | from unittest import TestCase 4 | 5 | from eth_account import Account 6 | from eth_account.signers.local import LocalAccount 7 | from eth_typing import HexStr 8 | 9 | from tests.integration.test_config import EnvURL, private_key_1 10 | from zksync2.core.types import EthBlockParams 11 | from zksync2.manage_contracts.contract_factory import ( 12 | LegacyContractFactory, 13 | DeploymentType, 14 | ) 15 | from zksync2.module.module_builder import ZkSyncBuilder 16 | from zksync2.signer.eth_signer import PrivateKeyEthSigner 17 | 18 | 19 | def generate_random_salt() -> bytes: 20 | return os.urandom(32) 21 | 22 | 23 | class ContractFactoryTest(TestCase): 24 | 25 | def setUp(self) -> None: 26 | self.env = EnvURL() 27 | self.provider = ZkSyncBuilder.build(self.env.env.zksync_server) 28 | self.account: LocalAccount = Account.from_key(private_key_1) 29 | self.chain_id = self.provider.zksync.chain_id 30 | self.signer = PrivateKeyEthSigner(self.account, self.chain_id) 31 | self.counter_address = None 32 | self.test_tx_hash = None 33 | self.some_erc20_address = None 34 | 35 | def test_contract_factory_create(self): 36 | directory = Path(__file__).parent 37 | path = directory / Path("../contracts/Counter.json") 38 | deployer = LegacyContractFactory.from_json( 39 | zksync=self.provider, 40 | compiled_contract=path.resolve(), 41 | account=self.account, 42 | signer=self.signer, 43 | ) 44 | contract = deployer.deploy() 45 | self.assertIsNotNone(self.provider.zksync.get_code(contract.address)) 46 | 47 | def test_contract_factory_crete2(self): 48 | salt = generate_random_salt() 49 | directory = Path(__file__).parent 50 | path = directory / Path("../contracts/Counter.json") 51 | deployer = LegacyContractFactory.from_json( 52 | zksync=self.provider, 53 | compiled_contract=path.resolve(), 54 | account=self.account, 55 | signer=self.signer, 56 | deployment_type=DeploymentType.CREATE2, 57 | ) 58 | contract = deployer.deploy(salt=salt) 59 | self.assertIsNotNone(self.provider.zksync.get_code(contract.address)) 60 | 61 | def test_contract_factory_crete2_with_args(self): 62 | salt = generate_random_salt() 63 | directory = Path(__file__).parent 64 | path = directory / Path("../contracts/Token.json") 65 | 66 | constructor_arguments = {"name_": "Ducat", "symbol_": "Ducat", "decimals_": 18} 67 | deployer = LegacyContractFactory.from_json( 68 | zksync=self.provider, 69 | compiled_contract=path.resolve(), 70 | account=self.account, 71 | signer=self.signer, 72 | deployment_type=DeploymentType.CREATE2, 73 | ) 74 | contract = deployer.deploy(salt=salt, **constructor_arguments) 75 | self.assertIsNotNone(self.provider.zksync.get_code(contract.address)) 76 | 77 | def test_deploy_paymaster(self): 78 | salt = generate_random_salt() 79 | directory = Path(__file__).parent 80 | path = directory / "../contracts/Paymaster.json" 81 | token_address = self.provider.to_checksum_address( 82 | "0x0183Fe07a98bc036d6eb23C3943d823bcD66a90F" 83 | ) 84 | constructor_arguments = {"_erc20": token_address} 85 | 86 | deployer = LegacyContractFactory.from_json( 87 | zksync=self.provider, 88 | compiled_contract=path.resolve(), 89 | account=self.account, 90 | signer=self.signer, 91 | deployment_type=DeploymentType.CREATE2_ACCOUNT, 92 | ) 93 | contract = deployer.deploy(salt=salt, **constructor_arguments) 94 | self.assertIsNotNone(self.provider.zksync.get_code(contract.address)) 95 | -------------------------------------------------------------------------------- /tests/integration/test_zksync_contract.py: -------------------------------------------------------------------------------- 1 | import os 2 | from unittest import TestCase 3 | 4 | from eth_account import Account 5 | from eth_account.signers.local import LocalAccount 6 | from web3 import Web3 7 | 8 | from tests.integration.test_config import private_key_1 9 | from tests.integration.test_config import EnvURL 10 | from zksync2.core.utils import RecommendedGasLimit 11 | from zksync2.manage_contracts.utils import get_zksync_hyperchain 12 | from zksync2.module.module_builder import ZkSyncBuilder 13 | from zksync2.signer.eth_signer import PrivateKeyEthSigner 14 | 15 | 16 | def generate_random_salt() -> bytes: 17 | return os.urandom(32) 18 | 19 | 20 | class ZkSyncWeb3Tests(TestCase): 21 | def setUp(self) -> None: 22 | env = EnvURL() 23 | self.zksync = ZkSyncBuilder.build(env.env.zksync_server) 24 | self.eth_web3 = Web3(Web3.HTTPProvider(env.env.eth_server)) 25 | self.account: LocalAccount = Account.from_key(private_key_1) 26 | self.chain_id = self.zksync.zksync.chain_id 27 | self.signer = PrivateKeyEthSigner(self.account, self.chain_id) 28 | self.zksync_contract = self.eth_web3.eth.contract( 29 | Web3.to_checksum_address(self.zksync.zksync.zks_main_contract()), 30 | abi=get_zksync_hyperchain(), 31 | ) 32 | 33 | def test_facet_addresses_call(self): 34 | facets = self.zksync_contract.functions.facets().call( 35 | { 36 | "chainId": self.eth_web3.eth.chain_id, 37 | "from": self.account.address, 38 | "nonce": self.eth_web3.eth.get_transaction_count(self.account.address), 39 | } 40 | ) 41 | 42 | def test_get_first_unprocessed_priority_tx(self): 43 | tx = self.zksync_contract.functions.getFirstUnprocessedPriorityTx().call( 44 | { 45 | "chainId": self.eth_web3.eth.chain_id, 46 | "from": self.account.address, 47 | "nonce": self.eth_web3.eth.get_transaction_count(self.account.address), 48 | } 49 | ) 50 | 51 | def test_get_l2_bootloader_bytecode_hash(self): 52 | bytecode_hash = ( 53 | self.zksync_contract.functions.getL2BootloaderBytecodeHash().call( 54 | { 55 | "chainId": self.eth_web3.eth.chain_id, 56 | "from": self.account.address, 57 | "nonce": self.eth_web3.eth.get_transaction_count( 58 | self.account.address 59 | ), 60 | } 61 | ) 62 | ) 63 | 64 | def test_get_l2_default_account_bytecode_hash(self): 65 | bytecode_hash = ( 66 | self.zksync_contract.functions.getL2DefaultAccountBytecodeHash().call( 67 | { 68 | "chainId": self.eth_web3.eth.chain_id, 69 | "from": self.account.address, 70 | "nonce": self.eth_web3.eth.get_transaction_count( 71 | self.account.address 72 | ), 73 | } 74 | ) 75 | ) 76 | 77 | def test_get_proposed_upgrade_timestamp(self): 78 | upgrade_timestamp = self.zksync_contract.functions.getPriorityQueueSize().call( 79 | { 80 | "chainId": self.eth_web3.eth.chain_id, 81 | "from": self.account.address, 82 | "nonce": self.eth_web3.eth.get_transaction_count(self.account.address), 83 | } 84 | ) 85 | 86 | def test_get_total_blocks_committed(self): 87 | total = self.zksync_contract.functions.getProtocolVersion().call( 88 | { 89 | "chainId": self.eth_web3.eth.chain_id, 90 | "from": self.account.address, 91 | "nonce": self.eth_web3.eth.get_transaction_count(self.account.address), 92 | } 93 | ) 94 | 95 | def test_get_total_blocks_executed(self): 96 | total = self.zksync_contract.functions.getTotalBatchesCommitted().call( 97 | { 98 | "chainId": self.eth_web3.eth.chain_id, 99 | "from": self.account.address, 100 | "nonce": self.eth_web3.eth.get_transaction_count(self.account.address), 101 | } 102 | ) 103 | 104 | def test_get_total_blocks_verified(self): 105 | total = self.zksync_contract.functions.getTotalBatchesExecuted().call( 106 | { 107 | "chainId": self.eth_web3.eth.chain_id, 108 | "from": self.account.address, 109 | "nonce": self.eth_web3.eth.get_transaction_count(self.account.address), 110 | } 111 | ) 112 | 113 | def test_get_total_priority_txs(self): 114 | priority = self.zksync_contract.functions.getTotalBatchesVerified().call( 115 | { 116 | "chainId": self.eth_web3.eth.chain_id, 117 | "from": self.account.address, 118 | "nonce": self.eth_web3.eth.get_transaction_count(self.account.address), 119 | } 120 | ) 121 | 122 | def test_is_diamond_storage_frozen(self): 123 | v = self.zksync_contract.functions.isDiamondStorageFrozen().call( 124 | { 125 | "chainId": self.eth_web3.eth.chain_id, 126 | "from": self.account.address, 127 | "nonce": self.eth_web3.eth.get_transaction_count(self.account.address), 128 | } 129 | ) 130 | 131 | def test_get_verifier(self): 132 | verifier = self.zksync_contract.functions.getVerifier().call( 133 | { 134 | "chainId": self.eth_web3.eth.chain_id, 135 | "from": self.account.address, 136 | "nonce": self.eth_web3.eth.get_transaction_count(self.account.address), 137 | } 138 | ) 139 | 140 | def test_get_verifier_params(self): 141 | verifier_params = ret = self.zksync_contract.functions.getVerifierParams().call( 142 | { 143 | "chainId": self.eth_web3.eth.chain_id, 144 | "from": self.account.address, 145 | "nonce": self.eth_web3.eth.get_transaction_count(self.account.address), 146 | } 147 | ) 148 | 149 | def test_request_l2_transaction(self): 150 | RECOMMENDED_DEPOSIT_L2_GAS_LIMIT = 10000000 151 | DEPOSIT_GAS_PER_PUBDATA_LIMIT = 50000 152 | gas_price = self.eth_web3.eth.gas_price 153 | gas_limit = RecommendedGasLimit.EXECUTE.value 154 | l2_value = 0 155 | contract = self.eth_web3.eth.contract( 156 | Web3.to_checksum_address(self.zksync.zksync.zks_main_contract()), 157 | abi=get_zksync_hyperchain(), 158 | ) 159 | tx = contract.functions.requestL2Transaction( 160 | Web3.to_checksum_address(self.zksync.zksync.zks_main_contract()), 161 | l2_value, 162 | b"", 163 | RECOMMENDED_DEPOSIT_L2_GAS_LIMIT, 164 | DEPOSIT_GAS_PER_PUBDATA_LIMIT, 165 | [], 166 | Web3.to_checksum_address(self.zksync.zksync.zks_main_contract()), 167 | ).build_transaction( 168 | { 169 | "nonce": self.eth_web3.eth.get_transaction_count(self.account.address), 170 | "from": self.account.address, 171 | "gasPrice": gas_price, 172 | "gas": gas_limit, 173 | "value": 0, 174 | } 175 | ) 176 | signed_tx = self.account.sign_transaction(tx) 177 | tx_hash = self.eth_web3.eth.send_raw_transaction(signed_tx.raw_transaction) 178 | tx_receipt = self.eth_web3.eth.wait_for_transaction_receipt(tx_hash) 179 | -------------------------------------------------------------------------------- /tests/integration/token.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "DAI", 4 | "symbol": "DAI", 5 | "decimals": 18, 6 | "address": "0x70a0F165d6f8054d0d0CF8dFd4DD2005f0AF6B55" 7 | }, 8 | { 9 | "name": "wBTC", 10 | "symbol": "wBTC", 11 | "decimals": 8, 12 | "address": "0x1C552d7B40b38Fb1235697Bed7b8e1e47B46e5BA" 13 | }, 14 | { 15 | "name": "BAT", 16 | "symbol": "BAT", 17 | "decimals": 18, 18 | "address": "0xdF2Ff03eAAfae59fA7fd30D4f91ab045B3d5D95D" 19 | }, 20 | { 21 | "name": "GNT", 22 | "symbol": "GNT", 23 | "decimals": 18, 24 | "address": "0xeF81A0BB8819F94EEf15992F31555a282d7009d1" 25 | }, 26 | { 27 | "name": "MLTT", 28 | "symbol": "MLTT", 29 | "decimals": 18, 30 | "address": "0x9ad574a765F65Ec554780c2b5D97979Ed1957d30" 31 | }, 32 | { 33 | "name": "DAIK", 34 | "symbol": "DAIK", 35 | "decimals": 18, 36 | "address": "0x266B465D9D37cF6001d38b8e3f839fAE0e10D619" 37 | }, 38 | { 39 | "name": "wBTCK", 40 | "symbol": "wBTCK", 41 | "decimals": 8, 42 | "address": "0x05789138d7838a4707FFB45EA5B2c498B1e8Be3c" 43 | }, 44 | { 45 | "name": "BATK", 46 | "symbol": "BATS", 47 | "decimals": 18, 48 | "address": "0xfeC8FE20C644fab5d37B86E821A29F1abfEdFc55" 49 | }, 50 | { 51 | "name": "GNTK", 52 | "symbol": "GNTS", 53 | "decimals": 18, 54 | "address": "0xde617bf595d8090c63350CA3916b13FBD79f0E0a" 55 | }, 56 | { 57 | "name": "MLTTK", 58 | "symbol": "MLTTS", 59 | "decimals": 18, 60 | "address": "0x0B827231D3ECE7906361723170701941f5813191" 61 | }, 62 | { 63 | "name": "DAIL", 64 | "symbol": "DAIL", 65 | "decimals": 18, 66 | "address": "0x4EDe5c04d0eF5aDDD222cc7D3C4cbE23Ac7fD4F4" 67 | }, 68 | { 69 | "name": "wBTCL", 70 | "symbol": "wBTCP", 71 | "decimals": 8, 72 | "address": "0x2E694B999D7746Dcf3864E9C2F47a4daEBD65721" 73 | }, 74 | { 75 | "name": "BATL", 76 | "symbol": "BATW", 77 | "decimals": 18, 78 | "address": "0x0a1D1D084645a46E9E019da345684308701855b6" 79 | }, 80 | { 81 | "name": "GNTL", 82 | "symbol": "GNTW", 83 | "decimals": 18, 84 | "address": "0x1630bcE01eb41A9Fd5d49a14e5c6D52b1B127d17" 85 | }, 86 | { 87 | "name": "MLTTL", 88 | "symbol": "MLTTW", 89 | "decimals": 18, 90 | "address": "0xa60bc9ae6a6967CAC6D8b08e12a2EF087348Cd32" 91 | }, 92 | { 93 | "name": "Wrapped Ether", 94 | "symbol": "WETH", 95 | "decimals": 18, 96 | "address": "0x4A470422bFf67C34a3A565106118023059fa4E34" 97 | } 98 | ] -------------------------------------------------------------------------------- /tests/unit/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zksync-sdk/zksync2-python/a8118a7c1938a32c88ef2de3bea790b40278e26e/tests/unit/__init__.py -------------------------------------------------------------------------------- /tests/unit/test_config.py: -------------------------------------------------------------------------------- 1 | import os 2 | from dataclasses import dataclass 3 | from enum import IntEnum, auto 4 | from eth_typing import HexStr 5 | from eth_utils import remove_0x_prefix 6 | 7 | 8 | class EnvPrivateKey: 9 | def __init__(self, env: str): 10 | env = os.getenv(env, None) 11 | if env is None: 12 | raise LookupError(f"Can't build key from {env}") 13 | self._key = bytes.fromhex(remove_0x_prefix(HexStr(env))) 14 | 15 | @property 16 | def key(self) -> bytes: 17 | return self._key 18 | 19 | 20 | class EnvType(IntEnum): 21 | LOCAL_HOST = auto() 22 | TESTNET = auto() 23 | UNKNOWN = auto() 24 | 25 | 26 | @dataclass 27 | class TestEnvironment: 28 | type: EnvType 29 | zksync_server: str 30 | eth_server: str 31 | 32 | 33 | LOCAL_ENV = TestEnvironment( 34 | EnvType.LOCAL_HOST, "http://127.0.0.1:15100", "http://127.0.0.1:15045" 35 | ) 36 | -------------------------------------------------------------------------------- /tests/unit/test_contract_deploy.py: -------------------------------------------------------------------------------- 1 | from pathlib import Path 2 | from unittest import TestCase 3 | from eth_typing import HexStr 4 | from eth_utils import add_0x_prefix 5 | from web3 import Web3 6 | from web3.types import Nonce 7 | from .test_config import LOCAL_ENV 8 | from zksync2.core.utils import hash_byte_code 9 | from tests.contracts.utils import contract_path 10 | from zksync2.manage_contracts.precompute_contract_deployer import ( 11 | PrecomputeContractDeployer, 12 | ) 13 | from zksync2.manage_contracts.contract_encoder_base import ( 14 | ContractEncoder, 15 | JsonConfiguration, 16 | ) 17 | from zksync2.module.module_builder import ZkSyncBuilder 18 | 19 | 20 | class ContractDeployerTests(TestCase): 21 | def setUp(self) -> None: 22 | env = LOCAL_ENV 23 | self.web3 = ZkSyncBuilder.build(env.zksync_server) 24 | self.contract_deployer = PrecomputeContractDeployer(self.web3) 25 | directory = Path(__file__).parent 26 | path = directory / Path("../contracts/Counter.json") 27 | counter_contract = ContractEncoder.from_json( 28 | self.web3, path.resolve(), JsonConfiguration.STANDARD 29 | ) 30 | self.counter_contract_bin = counter_contract.bytecode 31 | 32 | def test_compute_l2_create2(self): 33 | expected = Web3.to_checksum_address( 34 | "0xf7671F9178dF17CF2F94a51d5a97bF54f6dff25a" 35 | ) 36 | sender = HexStr("0xa909312acfc0ed4370b8bd20dfe41c8ff6595194") 37 | salt = b"\0" * 32 38 | addr = self.contract_deployer.compute_l2_create2_address( 39 | sender, self.counter_contract_bin, b"", salt 40 | ) 41 | self.assertEqual(expected, addr) 42 | 43 | def test_compute_l2_create(self): 44 | expected = Web3.to_checksum_address( 45 | "0x5107b7154dfc1d3b7f1c4e19b5087e1d3393bcf4" 46 | ) 47 | sender = HexStr("0x7e5f4552091a69125d5dfcb7b8c2659029395bdf") 48 | addr = self.contract_deployer.compute_l2_create_address(sender, Nonce(3)) 49 | self.assertEqual(expected, addr) 50 | 51 | def test_hash_byte_code(self): 52 | expected = "0x0100003fcee62dec356138ff4ab621cb9ed313c17e98a4ec349b3e8e1642d588" 53 | hash_bytes = hash_byte_code(self.counter_contract_bin) 54 | result = add_0x_prefix(HexStr(hash_bytes.hex())) 55 | self.assertEqual(result, expected) 56 | -------------------------------------------------------------------------------- /tests/unit/test_eip712.py: -------------------------------------------------------------------------------- 1 | import json 2 | from unittest import TestCase, skip 3 | 4 | from eth_account.messages import encode_typed_data 5 | from eth_utils.crypto import keccak_256 6 | from zksync2.eip712 import EIP712Struct, String, Address, make_domain 7 | from zksync2.core.utils import pad_front_bytes 8 | 9 | 10 | class Person(EIP712Struct): 11 | name = String() 12 | wallet = Address() 13 | 14 | 15 | class Mail(EIP712Struct): 16 | pass 17 | 18 | 19 | def make_mail(from_, to, content) -> Mail: 20 | setattr(Mail, "from", Person) 21 | setattr(Mail, "to", Person) 22 | setattr(Mail, "contents", String()) 23 | 24 | kwargs = {"to": to, "from": from_, "contents": content} 25 | return Mail(**kwargs) 26 | 27 | 28 | class EIP712Tests(TestCase): 29 | def setUp(self) -> None: 30 | self.person_from = Person( 31 | name="Cow", wallet="0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826" 32 | ) 33 | self.person_to = Person( 34 | name="Bob", wallet="0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB" 35 | ) 36 | self.mail = make_mail( 37 | from_=self.person_from, to=self.person_to, content="Hello, Bob!" 38 | ) 39 | self.domain = make_domain( 40 | name="Ether Mail", 41 | version="1", 42 | chainId=1, 43 | verifyingContract="0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC", 44 | ) 45 | 46 | def test_encode_type(self): 47 | result = self.mail.encode_type() 48 | self.assertEqual( 49 | "Mail(Person from,Person to,string contents)Person(string name,address wallet)", 50 | result, 51 | ) 52 | 53 | def test_hash_encoded_type(self): 54 | result = self.mail.type_hash() 55 | self.assertEqual( 56 | "a0cedeb2dc280ba39b857546d74f5549c3a1d7bdc2dd96bf881f76108e23dac2", 57 | result.hex(), 58 | ) 59 | 60 | @skip 61 | def test_encode_person(self): 62 | from_str = self.mail.get_data_value("from").to_message_json(self.domain) 63 | value = json.loads(from_str) 64 | ret = encode_typed_data(value) 65 | self.assertEqual( 66 | "fc71e5fa27ff56c350aa531bc129ebdf613b772b6604664f5d8dbe21b85eb0c8", 67 | ret.body.hex(), 68 | ) 69 | 70 | to_str = self.mail.get_data_value("to").to_message_json(self.domain) 71 | value = json.loads(to_str) 72 | ret = encode_typed_data(value) 73 | self.assertEqual( 74 | "cd54f074a4af31b4411ff6a60c9719dbd559c221c8ac3492d9d872b041d703d1", 75 | ret.body.hex(), 76 | ) 77 | 78 | @skip 79 | def test_encode_mail_data(self): 80 | struct_message_json = self.mail.to_message_json(self.domain) 81 | value = json.loads(struct_message_json) 82 | ret = encode_typed_data(value) 83 | self.assertEqual( 84 | "c52c0ee5d84264471806290a3f2c4cecfc5490626bf912d01f240d7a274b371e", 85 | ret.body.hex(), 86 | ) 87 | 88 | def test_singed_bytes(self): 89 | result_bytes = self.mail.signable_bytes(self.domain) 90 | ret = keccak_256(result_bytes) 91 | self.assertEqual( 92 | "be609aee343fb3c4b28e1df9e632fca64fcfaede20f02e86244efddf30957bd2", 93 | ret.hex(), 94 | ) 95 | 96 | def test_encode_content(self): 97 | val = self.mail.get_data_value("contents") 98 | ret = keccak_256(val.encode()) 99 | self.assertEqual( 100 | "b5aadf3154a261abdd9086fc627b61efca26ae5702701d05cd2305f7c52a2fc8", 101 | ret.hex(), 102 | ) 103 | 104 | def test_encode_domain(self): 105 | type_hash = self.domain.type_hash() 106 | ret = self.domain.encode_value() 107 | ret = type_hash + ret 108 | ret = keccak_256(ret) 109 | self.assertEqual( 110 | "f2cee375fa42b42143804025fc449deafd50cc031ca257e0b194a650a912090f", 111 | ret.hex(), 112 | ) 113 | 114 | def test_encode_domain_members(self): 115 | name = self.domain.get_data_value("name") 116 | name_hash = keccak_256(name.encode()) 117 | self.assertEqual( 118 | "c70ef06638535b4881fafcac8287e210e3769ff1a8e91f1b95d6246e61e4d3c6", 119 | name_hash.hex(), 120 | ) 121 | 122 | version = self.domain.get_data_value("version") 123 | version_hash = keccak_256(version.encode()) 124 | self.assertEqual( 125 | "c89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6", 126 | version_hash.hex(), 127 | ) 128 | 129 | chain_id = self.domain.get_data_value("chainId") 130 | chain_id_padded = pad_front_bytes(chain_id.to_bytes(2, "big"), 32) 131 | self.assertEqual( 132 | "0000000000000000000000000000000000000000000000000000000000000001", 133 | chain_id_padded.hex(), 134 | ) 135 | 136 | verified_contract = self.domain.get_data_value("verifyingContract") 137 | verified_contract = verified_contract[2:] 138 | verified_contract_hash = b"\0" * 12 + bytes.fromhex(verified_contract) 139 | 140 | self.assertEqual( 141 | "000000000000000000000000cccccccccccccccccccccccccccccccccccccccc", 142 | verified_contract_hash.hex(), 143 | ) 144 | -------------------------------------------------------------------------------- /tests/unit/test_eth_signer.py: -------------------------------------------------------------------------------- 1 | from unittest import TestCase 2 | from eth_typing import HexStr 3 | from eth_utils import add_0x_prefix 4 | 5 | from zksync2.signer.eth_signer import PrivateKeyEthSigner 6 | from eth_account.signers.local import LocalAccount 7 | from eth_account import Account 8 | from zksync2.eip712 import make_domain, EIP712Struct, String, Address 9 | from eth_utils.crypto import keccak_256 10 | 11 | 12 | class Person(EIP712Struct): 13 | name = String() 14 | wallet = Address() 15 | 16 | 17 | class Mail(EIP712Struct): 18 | pass 19 | 20 | 21 | def make_mail(from_, to, content) -> Mail: 22 | setattr(Mail, "from", Person) 23 | setattr(Mail, "to", Person) 24 | setattr(Mail, "contents", String()) 25 | 26 | kwargs = {"to": to, "from": from_, "contents": content} 27 | return Mail(**kwargs) 28 | 29 | 30 | class EthSignerTests(TestCase): 31 | _TEST_TYPED_EXPECTED_SIGNATURE = HexStr( 32 | "0x4355c47d63924e8a72e509b65029052eb6c299d53a04e167c5775fd466751" 33 | "c9d07299936d304c153f6443dfa05f40ff007d72911b6f72307f996231605b915621c" 34 | ) 35 | 36 | def setUp(self) -> None: 37 | self.domain = make_domain( 38 | name="Ether Mail", 39 | version="1", 40 | chainId=1, 41 | verifyingContract="0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC", 42 | ) 43 | self.person_from = Person( 44 | name="Cow", wallet="0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826" 45 | ) 46 | self.person_to = Person( 47 | name="Bob", wallet="0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB" 48 | ) 49 | self.mail = make_mail( 50 | from_=self.person_from, to=self.person_to, content="Hello, Bob!" 51 | ) 52 | 53 | private_key = keccak_256("cow".encode("utf-8")) 54 | self.account: LocalAccount = Account.from_key(private_key) 55 | self.signer = PrivateKeyEthSigner(self.account, 1) 56 | 57 | def test_sign_typed_data(self): 58 | sm = self.signer.sign_typed_data(self.mail, self.domain) 59 | self.assertEqual( 60 | self._TEST_TYPED_EXPECTED_SIGNATURE, add_0x_prefix(sm.signature.hex()) 61 | ) 62 | 63 | def test_verify_signed_typed_data(self): 64 | ret = self.signer.verify_typed_data( 65 | self._TEST_TYPED_EXPECTED_SIGNATURE, self.mail, self.domain 66 | ) 67 | self.assertTrue(ret) 68 | -------------------------------------------------------------------------------- /tests/unit/test_transaction712.py: -------------------------------------------------------------------------------- 1 | from pathlib import Path 2 | from unittest import TestCase 3 | 4 | from zksync2.eip712 import make_domain 5 | from eth_account import Account 6 | from eth_account.signers.local import LocalAccount 7 | from eth_typing import HexStr 8 | from eth_utils.crypto import keccak 9 | from web3 import Web3 10 | from web3.types import Nonce 11 | 12 | from tests.contracts.utils import contract_path 13 | from .test_config import LOCAL_ENV 14 | from zksync2.manage_contracts.contract_encoder_base import ( 15 | ContractEncoder, 16 | JsonConfiguration, 17 | ) 18 | from zksync2.module.request_types import EIP712Meta 19 | from zksync2.transaction.transaction712 import Transaction712 20 | from zksync2.transaction.transaction_builders import TxCreateContract 21 | 22 | PRIVATE_KEY2 = bytes.fromhex( 23 | "fd1f96220fa3a40c46d65f81d61dd90af600746fd47e5c82673da937a48b38ef" 24 | ) 25 | 26 | 27 | class Transaction712Tests(TestCase): 28 | NONCE = Nonce(42) 29 | CHAIN_ID = 42 30 | GAS_LIMIT = 54321 31 | SENDER = HexStr("0x1234512345123451234512345123451234512345") 32 | RECEIVER = HexStr("0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC") 33 | 34 | TRANSACTION_SIGNATURE = ( 35 | "Transaction(uint256 txType,uint256 from,uint256 to,uint256 gasLimit,uint256 " 36 | "gasPerPubdataByteLimit,uint256 maxFeePerGas,uint256 maxPriorityFeePerGas," 37 | "uint256 paymaster,uint256 nonce,uint256 value,bytes data,bytes32[] factoryDeps," 38 | "bytes paymasterInput)" 39 | ) 40 | 41 | EXPECTED_ENCODED_VALUE = ( 42 | "0x1e40bcee418db11047ffefb27b304f8ec1b5d644c35c56878f5cc12988b3162d" 43 | ) 44 | EXPECTED_ENCODED_BYTES = ( 45 | "0x7519adb6e67031ee048d921120687e4fbdf83961bcf43756f349d689eed2b80c" 46 | ) 47 | 48 | def setUp(self) -> None: 49 | # self.web3 = Web3(EthereumTesterProvider(PyEVMBackend())) 50 | self.env = LOCAL_ENV 51 | self.web3 = Web3(Web3.HTTPProvider(self.env.eth_server)) 52 | self.account: LocalAccount = Account.from_key(PRIVATE_KEY2) 53 | directory = Path(__file__).parent 54 | path = directory / Path("../contracts/Counter.json") 55 | self.counter_contract_encoder = ContractEncoder.from_json( 56 | self.web3, path.resolve(), JsonConfiguration.STANDARD 57 | ) 58 | self.tx712 = Transaction712( 59 | chain_id=self.CHAIN_ID, 60 | nonce=self.NONCE, 61 | gas_limit=self.GAS_LIMIT, 62 | to=self.RECEIVER, 63 | value=0, 64 | data=self.counter_contract_encoder.encode_method( 65 | fn_name="increment", args=[42] 66 | ), 67 | maxPriorityFeePerGas=0, 68 | maxFeePerGas=0, 69 | from_=self.SENDER, 70 | meta=EIP712Meta(0), 71 | ) 72 | 73 | def test_deploy_contract_tx712(self): 74 | tx = TxCreateContract( 75 | web3=self.web3, 76 | chain_id=280, 77 | nonce=0, 78 | from_=self.account.address.lower(), 79 | gas_limit=0, # UNKNOWN AT THIS STATE 80 | gas_price=250000000, 81 | bytecode=self.counter_contract_encoder.bytecode, 82 | ) 83 | tx_712 = tx.tx712(9910372) 84 | msg = tx_712.to_eip712_struct().hash_struct() 85 | self.assertEqual( 86 | "b65d7e33b4d31aa931d044aff74ad6780374acd5bcbd192b1b0210c40664ccb2", 87 | msg.hex(), 88 | ) 89 | 90 | def test_encode_to_eip712_type_string(self): 91 | eip712_struct = self.tx712.to_eip712_struct() 92 | ret = eip712_struct.encode_type() 93 | self.assertEqual(self.TRANSACTION_SIGNATURE, ret) 94 | 95 | def test_serialize_to_eip712_encoded_value(self): 96 | eip712_struct = self.tx712.to_eip712_struct() 97 | encoded_value = eip712_struct.hash_struct() 98 | result = "0x" + encoded_value.hex() 99 | self.assertEqual(self.EXPECTED_ENCODED_VALUE, result) 100 | 101 | def test_serialize_to_eip712_message(self): 102 | domain = make_domain(name="zkSync", version="2", chainId=self.CHAIN_ID) 103 | eip712_struct = self.tx712.to_eip712_struct() 104 | 105 | result_bytes = eip712_struct.signable_bytes(domain) 106 | msg = keccak(result_bytes) 107 | result = "0x" + msg.hex() 108 | self.assertEqual(self.EXPECTED_ENCODED_BYTES, result) 109 | -------------------------------------------------------------------------------- /tests/unit/test_utils.py: -------------------------------------------------------------------------------- 1 | from unittest import TestCase 2 | 3 | from eth_typing import HexStr 4 | 5 | from tests.integration.test_config import EnvURL 6 | from zksync2.core.utils import apply_l1_to_l2_alias, undo_l1_to_l2_alias 7 | from zksync2.module.module_builder import ZkSyncBuilder 8 | 9 | 10 | class UtilsTest(TestCase): 11 | def setUp(self) -> None: 12 | self.env = EnvURL() 13 | self.zksync = ZkSyncBuilder.build(self.env.env.zksync_server) 14 | 15 | def test_apply_l1_to_l2_alias(self): 16 | l1_contract_address = HexStr("0x702942B8205E5dEdCD3374E5f4419843adA76Eeb") 17 | l2_contract_address = apply_l1_to_l2_alias(l1_contract_address) 18 | self.assertEqual( 19 | l2_contract_address.lower(), 20 | "0x813A42B8205E5DedCd3374e5f4419843ADa77FFC".lower(), 21 | ) 22 | 23 | def test_undo_l1_to_l2_alias(self): 24 | l2_contract_address = HexStr("0x813A42B8205E5DedCd3374e5f4419843ADa77FFC") 25 | l1_contract_address = undo_l1_to_l2_alias(l2_contract_address) 26 | self.assertEqual( 27 | l1_contract_address.lower(), 28 | "0x702942B8205E5dEdCD3374E5f4419843adA76Eeb".lower(), 29 | ) 30 | -------------------------------------------------------------------------------- /zksync2/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zksync-sdk/zksync2-python/a8118a7c1938a32c88ef2de3bea790b40278e26e/zksync2/__init__.py -------------------------------------------------------------------------------- /zksync2/account/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zksync-sdk/zksync2-python/a8118a7c1938a32c88ef2de3bea790b40278e26e/zksync2/account/__init__.py -------------------------------------------------------------------------------- /zksync2/account/smart_account.py: -------------------------------------------------------------------------------- 1 | from ctypes import Union 2 | from typing import Any 3 | 4 | from eth_account import Account 5 | from eth_typing import HexStr 6 | from web3 import Web3 7 | 8 | from zksync2.account.smart_account_utils import ( 9 | populate_transaction_multiple_ecdsa, 10 | sign_payload_with_multiple_ecdsa, 11 | populate_transaction_ecdsa, 12 | sign_payload_with_ecdsa, 13 | ) 14 | from zksync2.core.types import TransferTransaction, WithdrawTransaction, ZkBlockParams 15 | from zksync2.manage_contracts.deploy_addresses import ZkSyncAddresses 16 | from zksync2.manage_contracts.utils import nonce_holder_abi_default 17 | from zksync2.module.response_types import ZksAccountBalances 18 | from zksync2.signer.eth_signer import PrivateKeyEthSigner 19 | from zksync2.transaction.transaction712 import Transaction712 20 | from zksync2.transaction.transaction_builders import TxBase 21 | 22 | 23 | class SmartAccount: 24 | 25 | def __init__( 26 | self, 27 | address: HexStr, 28 | secret, 29 | provider: Web3, 30 | transaction_builder=None, 31 | payload_signer=None, 32 | ): 33 | self._address = address 34 | self._secret = secret 35 | self.provider = provider 36 | self.transaction_builder = transaction_builder 37 | self.payload_signer = payload_signer 38 | 39 | @property 40 | def get_address(self) -> HexStr: 41 | """Read-only property for address""" 42 | return self._address 43 | 44 | @property 45 | def secret(self): 46 | """Read-only property for secret""" 47 | return self._secret 48 | 49 | def get_balance( 50 | self, block_tag=ZkBlockParams.COMMITTED.value, token_address: HexStr = None 51 | ) -> int: 52 | """ 53 | Returns the balance of the account. 54 | 55 | :param block_tag: The block tag to get the balance at. Defaults to 'committed'. 56 | :param token_address: The token address to query balance for. Defaults to the native token. 57 | """ 58 | return self.provider.zksync.zks_get_balance( 59 | self.get_address, block_tag, token_address 60 | ) 61 | 62 | def get_all_balances(self) -> ZksAccountBalances: 63 | """ 64 | Returns the balance of the account. 65 | """ 66 | return self.provider.zksync.zks_get_all_account_balances(self.get_address) 67 | 68 | def get_deployment_nonce(self) -> int: 69 | nonce_holder = self.provider.eth.contract( 70 | Web3.to_checksum_address(ZkSyncAddresses.NONCE_HOLDER_ADDRESS.value), 71 | abi=nonce_holder_abi_default(), 72 | ) 73 | 74 | return nonce_holder.functions.getDeploymentNonce(self.get_address).call() 75 | 76 | def populate_transaction(self, tx: TxBase): 77 | return self.transaction_builder( 78 | tx, tx.tx["from"] or self._address, self._secret, self.provider 79 | ) 80 | 81 | def sign_transaction(self, tx: TxBase) -> bytes: 82 | populated = self.populate_transaction(tx) 83 | populated.meta.custom_signature = self.payload_signer( 84 | populated.to_eip712_struct().signable_bytes( 85 | PrivateKeyEthSigner.get_default_domain(self.provider.eth.chain_id) 86 | ), 87 | self._secret, 88 | self.provider, 89 | ) 90 | return populated.encode() 91 | 92 | def send_transaction(self, tx: TxBase): 93 | return self.provider.zksync.send_raw_transaction(self.sign_transaction(tx)) 94 | 95 | def transfer(self, tx: TransferTransaction): 96 | transaction = self.provider.zksync.get_transfer_transaction( 97 | tx, self.get_address 98 | ) 99 | 100 | return self.send_transaction(transaction) 101 | 102 | def withdraw(self, tx: WithdrawTransaction): 103 | """ 104 | Initiates the withdrawal process which withdraws ETH or any ERC20 token 105 | from the associated account on L2 network to the target account on L1 network. 106 | 107 | :param tx: WithdrawTransaction class. Required parameters are token(HexStr) and amount(int). 108 | 109 | Returns: 110 | - Withdrawal hash. 111 | """ 112 | from_: HexStr = self.get_address 113 | is_contract_address = ( 114 | len(self.provider.eth.get_code(Web3.to_checksum_address(self.get_address))) 115 | != 0 116 | ) 117 | if is_contract_address: 118 | from_ = Account.from_key(self.secret[0]).address 119 | transaction = self.provider.zksync.get_withdraw_transaction(tx, from_=from_) 120 | 121 | if is_contract_address: 122 | transaction.tx["from"] = self.get_address 123 | transaction.tx["nonce"] = tx.options.nonce or 0 124 | 125 | return self.send_transaction(transaction) 126 | 127 | 128 | class MultisigECDSASmartAccount: 129 | @classmethod 130 | def create( 131 | cls, address: HexStr, secret: [HexStr], provider: Web3 132 | ) -> "SmartAccount": 133 | return SmartAccount( 134 | address, 135 | secret, 136 | provider, 137 | populate_transaction_multiple_ecdsa, 138 | sign_payload_with_multiple_ecdsa, 139 | ) 140 | 141 | 142 | class ECDSASmartAccount: 143 | @classmethod 144 | def create( 145 | cls, address: HexStr, secret: [HexStr], provider: Web3 146 | ) -> "SmartAccount": 147 | return SmartAccount( 148 | address, 149 | secret, 150 | provider, 151 | populate_transaction_ecdsa, 152 | sign_payload_with_ecdsa, 153 | ) 154 | -------------------------------------------------------------------------------- /zksync2/account/smart_account_utils.py: -------------------------------------------------------------------------------- 1 | import string 2 | 3 | from eth_account import Account 4 | from eth_account.signers.local import LocalAccount 5 | from eth_typing import HexStr 6 | from web3 import Web3 7 | 8 | from zksync2.core.types import EthBlockParams 9 | from zksync2.core.utils import DEFAULT_GAS_PER_PUBDATA_LIMIT 10 | from zksync2.module.request_types import EIP712Meta 11 | from zksync2.signer.eth_signer import PrivateKeyEthSigner 12 | from zksync2.transaction.transaction712 import Transaction712 13 | from zksync2.transaction.transaction_builders import TxBase 14 | 15 | 16 | def sign_payload_with_ecdsa(payload: bytes, secret, provider: Web3) -> string: 17 | account: LocalAccount = Account.from_key(secret) 18 | signer = PrivateKeyEthSigner(account, provider.eth.chain_id) 19 | 20 | return signer.sign_message(payload).signature 21 | 22 | 23 | def sign_payload_with_multiple_ecdsa(payload: bytes, secrets: [str], provider): 24 | signatures = [] 25 | for secret in secrets: 26 | account: LocalAccount = Account.from_key(secret) 27 | signer = PrivateKeyEthSigner(account, provider.eth.chain_id) 28 | signatures.append(signer.sign_message(payload).signature) 29 | return b"".join(signatures) 30 | 31 | 32 | def populate_transaction_ecdsa( 33 | tx: TxBase, from_: str, secret: str, provider: Web3 34 | ) -> Transaction712: 35 | if provider is None: 36 | raise ValueError(f"Must be True or False. Got: {provider}") 37 | 38 | tx.tx["chainId"] = provider.eth.chain_id 39 | tx.tx["gas"] = tx.tx["gas"] or 0 40 | tx.tx["value"] = tx.tx["value"] or 0 41 | tx.tx["data"] = tx.tx["data"] or 0 42 | tx.tx["eip712Meta"] = tx.tx["eip712Meta"] or EIP712Meta() 43 | tx.tx["eip712Meta"].gas_per_pub_data = ( 44 | DEFAULT_GAS_PER_PUBDATA_LIMIT 45 | if tx.tx["eip712Meta"].gas_per_pub_data is None 46 | else tx.tx["eip712Meta"].gas_per_pub_data 47 | ) 48 | tx.tx["eip712Meta"].factory_deps = ( 49 | [] 50 | if tx.tx["eip712Meta"].factory_deps is None 51 | else tx.tx["eip712Meta"].factory_deps 52 | ) 53 | 54 | fee = None 55 | if from_ is not None: 56 | is_contract_address = ( 57 | len(provider.eth.get_code(Web3.to_checksum_address(from_))) != 0 58 | ) 59 | if is_contract_address: 60 | # Gas estimation does not work when initiator is contract account (works only with EOA). 61 | # In order to estimation gas, the transaction's from value is replaced with signer's address. 62 | fee = provider.zksync.zks_estimate_fee( 63 | { 64 | **tx.tx712(0).to_zk_transaction(), 65 | "from": Account.from_key(secret).address, 66 | } 67 | ) 68 | 69 | tx.tx["from"] = Account.from_key(secret).address if from_ is None else from_ 70 | tx.tx["nonce"] = tx.tx["nonce"] or provider.zksync.get_transaction_count( 71 | Web3.to_checksum_address(tx.tx["from"]), EthBlockParams.PENDING.value 72 | ) 73 | if fee is None: 74 | fee = provider.zksync.zks_estimate_fee(tx.tx712(0).to_zk_transaction()) 75 | gas_limit = tx.tx["gas"] or fee.gas_limit 76 | tx.tx["maxFeePerGas"] = tx.tx["maxFeePerGas"] or fee.max_fee_per_gas 77 | tx.tx["maxPriorityFeePerGas"] = ( 78 | tx.tx["maxPriorityFeePerGas"] or fee.max_priority_fee_per_gas 79 | ) 80 | 81 | return tx.tx712(gas_limit) 82 | 83 | 84 | def populate_transaction_multiple_ecdsa( 85 | tx: TxBase, from_: str, secret: [HexStr], provider: Web3 86 | ) -> Transaction712: 87 | return populate_transaction_ecdsa(tx, from_, secret[0], provider) 88 | -------------------------------------------------------------------------------- /zksync2/account/utils.py: -------------------------------------------------------------------------------- 1 | import web3 2 | from eth_typing import HexStr 3 | from web3 import Web3 4 | from web3.types import Nonce 5 | 6 | from zksync2.core.types import ( 7 | DepositTransaction, 8 | RequestExecuteCallMsg, 9 | TransactionOptions, 10 | ) 11 | from zksync2.transaction.transaction712 import Transaction712 12 | 13 | 14 | def deposit_to_request_execute( 15 | transaction: DepositTransaction, 16 | ) -> RequestExecuteCallMsg: 17 | return RequestExecuteCallMsg( 18 | contract_address=transaction.to, 19 | call_data=HexStr("0x"), 20 | l2_gas_limit=transaction.l2_gas_limit, 21 | l2_value=transaction.amount, 22 | operator_tip=transaction.operator_tip, 23 | gas_per_pubdata_byte=transaction.gas_per_pubdata_byte, 24 | refund_recipient=transaction.refund_recipient, 25 | options=transaction.options, 26 | ) 27 | 28 | 29 | def options_from_712(tx: Transaction712) -> TransactionOptions: 30 | return TransactionOptions( 31 | chain_id=tx.chain_id, 32 | nonce=Nonce(tx.nonce), 33 | gas_limit=tx.gas_limit, 34 | max_fee_per_gas=tx.maxFeePerGas, 35 | max_priority_fee_per_gas=tx.maxPriorityFeePerGas, 36 | gas_price=tx.maxFeePerGas, 37 | ) 38 | 39 | 40 | def prepare_transaction_options( 41 | options: TransactionOptions, from_: HexStr = None, provider: Web3 = None 42 | ): 43 | opt = {} 44 | if options.value is not None: 45 | opt["value"] = options.value 46 | 47 | if ( 48 | options.max_fee_per_gas is not None 49 | or options.max_priority_fee_per_gas is not None 50 | ): 51 | if options.max_priority_fee_per_gas is not None: 52 | opt["maxPriorityFeePerGas"] = options.max_priority_fee_per_gas 53 | if options.max_fee_per_gas is not None: 54 | opt["maxFeePerGas"] = options.max_fee_per_gas 55 | elif options.gas_price is not None: 56 | opt["gasPrice"] = options.gas_price 57 | 58 | if options.gas_limit is not None: 59 | opt["gas"] = options.gas_limit 60 | if options.nonce is not None: 61 | opt["nonce"] = options.nonce 62 | elif provider is not None: 63 | opt["nonce"] = provider.eth.get_transaction_count( 64 | Web3.to_checksum_address(from_) 65 | ) 66 | if options.chain_id is not None: 67 | opt["chainId"] = options.chain_id 68 | if from_ is not None: 69 | opt["from"] = from_ 70 | 71 | return opt 72 | -------------------------------------------------------------------------------- /zksync2/account/wallet.py: -------------------------------------------------------------------------------- 1 | from zksync2.account.wallet_l1 import WalletL1 2 | from zksync2.account.wallet_l2 import WalletL2 3 | 4 | from web3 import Web3 5 | 6 | from eth_account.signers.base import BaseAccount 7 | 8 | from zksync2.module.module_builder import ZkWeb3 9 | 10 | 11 | class Wallet(WalletL1, WalletL2): 12 | def __init__(self, zksync_web3: ZkWeb3, eth_web3: Web3, l1_account: BaseAccount): 13 | self._eth_web3 = eth_web3 14 | self._zksync_web3 = zksync_web3 15 | self._l1_account = l1_account 16 | WalletL1.__init__(self, zksync_web3, eth_web3, l1_account) 17 | WalletL2.__init__(self, zksync_web3, eth_web3, l1_account) 18 | 19 | def sign_transaction(self, tx): 20 | return self._l1_account.sign_transaction(tx) 21 | -------------------------------------------------------------------------------- /zksync2/account/wallet_l2.py: -------------------------------------------------------------------------------- 1 | from eth_account.signers.base import BaseAccount 2 | from eth_typing import HexStr 3 | from web3 import Web3 4 | 5 | from zksync2.core.types import ( 6 | ZkBlockParams, 7 | L2BridgeContracts, 8 | TransferTransaction, 9 | WithdrawTransaction, 10 | ) 11 | from zksync2.manage_contracts.deploy_addresses import ZkSyncAddresses 12 | from zksync2.manage_contracts.utils import ( 13 | get_zksync_hyperchain, 14 | nonce_holder_abi_default, 15 | l2_bridge_abi_default, 16 | l2_shared_bridge_abi_default, 17 | ) 18 | from zksync2.module.module_builder import ZkWeb3 19 | from zksync2.module.response_types import ZksAccountBalances 20 | from zksync2.signer.eth_signer import PrivateKeyEthSigner 21 | from zksync2.transaction.transaction712 import Transaction712 22 | 23 | 24 | class WalletL2: 25 | def __init__(self, zksync_web3: ZkWeb3, eth_web3: Web3, l1_account: BaseAccount): 26 | self._eth_web3 = eth_web3 27 | self._zksync_web3 = zksync_web3 28 | self._main_contract_address = self._zksync_web3.zksync.zks_main_contract() 29 | self._l1_account = l1_account 30 | self.contract = self._eth_web3.eth.contract( 31 | Web3.to_checksum_address(self._main_contract_address), 32 | abi=get_zksync_hyperchain(), 33 | ) 34 | 35 | def get_balance( 36 | self, block_tag=ZkBlockParams.COMMITTED.value, token_address: HexStr = None 37 | ) -> int: 38 | """ 39 | Returns the balance of the account. 40 | 41 | :param block_tag: The block tag to get the balance at. Defaults to 'committed'. 42 | :param token_address: The token address to query balance for. Defaults to the native token. 43 | """ 44 | return self._zksync_web3.zksync.zks_get_balance( 45 | self._l1_account.address, block_tag, token_address 46 | ) 47 | 48 | def get_all_balances(self) -> ZksAccountBalances: 49 | """ 50 | Returns the balance of the account. 51 | """ 52 | return self._zksync_web3.zksync.zks_get_all_account_balances( 53 | self._l1_account.address 54 | ) 55 | 56 | def get_deployment_nonce(self) -> int: 57 | """ 58 | Returns all token balances of the account. 59 | """ 60 | nonce_holder = self._zksync_web3.zksync.contract( 61 | address=ZkSyncAddresses.NONCE_HOLDER_ADDRESS.value, 62 | abi=nonce_holder_abi_default(), 63 | ) 64 | deployment_nonce = nonce_holder.functions.getDeploymentNonce( 65 | self._l1_account.address 66 | ).call({"from": self._l1_account.address}) 67 | return deployment_nonce 68 | 69 | def get_l2_bridge_contracts(self) -> L2BridgeContracts: 70 | """ 71 | Returns L2 bridge contracts. 72 | """ 73 | addresses = self._zksync_web3.zksync.zks_get_bridge_contracts() 74 | return L2BridgeContracts( 75 | erc20=self._zksync_web3.eth.contract( 76 | address=Web3.to_checksum_address(addresses.erc20_l2_default_bridge), 77 | abi=l2_bridge_abi_default(), 78 | ), 79 | weth=self._zksync_web3.eth.contract( 80 | address=Web3.to_checksum_address(addresses.weth_bridge_l2), 81 | abi=l2_bridge_abi_default(), 82 | ), 83 | shared=self._zksync_web3.eth.contract( 84 | address=Web3.to_checksum_address(addresses.shared_l2_default_bridge), 85 | abi=l2_shared_bridge_abi_default(), 86 | ), 87 | ) 88 | 89 | def transfer(self, tx: TransferTransaction) -> HexStr: 90 | """ 91 | Transfer ETH or any ERC20 token within the same interface. 92 | 93 | :param tx: TransferTransaction class. Required parameters are to and amount. 94 | 95 | Returns: 96 | - Transaction hash. 97 | """ 98 | transaction = self._zksync_web3.zksync.get_transfer_transaction( 99 | tx, self._l1_account.address 100 | ) 101 | 102 | tx_712: Transaction712 = transaction.tx712(transaction.tx["gas"]) 103 | fee = self._zksync_web3.zksync.zks_estimate_fee(tx_712.to_zk_transaction()) 104 | tx_712.gas_limit = tx_712.gas_limit or fee.gas_limit 105 | tx_712.maxFeePerGas = tx_712.maxFeePerGas or fee.max_fee_per_gas 106 | tx_712.maxPriorityFeePerGas = ( 107 | tx_712.maxPriorityFeePerGas or fee.max_priority_fee_per_gas 108 | ) 109 | 110 | signer = PrivateKeyEthSigner(self._l1_account, tx.options.chain_id) 111 | signed_message = signer.sign_typed_data(tx_712.to_eip712_struct()) 112 | 113 | msg = tx_712.encode(signed_message) 114 | tx_hash = self._zksync_web3.zksync.send_raw_transaction(msg) 115 | 116 | return tx_hash 117 | 118 | def withdraw(self, tx: WithdrawTransaction): 119 | """ 120 | Initiates the withdrawal process which withdraws ETH or any ERC20 token 121 | from the associated account on L2 network to the target account on L1 network. 122 | 123 | :param tx: WithdrawTransaction class. Required parameters are token(HexStr) and amount(int). 124 | 125 | Returns: 126 | - Withdrawal hash. 127 | """ 128 | transaction = self._zksync_web3.zksync.get_withdraw_transaction( 129 | tx, from_=self._l1_account.address 130 | ) 131 | 132 | tx_712 = transaction.tx712() 133 | fee = self._zksync_web3.zksync.zks_estimate_fee(tx_712.to_zk_transaction()) 134 | tx_712.gas_limit = tx_712.gas_limit or fee.gas_limit 135 | tx_712.maxFeePerGas = tx_712.maxFeePerGas or fee.max_fee_per_gas 136 | tx_712.maxPriorityFeePerGas = ( 137 | tx_712.maxPriorityFeePerGas or fee.max_priority_fee_per_gas 138 | ) 139 | 140 | signer = PrivateKeyEthSigner(self._l1_account, self._zksync_web3.eth.chain_id) 141 | signed_message = signer.sign_typed_data(tx_712.to_eip712_struct()) 142 | 143 | msg = tx_712.encode(signed_message) 144 | 145 | return self._zksync_web3.zksync.send_raw_transaction(msg) 146 | -------------------------------------------------------------------------------- /zksync2/core/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zksync-sdk/zksync2-python/a8118a7c1938a32c88ef2de3bea790b40278e26e/zksync2/core/__init__.py -------------------------------------------------------------------------------- /zksync2/core/utils.py: -------------------------------------------------------------------------------- 1 | import math 2 | import sys 3 | from enum import IntEnum 4 | from hashlib import sha256 5 | from typing import Union 6 | 7 | from eth_abi import encode 8 | from eth_typing import HexStr, Address, ChecksumAddress 9 | from eth_utils import remove_0x_prefix, add_0x_prefix 10 | from hexbytes import HexBytes 11 | from web3 import Web3 12 | 13 | ADDRESS_MODULO = pow(2, 160) 14 | L1_TO_L2_ALIAS_OFFSET = "0x1111000000000000000000000000000000001111" 15 | 16 | ETH_ADDRESS_IN_CONTRACTS = "0x0000000000000000000000000000000000000001" 17 | 18 | LEGACY_ETH_ADDRESS = HexStr("0x" + "0" * 40) 19 | ADDRESS_DEFAULT = HexStr("0x" + "0" * 40) 20 | L2_BASE_TOKEN_ADDRESS = HexStr("0x000000000000000000000000000000000000800a") 21 | L2_ETH_TOKEN_ADDRESS = HexStr("0x000000000000000000000000000000000000800a") 22 | BOOTLOADER_FORMAL_ADDRESS = HexStr("0x0000000000000000000000000000000000008001") 23 | 24 | DEPOSIT_GAS_PER_PUBDATA_LIMIT = 800 25 | MAX_PRIORITY_FEE_PER_GAS = 100_000_000 26 | DEFAULT_GAS_PER_PUBDATA_LIMIT = 50000 27 | 28 | L1_FEE_ESTIMATION_COEF_NUMERATOR = 12 29 | L1_FEE_ESTIMATION_COEF_DENOMINATOR = 10 30 | 31 | 32 | def int_to_bytes(x: int) -> bytes: 33 | return x.to_bytes((x.bit_length() + 7) // 8, byteorder=sys.byteorder) 34 | 35 | 36 | def to_bytes(data: Union[bytes, HexStr]) -> bytes: 37 | if isinstance(data, bytes): 38 | return data 39 | return bytes.fromhex(remove_0x_prefix(data)) 40 | 41 | 42 | def is_eth(address: HexStr) -> bool: 43 | return ( 44 | address.lower() == LEGACY_ETH_ADDRESS 45 | or address.lower() == L2_BASE_TOKEN_ADDRESS 46 | or address.lower() == ETH_ADDRESS_IN_CONTRACTS 47 | ) 48 | 49 | 50 | def is_address_eq(a: HexStr, b: HexStr) -> bool: 51 | return a.lower() == b.lower() 52 | 53 | 54 | def encode_address(addr: Union[Address, ChecksumAddress, str]) -> bytes: 55 | if len(addr) == 0: 56 | return bytes() 57 | if isinstance(addr, bytes): 58 | return addr 59 | return bytes.fromhex(remove_0x_prefix(addr)) 60 | 61 | 62 | def hash_byte_code(bytecode: bytes) -> bytes: 63 | bytecode_len = len(bytecode) 64 | bytecode_size = int(bytecode_len / 32) 65 | if bytecode_len % 32 != 0: 66 | raise RuntimeError("Bytecode length in 32-byte words must be odd") 67 | if bytecode_size > 2**16: 68 | raise OverflowError("hash_byte_code, bytecode length must be less than 2^16") 69 | bytecode_hash = sha256(bytecode).digest() 70 | encoded_len = bytecode_size.to_bytes(2, byteorder="big") 71 | ret = b"\x01\00" + encoded_len + bytecode_hash[4:] 72 | return ret 73 | 74 | 75 | def pad_front_bytes(bs: bytes, needed_length: int): 76 | padded = b"\0" * (needed_length - len(bs)) + bs 77 | return padded 78 | 79 | 80 | def get_custom_bridge_data(token_contract) -> bytes: 81 | address = token_contract.address 82 | name = ( 83 | "Ether" 84 | if address.lower() == ETH_ADDRESS_IN_CONTRACTS.lower() 85 | else token_contract.functions.name().call() 86 | ) 87 | symbol = ( 88 | "ETH" 89 | if address.lower() == ETH_ADDRESS_IN_CONTRACTS.lower() 90 | else token_contract.functions.symbol().call() 91 | ) 92 | decimals = ( 93 | 18 94 | if address.lower() == ETH_ADDRESS_IN_CONTRACTS.lower() 95 | else token_contract.functions.decimals().call() 96 | ) 97 | 98 | name_encoded = encode(["string"], [name]) 99 | symbol_encoded = encode(["string"], [symbol]) 100 | decimals_encoded = encode(["uint256"], [decimals]) 101 | 102 | return encode( 103 | ["bytes", "bytes", "bytes"], [name_encoded, symbol_encoded, decimals_encoded] 104 | ) 105 | 106 | 107 | def apply_l1_to_l2_alias(address: HexStr): 108 | value = (int(L1_TO_L2_ALIAS_OFFSET, 16) + int(address, 16)) % ADDRESS_MODULO 109 | hex_result = remove_0x_prefix(Web3.to_hex(value)) 110 | result = hex_result.rjust(40, "0") 111 | return add_0x_prefix(result) 112 | 113 | 114 | def pad_back_bytes(bs: bytes, needed_length: int): 115 | padded = bs + b"\0" * (needed_length - len(bs)) 116 | return padded 117 | 118 | 119 | def undo_l1_to_l2_alias(address: HexStr): 120 | result = int(address, 16) - int(L1_TO_L2_ALIAS_OFFSET, 16) 121 | if result < 0: 122 | result += ADDRESS_MODULO 123 | 124 | return Web3.to_hex(result) 125 | 126 | 127 | def scale_gas_limit(base_gas: int): 128 | return math.trunc( 129 | (base_gas * L1_FEE_ESTIMATION_COEF_NUMERATOR) 130 | / L1_FEE_ESTIMATION_COEF_DENOMINATOR 131 | ) 132 | 133 | 134 | class RecommendedGasLimit(IntEnum): 135 | DEPOSIT = 10000000 136 | EXECUTE = 620000 137 | ERC20_APPROVE = 50000 138 | DEPOSIT_GAS_PER_PUBDATA_LIMIT = 800 139 | L1_RECOMMENDED_ETH_DEPOSIT_GAS_LIMIT = 200000 140 | L1_RECOMMENDED_MIN_ERC_20_DEPOSIT_GAS_LIMIT = 400000 141 | -------------------------------------------------------------------------------- /zksync2/eip712/__init__.py: -------------------------------------------------------------------------------- 1 | from zksync2.eip712.domain_separator import make_domain 2 | from zksync2.eip712.struct import EIP712Struct 3 | from zksync2.eip712.types import Address, Array, Boolean, Bytes, Int, String, Uint 4 | 5 | default_domain = None 6 | -------------------------------------------------------------------------------- /zksync2/eip712/domain_separator.py: -------------------------------------------------------------------------------- 1 | from zksync2.eip712.struct import EIP712Struct 2 | from zksync2.eip712.types import String, Uint, Address, Bytes 3 | 4 | 5 | def make_domain( 6 | name=None, version=None, chainId=None, verifyingContract=None, salt=None 7 | ): 8 | """Helper method to create the standard EIP712Domain struct for you. 9 | 10 | Per the standard, if a value is not used then the parameter is omitted from the struct entirely. 11 | """ 12 | 13 | if all(i is None for i in [name, version, chainId, verifyingContract, salt]): 14 | raise ValueError("At least one argument must be given.") 15 | 16 | class EIP712Domain(EIP712Struct): 17 | pass 18 | 19 | kwargs = dict() 20 | if name is not None: 21 | EIP712Domain.name = String() 22 | kwargs["name"] = str(name) 23 | if version is not None: 24 | EIP712Domain.version = String() 25 | kwargs["version"] = str(version) 26 | if chainId is not None: 27 | EIP712Domain.chainId = Uint(256) 28 | kwargs["chainId"] = int(chainId) 29 | if verifyingContract is not None: 30 | EIP712Domain.verifyingContract = Address() 31 | kwargs["verifyingContract"] = verifyingContract 32 | if salt is not None: 33 | EIP712Domain.salt = Bytes(32) 34 | kwargs["salt"] = salt 35 | 36 | return EIP712Domain(**kwargs) 37 | -------------------------------------------------------------------------------- /zksync2/eip712/types.py: -------------------------------------------------------------------------------- 1 | import re 2 | from json import JSONEncoder 3 | from typing import Any, Union, Type 4 | 5 | from eth_utils.crypto import keccak 6 | from eth_utils.conversions import to_bytes, to_hex, to_int 7 | 8 | 9 | class EIP712Type: 10 | """The base type for members of a struct. 11 | 12 | Generally you wouldn't use this - instead, see the subclasses below. Or you may want an EIP712Struct instead. 13 | """ 14 | 15 | def __init__(self, type_name: str, none_val: Any): 16 | self.type_name = type_name 17 | self.none_val = none_val 18 | 19 | def encode_value(self, value) -> bytes: 20 | """Given a value, verify it and convert into the format required by the spec. 21 | 22 | :param value: A correct input value for the implemented type. 23 | :return: A 32-byte object containing encoded data 24 | """ 25 | if value is None: 26 | return self._encode_value(self.none_val) 27 | else: 28 | return self._encode_value(value) 29 | 30 | def _encode_value(self, value) -> bytes: 31 | """Must be implemented by subclasses, handles value encoding on a case-by-case basis. 32 | 33 | Don't call this directly - use ``.encode_value(value)`` instead. 34 | """ 35 | pass 36 | 37 | def __eq__(self, other): 38 | self_type = getattr(self, "type_name") 39 | other_type = getattr(other, "type_name") 40 | 41 | return self_type is not None and self_type == other_type 42 | 43 | def __hash__(self): 44 | return hash(self.type_name) 45 | 46 | 47 | class Array(EIP712Type): 48 | def __init__( 49 | self, member_type: Union[EIP712Type, Type[EIP712Type]], fixed_length: int = 0 50 | ): 51 | """Represents an array member type. 52 | 53 | Example: 54 | a1 = Array(String()) # string[] a1 55 | a2 = Array(String(), 8) # string[8] a2 56 | a3 = Array(MyStruct) # MyStruct[] a3 57 | """ 58 | fixed_length = int(fixed_length) 59 | if fixed_length == 0: 60 | type_name = f"{member_type.type_name}[]" 61 | else: 62 | type_name = f"{member_type.type_name}[{fixed_length}]" 63 | self.member_type = member_type 64 | self.fixed_length = fixed_length 65 | super(Array, self).__init__(type_name, []) 66 | 67 | def _encode_value(self, value): 68 | """Arrays are encoded by concatenating their encoded contents, and taking the keccak256 hash.""" 69 | encoder = self.member_type 70 | encoded_values = [encoder.encode_value(v) for v in value] 71 | return keccak(b"".join(encoded_values)) 72 | 73 | 74 | class Address(EIP712Type): 75 | def __init__(self): 76 | """Represents an ``address`` type.""" 77 | super(Address, self).__init__("address", 0) 78 | 79 | def _encode_value(self, value): 80 | """Addresses are encoded like Uint160 numbers.""" 81 | 82 | # Some smart conversions - need to get the address to a numeric before we encode it 83 | if isinstance(value, bytes): 84 | v = to_int(value) 85 | elif isinstance(value, str): 86 | v = to_int(hexstr=value) 87 | else: 88 | v = value # Fallback, just use it as-is. 89 | return Uint(160).encode_value(v) 90 | 91 | 92 | class Boolean(EIP712Type): 93 | def __init__(self): 94 | """Represents a ``bool`` type.""" 95 | super(Boolean, self).__init__("bool", False) 96 | 97 | def _encode_value(self, value): 98 | """Booleans are encoded like the uint256 values of 0 and 1.""" 99 | if value is False: 100 | return Uint(256).encode_value(0) 101 | elif value is True: 102 | return Uint(256).encode_value(1) 103 | else: 104 | raise ValueError(f"Must be True or False. Got: {value}") 105 | 106 | 107 | class Bytes(EIP712Type): 108 | def __init__(self, length: int = 0): 109 | """Represents a solidity bytes type. 110 | 111 | Length may be used to specify a static ``bytesN`` type. Or 0 for a dynamic ``bytes`` type. 112 | Example: 113 | b1 = Bytes() # bytes b1 114 | b2 = Bytes(10) # bytes10 b2 115 | 116 | ``length`` MUST be between 0 and 32, or a ValueError is raised. 117 | """ 118 | length = int(length) 119 | if length == 0: 120 | # Special case: Length of 0 means a dynamic bytes type 121 | type_name = "bytes" 122 | elif 1 <= length <= 32: 123 | type_name = f"bytes{length}" 124 | else: 125 | raise ValueError(f"Byte length must be between 1 or 32. Got: {length}") 126 | self.length = length 127 | super(Bytes, self).__init__(type_name, b"") 128 | 129 | def _encode_value(self, value): 130 | """Static bytesN types are encoded by right-padding to 32 bytes. Dynamic bytes types are keccak256 hashed.""" 131 | if isinstance(value, str): 132 | # Try converting to a bytestring, assuming that it's been given as hex 133 | value = to_bytes(hexstr=value) 134 | 135 | if self.length == 0: 136 | return keccak(value) 137 | else: 138 | if len(value) > self.length: 139 | raise ValueError( 140 | f"{self.type_name} was given bytes with length {len(value)}" 141 | ) 142 | padding = bytes(32 - len(value)) 143 | return value + padding 144 | 145 | 146 | class Int(EIP712Type): 147 | def __init__(self, length: int = 256): 148 | """Represents a signed int type. Length may be given to specify the int length in bits. Default length is 256 149 | 150 | Example: 151 | i1 = Int(256) # int256 i1 152 | i2 = Int() # int256 i2 153 | i3 = Int(128) # int128 i3 154 | """ 155 | length = int(length) 156 | if length < 8 or length > 256 or length % 8 != 0: 157 | raise ValueError( 158 | f"Int length must be a multiple of 8, between 8 and 256. Got: {length}" 159 | ) 160 | self.length = length 161 | super(Int, self).__init__(f"int{length}", 0) 162 | 163 | def _encode_value(self, value: int): 164 | """Ints are encoded by padding them to 256-bit representations.""" 165 | value.to_bytes(self.length // 8, byteorder="big", signed=True) # For validation 166 | return value.to_bytes(32, byteorder="big", signed=True) 167 | 168 | 169 | class String(EIP712Type): 170 | def __init__(self): 171 | """Represents a string type.""" 172 | super(String, self).__init__("string", "") 173 | 174 | def _encode_value(self, value): 175 | """Strings are encoded by taking the keccak256 hash of their contents.""" 176 | return keccak(text=value) 177 | 178 | 179 | class Uint(EIP712Type): 180 | def __init__(self, length: int = 256): 181 | """Represents an unsigned int type. Length may be given to specify the int length in bits. Default length is 256 182 | 183 | Example: 184 | ui1 = Uint(256) # uint256 ui1 185 | ui2 = Uint() # uint256 ui2 186 | ui3 = Uint(128) # uint128 ui3 187 | """ 188 | length = int(length) 189 | if length < 8 or length > 256 or length % 8 != 0: 190 | raise ValueError( 191 | f"Uint length must be a multiple of 8, between 8 and 256. Got: {length}" 192 | ) 193 | self.length = length 194 | super(Uint, self).__init__(f"uint{length}", 0) 195 | 196 | def _encode_value(self, value: int): 197 | """Uints are encoded by padding them to 256-bit representations.""" 198 | value.to_bytes( 199 | self.length // 8, byteorder="big", signed=False 200 | ) # For validation 201 | return value.to_bytes(32, byteorder="big", signed=False) 202 | 203 | 204 | # This helper dict maps solidity's type names to our EIP712Type classes 205 | solidity_type_map = { 206 | "address": Address, 207 | "bool": Boolean, 208 | "bytes": Bytes, 209 | "int": Int, 210 | "string": String, 211 | "uint": Uint, 212 | } 213 | 214 | 215 | def from_solidity_type(solidity_type: str): 216 | """Convert a string into the EIP712Type implementation. Basic types only.""" 217 | pattern = r"([a-z]+)(\d+)?(\[(\d+)?\])?" 218 | match = re.match(pattern, solidity_type) 219 | 220 | if match is None: 221 | return None 222 | 223 | type_name = match.group(1) # The type name, like the "bytes" in "bytes32" 224 | opt_len = match.group(2) # An optional length spec, like the "32" in "bytes32" 225 | is_array = match.group(3) # Basically just checks for square brackets 226 | array_len = match.group(4) # For fixed length arrays only, this is the length 227 | 228 | if type_name not in solidity_type_map: 229 | # Only supporting basic types here - return None if we don't recognize it. 230 | return None 231 | 232 | # Construct the basic type 233 | base_type = solidity_type_map[type_name] 234 | if opt_len: 235 | type_instance = base_type(int(opt_len)) 236 | else: 237 | type_instance = base_type() 238 | 239 | if is_array: 240 | # Nest the aforementioned basic type into an Array. 241 | if array_len: 242 | result = Array(type_instance, int(array_len)) 243 | else: 244 | result = Array(type_instance) 245 | return result 246 | else: 247 | return type_instance 248 | 249 | 250 | class BytesJSONEncoder(JSONEncoder): 251 | def default(self, o): 252 | if isinstance(o, bytes): 253 | return to_hex(o) 254 | else: 255 | return super(BytesJSONEncoder, self).default(o) 256 | -------------------------------------------------------------------------------- /zksync2/manage_contracts/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zksync-sdk/zksync2-python/a8118a7c1938a32c88ef2de3bea790b40278e26e/zksync2/manage_contracts/__init__.py -------------------------------------------------------------------------------- /zksync2/manage_contracts/contract_abi/IContractDeployer.json: -------------------------------------------------------------------------------- 1 | { 2 | "abi": [ 3 | { 4 | "anonymous": false, 5 | "inputs": [ 6 | { 7 | "indexed": true, 8 | "internalType": "address", 9 | "name": "accountAddress", 10 | "type": "address" 11 | }, 12 | { 13 | "indexed": false, 14 | "internalType": "enum IContractDeployer.AccountNonceOrdering", 15 | "name": "nonceOrdering", 16 | "type": "uint8" 17 | } 18 | ], 19 | "name": "AccountNonceOrderingUpdated", 20 | "type": "event" 21 | }, 22 | { 23 | "anonymous": false, 24 | "inputs": [ 25 | { 26 | "indexed": true, 27 | "internalType": "address", 28 | "name": "accountAddress", 29 | "type": "address" 30 | }, 31 | { 32 | "indexed": false, 33 | "internalType": "enum IContractDeployer.AccountAbstractionVersion", 34 | "name": "aaVersion", 35 | "type": "uint8" 36 | } 37 | ], 38 | "name": "AccountVersionUpdated", 39 | "type": "event" 40 | }, 41 | { 42 | "anonymous": false, 43 | "inputs": [ 44 | { 45 | "indexed": true, 46 | "internalType": "address", 47 | "name": "deployerAddress", 48 | "type": "address" 49 | }, 50 | { 51 | "indexed": true, 52 | "internalType": "bytes32", 53 | "name": "bytecodeHash", 54 | "type": "bytes32" 55 | }, 56 | { 57 | "indexed": true, 58 | "internalType": "address", 59 | "name": "contractAddress", 60 | "type": "address" 61 | } 62 | ], 63 | "name": "ContractDeployed", 64 | "type": "event" 65 | }, 66 | { 67 | "inputs": [ 68 | { 69 | "internalType": "bytes32", 70 | "name": "_salt", 71 | "type": "bytes32" 72 | }, 73 | { 74 | "internalType": "bytes32", 75 | "name": "_bytecodeHash", 76 | "type": "bytes32" 77 | }, 78 | { 79 | "internalType": "bytes", 80 | "name": "_input", 81 | "type": "bytes" 82 | } 83 | ], 84 | "name": "create", 85 | "outputs": [ 86 | { 87 | "internalType": "address", 88 | "name": "newAddress", 89 | "type": "address" 90 | } 91 | ], 92 | "stateMutability": "payable", 93 | "type": "function" 94 | }, 95 | { 96 | "inputs": [ 97 | { 98 | "internalType": "bytes32", 99 | "name": "_salt", 100 | "type": "bytes32" 101 | }, 102 | { 103 | "internalType": "bytes32", 104 | "name": "_bytecodeHash", 105 | "type": "bytes32" 106 | }, 107 | { 108 | "internalType": "bytes", 109 | "name": "_input", 110 | "type": "bytes" 111 | } 112 | ], 113 | "name": "create2", 114 | "outputs": [ 115 | { 116 | "internalType": "address", 117 | "name": "newAddress", 118 | "type": "address" 119 | } 120 | ], 121 | "stateMutability": "payable", 122 | "type": "function" 123 | }, 124 | { 125 | "inputs": [ 126 | { 127 | "internalType": "bytes32", 128 | "name": "_salt", 129 | "type": "bytes32" 130 | }, 131 | { 132 | "internalType": "bytes32", 133 | "name": "_bytecodeHash", 134 | "type": "bytes32" 135 | }, 136 | { 137 | "internalType": "bytes", 138 | "name": "_input", 139 | "type": "bytes" 140 | }, 141 | { 142 | "internalType": "enum IContractDeployer.AccountAbstractionVersion", 143 | "name": "_aaVersion", 144 | "type": "uint8" 145 | } 146 | ], 147 | "name": "create2Account", 148 | "outputs": [ 149 | { 150 | "internalType": "address", 151 | "name": "newAddress", 152 | "type": "address" 153 | } 154 | ], 155 | "stateMutability": "payable", 156 | "type": "function" 157 | }, 158 | { 159 | "inputs": [ 160 | { 161 | "internalType": "bytes32", 162 | "name": "_salt", 163 | "type": "bytes32" 164 | }, 165 | { 166 | "internalType": "bytes32", 167 | "name": "_bytecodeHash", 168 | "type": "bytes32" 169 | }, 170 | { 171 | "internalType": "bytes", 172 | "name": "_input", 173 | "type": "bytes" 174 | }, 175 | { 176 | "internalType": "enum IContractDeployer.AccountAbstractionVersion", 177 | "name": "_aaVersion", 178 | "type": "uint8" 179 | } 180 | ], 181 | "name": "createAccount", 182 | "outputs": [ 183 | { 184 | "internalType": "address", 185 | "name": "newAddress", 186 | "type": "address" 187 | } 188 | ], 189 | "stateMutability": "payable", 190 | "type": "function" 191 | }, 192 | { 193 | "inputs": [ 194 | { 195 | "internalType": "address", 196 | "name": "_address", 197 | "type": "address" 198 | } 199 | ], 200 | "name": "getAccountInfo", 201 | "outputs": [ 202 | { 203 | "components": [ 204 | { 205 | "internalType": "enum IContractDeployer.AccountAbstractionVersion", 206 | "name": "supportedAAVersion", 207 | "type": "uint8" 208 | }, 209 | { 210 | "internalType": "enum IContractDeployer.AccountNonceOrdering", 211 | "name": "nonceOrdering", 212 | "type": "uint8" 213 | } 214 | ], 215 | "internalType": "struct IContractDeployer.AccountInfo", 216 | "name": "info", 217 | "type": "tuple" 218 | } 219 | ], 220 | "stateMutability": "view", 221 | "type": "function" 222 | }, 223 | { 224 | "inputs": [ 225 | { 226 | "internalType": "address", 227 | "name": "_sender", 228 | "type": "address" 229 | }, 230 | { 231 | "internalType": "uint256", 232 | "name": "_senderNonce", 233 | "type": "uint256" 234 | } 235 | ], 236 | "name": "getNewAddressCreate", 237 | "outputs": [ 238 | { 239 | "internalType": "address", 240 | "name": "newAddress", 241 | "type": "address" 242 | } 243 | ], 244 | "stateMutability": "pure", 245 | "type": "function" 246 | }, 247 | { 248 | "inputs": [ 249 | { 250 | "internalType": "address", 251 | "name": "_sender", 252 | "type": "address" 253 | }, 254 | { 255 | "internalType": "bytes32", 256 | "name": "_bytecodeHash", 257 | "type": "bytes32" 258 | }, 259 | { 260 | "internalType": "bytes32", 261 | "name": "_salt", 262 | "type": "bytes32" 263 | }, 264 | { 265 | "internalType": "bytes", 266 | "name": "_input", 267 | "type": "bytes" 268 | } 269 | ], 270 | "name": "getNewAddressCreate2", 271 | "outputs": [ 272 | { 273 | "internalType": "address", 274 | "name": "newAddress", 275 | "type": "address" 276 | } 277 | ], 278 | "stateMutability": "view", 279 | "type": "function" 280 | }, 281 | { 282 | "inputs": [ 283 | { 284 | "internalType": "enum IContractDeployer.AccountAbstractionVersion", 285 | "name": "_version", 286 | "type": "uint8" 287 | } 288 | ], 289 | "name": "updateAccountVersion", 290 | "outputs": [], 291 | "stateMutability": "nonpayable", 292 | "type": "function" 293 | }, 294 | { 295 | "inputs": [ 296 | { 297 | "internalType": "enum IContractDeployer.AccountNonceOrdering", 298 | "name": "_nonceOrdering", 299 | "type": "uint8" 300 | } 301 | ], 302 | "name": "updateNonceOrdering", 303 | "outputs": [], 304 | "stateMutability": "nonpayable", 305 | "type": "function" 306 | } 307 | ] 308 | } -------------------------------------------------------------------------------- /zksync2/manage_contracts/contract_abi/IERC1271.json: -------------------------------------------------------------------------------- 1 | { 2 | "abi": [ 3 | { 4 | "inputs": [ 5 | { 6 | "internalType": "bytes32", 7 | "name": "hash", 8 | "type": "bytes32" 9 | }, 10 | { 11 | "internalType": "bytes", 12 | "name": "signature", 13 | "type": "bytes" 14 | } 15 | ], 16 | "name": "isValidSignature", 17 | "outputs": [ 18 | { 19 | "internalType": "bytes4", 20 | "name": "magicValue", 21 | "type": "bytes4" 22 | } 23 | ], 24 | "stateMutability": "view", 25 | "type": "function" 26 | } 27 | ] 28 | } -------------------------------------------------------------------------------- /zksync2/manage_contracts/contract_abi/IERC20.json: -------------------------------------------------------------------------------- 1 | { 2 | "abi": [ 3 | { 4 | "anonymous": false, 5 | "inputs": [ 6 | { 7 | "indexed": true, 8 | "internalType": "address", 9 | "name": "owner", 10 | "type": "address" 11 | }, 12 | { 13 | "indexed": true, 14 | "internalType": "address", 15 | "name": "spender", 16 | "type": "address" 17 | }, 18 | { 19 | "indexed": false, 20 | "internalType": "uint256", 21 | "name": "value", 22 | "type": "uint256" 23 | } 24 | ], 25 | "name": "Approval", 26 | "type": "event" 27 | }, 28 | { 29 | "anonymous": false, 30 | "inputs": [ 31 | { 32 | "indexed": true, 33 | "internalType": "address", 34 | "name": "from", 35 | "type": "address" 36 | }, 37 | { 38 | "indexed": true, 39 | "internalType": "address", 40 | "name": "to", 41 | "type": "address" 42 | }, 43 | { 44 | "indexed": false, 45 | "internalType": "uint256", 46 | "name": "value", 47 | "type": "uint256" 48 | } 49 | ], 50 | "name": "Transfer", 51 | "type": "event" 52 | }, 53 | { 54 | "inputs": [ 55 | { 56 | "internalType": "address", 57 | "name": "owner", 58 | "type": "address" 59 | }, 60 | { 61 | "internalType": "address", 62 | "name": "spender", 63 | "type": "address" 64 | } 65 | ], 66 | "name": "allowance", 67 | "outputs": [ 68 | { 69 | "internalType": "uint256", 70 | "name": "", 71 | "type": "uint256" 72 | } 73 | ], 74 | "stateMutability": "view", 75 | "type": "function" 76 | }, 77 | { 78 | "inputs": [ 79 | { 80 | "internalType": "address", 81 | "name": "spender", 82 | "type": "address" 83 | }, 84 | { 85 | "internalType": "uint256", 86 | "name": "amount", 87 | "type": "uint256" 88 | } 89 | ], 90 | "name": "approve", 91 | "outputs": [ 92 | { 93 | "internalType": "bool", 94 | "name": "", 95 | "type": "bool" 96 | } 97 | ], 98 | "stateMutability": "nonpayable", 99 | "type": "function" 100 | }, 101 | { 102 | "inputs": [ 103 | { 104 | "internalType": "address", 105 | "name": "account", 106 | "type": "address" 107 | } 108 | ], 109 | "name": "balanceOf", 110 | "outputs": [ 111 | { 112 | "internalType": "uint256", 113 | "name": "", 114 | "type": "uint256" 115 | } 116 | ], 117 | "stateMutability": "view", 118 | "type": "function" 119 | }, 120 | { 121 | "inputs": [], 122 | "name": "decimals", 123 | "outputs": [ 124 | { 125 | "internalType": "uint8", 126 | "name": "", 127 | "type": "uint8" 128 | } 129 | ], 130 | "stateMutability": "view", 131 | "type": "function" 132 | }, 133 | { 134 | "inputs": [], 135 | "name": "name", 136 | "outputs": [ 137 | { 138 | "internalType": "string", 139 | "name": "", 140 | "type": "string" 141 | } 142 | ], 143 | "stateMutability": "view", 144 | "type": "function" 145 | }, 146 | { 147 | "inputs": [], 148 | "name": "symbol", 149 | "outputs": [ 150 | { 151 | "internalType": "string", 152 | "name": "", 153 | "type": "string" 154 | } 155 | ], 156 | "stateMutability": "view", 157 | "type": "function" 158 | }, 159 | { 160 | "inputs": [], 161 | "name": "totalSupply", 162 | "outputs": [ 163 | { 164 | "internalType": "uint256", 165 | "name": "", 166 | "type": "uint256" 167 | } 168 | ], 169 | "stateMutability": "view", 170 | "type": "function" 171 | }, 172 | { 173 | "inputs": [ 174 | { 175 | "internalType": "address", 176 | "name": "to", 177 | "type": "address" 178 | }, 179 | { 180 | "internalType": "uint256", 181 | "name": "amount", 182 | "type": "uint256" 183 | } 184 | ], 185 | "name": "transfer", 186 | "outputs": [ 187 | { 188 | "internalType": "bool", 189 | "name": "", 190 | "type": "bool" 191 | } 192 | ], 193 | "stateMutability": "nonpayable", 194 | "type": "function" 195 | }, 196 | { 197 | "inputs": [ 198 | { 199 | "internalType": "address", 200 | "name": "from", 201 | "type": "address" 202 | }, 203 | { 204 | "internalType": "address", 205 | "name": "to", 206 | "type": "address" 207 | }, 208 | { 209 | "internalType": "uint256", 210 | "name": "amount", 211 | "type": "uint256" 212 | } 213 | ], 214 | "name": "transferFrom", 215 | "outputs": [ 216 | { 217 | "internalType": "bool", 218 | "name": "", 219 | "type": "bool" 220 | } 221 | ], 222 | "stateMutability": "nonpayable", 223 | "type": "function" 224 | } 225 | ] 226 | } -------------------------------------------------------------------------------- /zksync2/manage_contracts/contract_abi/IEthToken.json: -------------------------------------------------------------------------------- 1 | { 2 | "abi": [ 3 | { 4 | "anonymous": false, 5 | "inputs": [ 6 | { 7 | "indexed": true, 8 | "internalType": "address", 9 | "name": "account", 10 | "type": "address" 11 | }, 12 | { 13 | "indexed": false, 14 | "internalType": "uint256", 15 | "name": "amount", 16 | "type": "uint256" 17 | } 18 | ], 19 | "name": "Mint", 20 | "type": "event" 21 | }, 22 | { 23 | "anonymous": false, 24 | "inputs": [ 25 | { 26 | "indexed": true, 27 | "internalType": "address", 28 | "name": "from", 29 | "type": "address" 30 | }, 31 | { 32 | "indexed": true, 33 | "internalType": "address", 34 | "name": "to", 35 | "type": "address" 36 | }, 37 | { 38 | "indexed": false, 39 | "internalType": "uint256", 40 | "name": "value", 41 | "type": "uint256" 42 | } 43 | ], 44 | "name": "Transfer", 45 | "type": "event" 46 | }, 47 | { 48 | "anonymous": false, 49 | "inputs": [ 50 | { 51 | "indexed": true, 52 | "internalType": "address", 53 | "name": "_l2Sender", 54 | "type": "address" 55 | }, 56 | { 57 | "indexed": true, 58 | "internalType": "address", 59 | "name": "_l1Receiver", 60 | "type": "address" 61 | }, 62 | { 63 | "indexed": false, 64 | "internalType": "uint256", 65 | "name": "_amount", 66 | "type": "uint256" 67 | } 68 | ], 69 | "name": "Withdrawal", 70 | "type": "event" 71 | }, 72 | { 73 | "anonymous": false, 74 | "inputs": [ 75 | { 76 | "indexed": true, 77 | "internalType": "address", 78 | "name": "_l2Sender", 79 | "type": "address" 80 | }, 81 | { 82 | "indexed": true, 83 | "internalType": "address", 84 | "name": "_l1Receiver", 85 | "type": "address" 86 | }, 87 | { 88 | "indexed": false, 89 | "internalType": "uint256", 90 | "name": "_amount", 91 | "type": "uint256" 92 | }, 93 | { 94 | "indexed": false, 95 | "internalType": "bytes", 96 | "name": "_additionalData", 97 | "type": "bytes" 98 | } 99 | ], 100 | "name": "WithdrawalWithMessage", 101 | "type": "event" 102 | }, 103 | { 104 | "inputs": [ 105 | { 106 | "internalType": "uint256", 107 | "name": "", 108 | "type": "uint256" 109 | } 110 | ], 111 | "name": "balanceOf", 112 | "outputs": [ 113 | { 114 | "internalType": "uint256", 115 | "name": "", 116 | "type": "uint256" 117 | } 118 | ], 119 | "stateMutability": "view", 120 | "type": "function" 121 | }, 122 | { 123 | "inputs": [], 124 | "name": "decimals", 125 | "outputs": [ 126 | { 127 | "internalType": "uint8", 128 | "name": "", 129 | "type": "uint8" 130 | } 131 | ], 132 | "stateMutability": "pure", 133 | "type": "function" 134 | }, 135 | { 136 | "inputs": [ 137 | { 138 | "internalType": "address", 139 | "name": "_account", 140 | "type": "address" 141 | }, 142 | { 143 | "internalType": "uint256", 144 | "name": "_amount", 145 | "type": "uint256" 146 | } 147 | ], 148 | "name": "mint", 149 | "outputs": [], 150 | "stateMutability": "nonpayable", 151 | "type": "function" 152 | }, 153 | { 154 | "inputs": [], 155 | "name": "name", 156 | "outputs": [ 157 | { 158 | "internalType": "string", 159 | "name": "", 160 | "type": "string" 161 | } 162 | ], 163 | "stateMutability": "pure", 164 | "type": "function" 165 | }, 166 | { 167 | "inputs": [], 168 | "name": "symbol", 169 | "outputs": [ 170 | { 171 | "internalType": "string", 172 | "name": "", 173 | "type": "string" 174 | } 175 | ], 176 | "stateMutability": "pure", 177 | "type": "function" 178 | }, 179 | { 180 | "inputs": [], 181 | "name": "totalSupply", 182 | "outputs": [ 183 | { 184 | "internalType": "uint256", 185 | "name": "", 186 | "type": "uint256" 187 | } 188 | ], 189 | "stateMutability": "view", 190 | "type": "function" 191 | }, 192 | { 193 | "inputs": [ 194 | { 195 | "internalType": "address", 196 | "name": "_from", 197 | "type": "address" 198 | }, 199 | { 200 | "internalType": "address", 201 | "name": "_to", 202 | "type": "address" 203 | }, 204 | { 205 | "internalType": "uint256", 206 | "name": "_amount", 207 | "type": "uint256" 208 | } 209 | ], 210 | "name": "transferFromTo", 211 | "outputs": [], 212 | "stateMutability": "nonpayable", 213 | "type": "function" 214 | }, 215 | { 216 | "inputs": [ 217 | { 218 | "internalType": "address", 219 | "name": "_l1Receiver", 220 | "type": "address" 221 | } 222 | ], 223 | "name": "withdraw", 224 | "outputs": [], 225 | "stateMutability": "payable", 226 | "type": "function" 227 | }, 228 | { 229 | "inputs": [ 230 | { 231 | "internalType": "address", 232 | "name": "_l1Receiver", 233 | "type": "address" 234 | }, 235 | { 236 | "internalType": "bytes", 237 | "name": "_additionalData", 238 | "type": "bytes" 239 | } 240 | ], 241 | "name": "withdrawWithMessage", 242 | "outputs": [], 243 | "stateMutability": "payable", 244 | "type": "function" 245 | } 246 | ] 247 | } -------------------------------------------------------------------------------- /zksync2/manage_contracts/contract_abi/IL1ERC20Bridge.json: -------------------------------------------------------------------------------- 1 | { 2 | "abi": [ 3 | { 4 | "anonymous": false, 5 | "inputs": [ 6 | { 7 | "indexed": true, 8 | "internalType": "address", 9 | "name": "to", 10 | "type": "address" 11 | }, 12 | { 13 | "indexed": true, 14 | "internalType": "address", 15 | "name": "l1Token", 16 | "type": "address" 17 | }, 18 | { 19 | "indexed": false, 20 | "internalType": "uint256", 21 | "name": "amount", 22 | "type": "uint256" 23 | } 24 | ], 25 | "name": "ClaimedFailedDeposit", 26 | "type": "event" 27 | }, 28 | { 29 | "anonymous": false, 30 | "inputs": [ 31 | { 32 | "indexed": true, 33 | "internalType": "bytes32", 34 | "name": "l2DepositTxHash", 35 | "type": "bytes32" 36 | }, 37 | { 38 | "indexed": true, 39 | "internalType": "address", 40 | "name": "from", 41 | "type": "address" 42 | }, 43 | { 44 | "indexed": true, 45 | "internalType": "address", 46 | "name": "to", 47 | "type": "address" 48 | }, 49 | { 50 | "indexed": false, 51 | "internalType": "address", 52 | "name": "l1Token", 53 | "type": "address" 54 | }, 55 | { 56 | "indexed": false, 57 | "internalType": "uint256", 58 | "name": "amount", 59 | "type": "uint256" 60 | } 61 | ], 62 | "name": "DepositInitiated", 63 | "type": "event" 64 | }, 65 | { 66 | "anonymous": false, 67 | "inputs": [ 68 | { 69 | "indexed": true, 70 | "internalType": "address", 71 | "name": "to", 72 | "type": "address" 73 | }, 74 | { 75 | "indexed": true, 76 | "internalType": "address", 77 | "name": "l1Token", 78 | "type": "address" 79 | }, 80 | { 81 | "indexed": false, 82 | "internalType": "uint256", 83 | "name": "amount", 84 | "type": "uint256" 85 | } 86 | ], 87 | "name": "WithdrawalFinalized", 88 | "type": "event" 89 | }, 90 | { 91 | "inputs": [], 92 | "name": "SHARED_BRIDGE", 93 | "outputs": [ 94 | { 95 | "internalType": "contract IL1SharedBridge", 96 | "name": "", 97 | "type": "address" 98 | } 99 | ], 100 | "stateMutability": "view", 101 | "type": "function" 102 | }, 103 | { 104 | "inputs": [ 105 | { 106 | "internalType": "address", 107 | "name": "_depositSender", 108 | "type": "address" 109 | }, 110 | { 111 | "internalType": "address", 112 | "name": "_l1Token", 113 | "type": "address" 114 | }, 115 | { 116 | "internalType": "bytes32", 117 | "name": "_l2TxHash", 118 | "type": "bytes32" 119 | }, 120 | { 121 | "internalType": "uint256", 122 | "name": "_l2BatchNumber", 123 | "type": "uint256" 124 | }, 125 | { 126 | "internalType": "uint256", 127 | "name": "_l2MessageIndex", 128 | "type": "uint256" 129 | }, 130 | { 131 | "internalType": "uint16", 132 | "name": "_l2TxNumberInBatch", 133 | "type": "uint16" 134 | }, 135 | { 136 | "internalType": "bytes32[]", 137 | "name": "_merkleProof", 138 | "type": "bytes32[]" 139 | } 140 | ], 141 | "name": "claimFailedDeposit", 142 | "outputs": [], 143 | "stateMutability": "nonpayable", 144 | "type": "function" 145 | }, 146 | { 147 | "inputs": [ 148 | { 149 | "internalType": "address", 150 | "name": "_l2Receiver", 151 | "type": "address" 152 | }, 153 | { 154 | "internalType": "address", 155 | "name": "_l1Token", 156 | "type": "address" 157 | }, 158 | { 159 | "internalType": "uint256", 160 | "name": "_amount", 161 | "type": "uint256" 162 | }, 163 | { 164 | "internalType": "uint256", 165 | "name": "_l2TxGasLimit", 166 | "type": "uint256" 167 | }, 168 | { 169 | "internalType": "uint256", 170 | "name": "_l2TxGasPerPubdataByte", 171 | "type": "uint256" 172 | } 173 | ], 174 | "name": "deposit", 175 | "outputs": [ 176 | { 177 | "internalType": "bytes32", 178 | "name": "txHash", 179 | "type": "bytes32" 180 | } 181 | ], 182 | "stateMutability": "payable", 183 | "type": "function" 184 | }, 185 | { 186 | "inputs": [ 187 | { 188 | "internalType": "address", 189 | "name": "_l2Receiver", 190 | "type": "address" 191 | }, 192 | { 193 | "internalType": "address", 194 | "name": "_l1Token", 195 | "type": "address" 196 | }, 197 | { 198 | "internalType": "uint256", 199 | "name": "_amount", 200 | "type": "uint256" 201 | }, 202 | { 203 | "internalType": "uint256", 204 | "name": "_l2TxGasLimit", 205 | "type": "uint256" 206 | }, 207 | { 208 | "internalType": "uint256", 209 | "name": "_l2TxGasPerPubdataByte", 210 | "type": "uint256" 211 | }, 212 | { 213 | "internalType": "address", 214 | "name": "_refundRecipient", 215 | "type": "address" 216 | } 217 | ], 218 | "name": "deposit", 219 | "outputs": [ 220 | { 221 | "internalType": "bytes32", 222 | "name": "txHash", 223 | "type": "bytes32" 224 | } 225 | ], 226 | "stateMutability": "payable", 227 | "type": "function" 228 | }, 229 | { 230 | "inputs": [ 231 | { 232 | "internalType": "address", 233 | "name": "_account", 234 | "type": "address" 235 | }, 236 | { 237 | "internalType": "address", 238 | "name": "_l1Token", 239 | "type": "address" 240 | }, 241 | { 242 | "internalType": "bytes32", 243 | "name": "_depositL2TxHash", 244 | "type": "bytes32" 245 | } 246 | ], 247 | "name": "depositAmount", 248 | "outputs": [ 249 | { 250 | "internalType": "uint256", 251 | "name": "amount", 252 | "type": "uint256" 253 | } 254 | ], 255 | "stateMutability": "nonpayable", 256 | "type": "function" 257 | }, 258 | { 259 | "inputs": [ 260 | { 261 | "internalType": "uint256", 262 | "name": "_l2BatchNumber", 263 | "type": "uint256" 264 | }, 265 | { 266 | "internalType": "uint256", 267 | "name": "_l2MessageIndex", 268 | "type": "uint256" 269 | }, 270 | { 271 | "internalType": "uint16", 272 | "name": "_l2TxNumberInBatch", 273 | "type": "uint16" 274 | }, 275 | { 276 | "internalType": "bytes", 277 | "name": "_message", 278 | "type": "bytes" 279 | }, 280 | { 281 | "internalType": "bytes32[]", 282 | "name": "_merkleProof", 283 | "type": "bytes32[]" 284 | } 285 | ], 286 | "name": "finalizeWithdrawal", 287 | "outputs": [], 288 | "stateMutability": "nonpayable", 289 | "type": "function" 290 | }, 291 | { 292 | "inputs": [ 293 | { 294 | "internalType": "uint256", 295 | "name": "_l2BatchNumber", 296 | "type": "uint256" 297 | }, 298 | { 299 | "internalType": "uint256", 300 | "name": "_l2MessageIndex", 301 | "type": "uint256" 302 | } 303 | ], 304 | "name": "isWithdrawalFinalized", 305 | "outputs": [ 306 | { 307 | "internalType": "bool", 308 | "name": "", 309 | "type": "bool" 310 | } 311 | ], 312 | "stateMutability": "view", 313 | "type": "function" 314 | }, 315 | { 316 | "inputs": [], 317 | "name": "l2Bridge", 318 | "outputs": [ 319 | { 320 | "internalType": "address", 321 | "name": "", 322 | "type": "address" 323 | } 324 | ], 325 | "stateMutability": "view", 326 | "type": "function" 327 | }, 328 | { 329 | "inputs": [ 330 | { 331 | "internalType": "address", 332 | "name": "_l1Token", 333 | "type": "address" 334 | } 335 | ], 336 | "name": "l2TokenAddress", 337 | "outputs": [ 338 | { 339 | "internalType": "address", 340 | "name": "", 341 | "type": "address" 342 | } 343 | ], 344 | "stateMutability": "view", 345 | "type": "function" 346 | }, 347 | { 348 | "inputs": [], 349 | "name": "l2TokenBeacon", 350 | "outputs": [ 351 | { 352 | "internalType": "address", 353 | "name": "", 354 | "type": "address" 355 | } 356 | ], 357 | "stateMutability": "view", 358 | "type": "function" 359 | }, 360 | { 361 | "inputs": [ 362 | { 363 | "internalType": "address", 364 | "name": "_token", 365 | "type": "address" 366 | } 367 | ], 368 | "name": "transferTokenToSharedBridge", 369 | "outputs": [], 370 | "stateMutability": "nonpayable", 371 | "type": "function" 372 | } 373 | ] 374 | } -------------------------------------------------------------------------------- /zksync2/manage_contracts/contract_abi/IL1Messenger.json: -------------------------------------------------------------------------------- 1 | { 2 | "abi": [ 3 | { 4 | "anonymous": false, 5 | "inputs": [ 6 | { 7 | "indexed": false, 8 | "internalType": "bytes32", 9 | "name": "_bytecodeHash", 10 | "type": "bytes32" 11 | } 12 | ], 13 | "name": "BytecodeL1PublicationRequested", 14 | "type": "event" 15 | }, 16 | { 17 | "anonymous": false, 18 | "inputs": [ 19 | { 20 | "indexed": true, 21 | "internalType": "address", 22 | "name": "_sender", 23 | "type": "address" 24 | }, 25 | { 26 | "indexed": true, 27 | "internalType": "bytes32", 28 | "name": "_hash", 29 | "type": "bytes32" 30 | }, 31 | { 32 | "indexed": false, 33 | "internalType": "bytes", 34 | "name": "_message", 35 | "type": "bytes" 36 | } 37 | ], 38 | "name": "L1MessageSent", 39 | "type": "event" 40 | }, 41 | { 42 | "anonymous": false, 43 | "inputs": [ 44 | { 45 | "components": [ 46 | { 47 | "internalType": "uint8", 48 | "name": "l2ShardId", 49 | "type": "uint8" 50 | }, 51 | { 52 | "internalType": "bool", 53 | "name": "isService", 54 | "type": "bool" 55 | }, 56 | { 57 | "internalType": "uint16", 58 | "name": "txNumberInBlock", 59 | "type": "uint16" 60 | }, 61 | { 62 | "internalType": "address", 63 | "name": "sender", 64 | "type": "address" 65 | }, 66 | { 67 | "internalType": "bytes32", 68 | "name": "key", 69 | "type": "bytes32" 70 | }, 71 | { 72 | "internalType": "bytes32", 73 | "name": "value", 74 | "type": "bytes32" 75 | } 76 | ], 77 | "indexed": false, 78 | "internalType": "struct L2ToL1Log", 79 | "name": "_l2log", 80 | "type": "tuple" 81 | } 82 | ], 83 | "name": "L2ToL1LogSent", 84 | "type": "event" 85 | }, 86 | { 87 | "inputs": [ 88 | { 89 | "internalType": "bytes32", 90 | "name": "_bytecodeHash", 91 | "type": "bytes32" 92 | } 93 | ], 94 | "name": "requestBytecodeL1Publication", 95 | "outputs": [], 96 | "stateMutability": "nonpayable", 97 | "type": "function" 98 | }, 99 | { 100 | "inputs": [ 101 | { 102 | "internalType": "bool", 103 | "name": "_isService", 104 | "type": "bool" 105 | }, 106 | { 107 | "internalType": "bytes32", 108 | "name": "_key", 109 | "type": "bytes32" 110 | }, 111 | { 112 | "internalType": "bytes32", 113 | "name": "_value", 114 | "type": "bytes32" 115 | } 116 | ], 117 | "name": "sendL2ToL1Log", 118 | "outputs": [ 119 | { 120 | "internalType": "uint256", 121 | "name": "logIdInMerkleTree", 122 | "type": "uint256" 123 | } 124 | ], 125 | "stateMutability": "nonpayable", 126 | "type": "function" 127 | }, 128 | { 129 | "inputs": [ 130 | { 131 | "internalType": "bytes", 132 | "name": "_message", 133 | "type": "bytes" 134 | } 135 | ], 136 | "name": "sendToL1", 137 | "outputs": [ 138 | { 139 | "internalType": "bytes32", 140 | "name": "", 141 | "type": "bytes32" 142 | } 143 | ], 144 | "stateMutability": "nonpayable", 145 | "type": "function" 146 | } 147 | ] 148 | } -------------------------------------------------------------------------------- /zksync2/manage_contracts/contract_abi/IL2Bridge.json: -------------------------------------------------------------------------------- 1 | { 2 | "abi": [ 3 | { 4 | "inputs": [ 5 | { 6 | "internalType": "address", 7 | "name": "_l1Sender", 8 | "type": "address" 9 | }, 10 | { 11 | "internalType": "address", 12 | "name": "_l2Receiver", 13 | "type": "address" 14 | }, 15 | { 16 | "internalType": "address", 17 | "name": "_l1Token", 18 | "type": "address" 19 | }, 20 | { 21 | "internalType": "uint256", 22 | "name": "_amount", 23 | "type": "uint256" 24 | }, 25 | { 26 | "internalType": "bytes", 27 | "name": "_data", 28 | "type": "bytes" 29 | } 30 | ], 31 | "name": "finalizeDeposit", 32 | "outputs": [], 33 | "stateMutability": "nonpayable", 34 | "type": "function" 35 | }, 36 | { 37 | "inputs": [], 38 | "name": "l1Bridge", 39 | "outputs": [ 40 | { 41 | "internalType": "address", 42 | "name": "", 43 | "type": "address" 44 | } 45 | ], 46 | "stateMutability": "view", 47 | "type": "function" 48 | }, 49 | { 50 | "inputs": [ 51 | { 52 | "internalType": "address", 53 | "name": "_l2Token", 54 | "type": "address" 55 | } 56 | ], 57 | "name": "l1TokenAddress", 58 | "outputs": [ 59 | { 60 | "internalType": "address", 61 | "name": "", 62 | "type": "address" 63 | } 64 | ], 65 | "stateMutability": "view", 66 | "type": "function" 67 | }, 68 | { 69 | "inputs": [ 70 | { 71 | "internalType": "address", 72 | "name": "_l1Token", 73 | "type": "address" 74 | } 75 | ], 76 | "name": "l2TokenAddress", 77 | "outputs": [ 78 | { 79 | "internalType": "address", 80 | "name": "", 81 | "type": "address" 82 | } 83 | ], 84 | "stateMutability": "view", 85 | "type": "function" 86 | }, 87 | { 88 | "inputs": [ 89 | { 90 | "internalType": "address", 91 | "name": "_l1Receiver", 92 | "type": "address" 93 | }, 94 | { 95 | "internalType": "address", 96 | "name": "_l2Token", 97 | "type": "address" 98 | }, 99 | { 100 | "internalType": "uint256", 101 | "name": "_amount", 102 | "type": "uint256" 103 | } 104 | ], 105 | "name": "withdraw", 106 | "outputs": [], 107 | "stateMutability": "nonpayable", 108 | "type": "function" 109 | } 110 | ] 111 | } -------------------------------------------------------------------------------- /zksync2/manage_contracts/contract_abi/IL2SharedBridge.json: -------------------------------------------------------------------------------- 1 | { 2 | "abi": [ 3 | { 4 | "anonymous": false, 5 | "inputs": [ 6 | { 7 | "indexed": true, 8 | "internalType": "address", 9 | "name": "l1Sender", 10 | "type": "address" 11 | }, 12 | { 13 | "indexed": true, 14 | "internalType": "address", 15 | "name": "l2Receiver", 16 | "type": "address" 17 | }, 18 | { 19 | "indexed": true, 20 | "internalType": "address", 21 | "name": "l2Token", 22 | "type": "address" 23 | }, 24 | { 25 | "indexed": false, 26 | "internalType": "uint256", 27 | "name": "amount", 28 | "type": "uint256" 29 | } 30 | ], 31 | "name": "FinalizeDeposit", 32 | "type": "event" 33 | }, 34 | { 35 | "anonymous": false, 36 | "inputs": [ 37 | { 38 | "indexed": true, 39 | "internalType": "address", 40 | "name": "l2Sender", 41 | "type": "address" 42 | }, 43 | { 44 | "indexed": true, 45 | "internalType": "address", 46 | "name": "l1Receiver", 47 | "type": "address" 48 | }, 49 | { 50 | "indexed": true, 51 | "internalType": "address", 52 | "name": "l2Token", 53 | "type": "address" 54 | }, 55 | { 56 | "indexed": false, 57 | "internalType": "uint256", 58 | "name": "amount", 59 | "type": "uint256" 60 | } 61 | ], 62 | "name": "WithdrawalInitiated", 63 | "type": "event" 64 | }, 65 | { 66 | "inputs": [ 67 | { 68 | "internalType": "address", 69 | "name": "_l1Sender", 70 | "type": "address" 71 | }, 72 | { 73 | "internalType": "address", 74 | "name": "_l2Receiver", 75 | "type": "address" 76 | }, 77 | { 78 | "internalType": "address", 79 | "name": "_l1Token", 80 | "type": "address" 81 | }, 82 | { 83 | "internalType": "uint256", 84 | "name": "_amount", 85 | "type": "uint256" 86 | }, 87 | { 88 | "internalType": "bytes", 89 | "name": "_data", 90 | "type": "bytes" 91 | } 92 | ], 93 | "name": "finalizeDeposit", 94 | "outputs": [], 95 | "stateMutability": "nonpayable", 96 | "type": "function" 97 | }, 98 | { 99 | "inputs": [], 100 | "name": "l1Bridge", 101 | "outputs": [ 102 | { 103 | "internalType": "address", 104 | "name": "", 105 | "type": "address" 106 | } 107 | ], 108 | "stateMutability": "view", 109 | "type": "function" 110 | }, 111 | { 112 | "inputs": [], 113 | "name": "l1SharedBridge", 114 | "outputs": [ 115 | { 116 | "internalType": "address", 117 | "name": "", 118 | "type": "address" 119 | } 120 | ], 121 | "stateMutability": "view", 122 | "type": "function" 123 | }, 124 | { 125 | "inputs": [ 126 | { 127 | "internalType": "address", 128 | "name": "_l2Token", 129 | "type": "address" 130 | } 131 | ], 132 | "name": "l1TokenAddress", 133 | "outputs": [ 134 | { 135 | "internalType": "address", 136 | "name": "", 137 | "type": "address" 138 | } 139 | ], 140 | "stateMutability": "view", 141 | "type": "function" 142 | }, 143 | { 144 | "inputs": [ 145 | { 146 | "internalType": "address", 147 | "name": "_l1Token", 148 | "type": "address" 149 | } 150 | ], 151 | "name": "l2TokenAddress", 152 | "outputs": [ 153 | { 154 | "internalType": "address", 155 | "name": "", 156 | "type": "address" 157 | } 158 | ], 159 | "stateMutability": "view", 160 | "type": "function" 161 | }, 162 | { 163 | "inputs": [ 164 | { 165 | "internalType": "address", 166 | "name": "_l1Receiver", 167 | "type": "address" 168 | }, 169 | { 170 | "internalType": "address", 171 | "name": "_l2Token", 172 | "type": "address" 173 | }, 174 | { 175 | "internalType": "uint256", 176 | "name": "_amount", 177 | "type": "uint256" 178 | } 179 | ], 180 | "name": "withdraw", 181 | "outputs": [], 182 | "stateMutability": "nonpayable", 183 | "type": "function" 184 | } 185 | ] 186 | } -------------------------------------------------------------------------------- /zksync2/manage_contracts/contract_abi/INonceHolder.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "anonymous": false, 4 | "inputs": [ 5 | { 6 | "indexed": true, 7 | "internalType": "address", 8 | "name": "accountAddress", 9 | "type": "address" 10 | }, 11 | { 12 | "indexed": true, 13 | "internalType": "uint256", 14 | "name": "key", 15 | "type": "uint256" 16 | }, 17 | { 18 | "indexed": false, 19 | "internalType": "uint256", 20 | "name": "value", 21 | "type": "uint256" 22 | } 23 | ], 24 | "name": "ValueSetUnderNonce", 25 | "type": "event" 26 | }, 27 | { 28 | "inputs": [ 29 | { 30 | "internalType": "address", 31 | "name": "_address", 32 | "type": "address" 33 | } 34 | ], 35 | "name": "getDeploymentNonce", 36 | "outputs": [ 37 | { 38 | "internalType": "uint256", 39 | "name": "", 40 | "type": "uint256" 41 | } 42 | ], 43 | "stateMutability": "view", 44 | "type": "function" 45 | }, 46 | { 47 | "inputs": [ 48 | { 49 | "internalType": "address", 50 | "name": "_address", 51 | "type": "address" 52 | } 53 | ], 54 | "name": "getMinNonce", 55 | "outputs": [ 56 | { 57 | "internalType": "uint256", 58 | "name": "", 59 | "type": "uint256" 60 | } 61 | ], 62 | "stateMutability": "view", 63 | "type": "function" 64 | }, 65 | { 66 | "inputs": [ 67 | { 68 | "internalType": "address", 69 | "name": "_address", 70 | "type": "address" 71 | } 72 | ], 73 | "name": "getRawNonce", 74 | "outputs": [ 75 | { 76 | "internalType": "uint256", 77 | "name": "", 78 | "type": "uint256" 79 | } 80 | ], 81 | "stateMutability": "view", 82 | "type": "function" 83 | }, 84 | { 85 | "inputs": [ 86 | { 87 | "internalType": "uint256", 88 | "name": "_key", 89 | "type": "uint256" 90 | } 91 | ], 92 | "name": "getValueUnderNonce", 93 | "outputs": [ 94 | { 95 | "internalType": "uint256", 96 | "name": "", 97 | "type": "uint256" 98 | } 99 | ], 100 | "stateMutability": "view", 101 | "type": "function" 102 | }, 103 | { 104 | "inputs": [ 105 | { 106 | "internalType": "uint256", 107 | "name": "_value", 108 | "type": "uint256" 109 | } 110 | ], 111 | "name": "increaseMinNonce", 112 | "outputs": [ 113 | { 114 | "internalType": "uint256", 115 | "name": "", 116 | "type": "uint256" 117 | } 118 | ], 119 | "stateMutability": "nonpayable", 120 | "type": "function" 121 | }, 122 | { 123 | "inputs": [ 124 | { 125 | "internalType": "address", 126 | "name": "_address", 127 | "type": "address" 128 | } 129 | ], 130 | "name": "incrementDeploymentNonce", 131 | "outputs": [ 132 | { 133 | "internalType": "uint256", 134 | "name": "", 135 | "type": "uint256" 136 | } 137 | ], 138 | "stateMutability": "nonpayable", 139 | "type": "function" 140 | }, 141 | { 142 | "inputs": [ 143 | { 144 | "internalType": "uint256", 145 | "name": "_expectedNonce", 146 | "type": "uint256" 147 | } 148 | ], 149 | "name": "incrementMinNonceIfEquals", 150 | "outputs": [], 151 | "stateMutability": "nonpayable", 152 | "type": "function" 153 | }, 154 | { 155 | "inputs": [ 156 | { 157 | "internalType": "address", 158 | "name": "_address", 159 | "type": "address" 160 | }, 161 | { 162 | "internalType": "uint256", 163 | "name": "_nonce", 164 | "type": "uint256" 165 | } 166 | ], 167 | "name": "isNonceUsed", 168 | "outputs": [ 169 | { 170 | "internalType": "bool", 171 | "name": "", 172 | "type": "bool" 173 | } 174 | ], 175 | "stateMutability": "view", 176 | "type": "function" 177 | }, 178 | { 179 | "inputs": [ 180 | { 181 | "internalType": "uint256", 182 | "name": "_key", 183 | "type": "uint256" 184 | }, 185 | { 186 | "internalType": "uint256", 187 | "name": "_value", 188 | "type": "uint256" 189 | } 190 | ], 191 | "name": "setValueUnderNonce", 192 | "outputs": [], 193 | "stateMutability": "nonpayable", 194 | "type": "function" 195 | }, 196 | { 197 | "inputs": [ 198 | { 199 | "internalType": "address", 200 | "name": "_address", 201 | "type": "address" 202 | }, 203 | { 204 | "internalType": "uint256", 205 | "name": "_key", 206 | "type": "uint256" 207 | }, 208 | { 209 | "internalType": "bool", 210 | "name": "_shouldBeUsed", 211 | "type": "bool" 212 | } 213 | ], 214 | "name": "validateNonceUsage", 215 | "outputs": [], 216 | "stateMutability": "view", 217 | "type": "function" 218 | } 219 | ] -------------------------------------------------------------------------------- /zksync2/manage_contracts/contract_abi/IPaymasterFlow.json: -------------------------------------------------------------------------------- 1 | { 2 | "abi": [ 3 | { 4 | "inputs": [ 5 | { 6 | "internalType": "address", 7 | "name": "_token", 8 | "type": "address" 9 | }, 10 | { 11 | "internalType": "uint256", 12 | "name": "_minAllowance", 13 | "type": "uint256" 14 | }, 15 | { 16 | "internalType": "bytes", 17 | "name": "_innerInput", 18 | "type": "bytes" 19 | } 20 | ], 21 | "name": "approvalBased", 22 | "outputs": [], 23 | "stateMutability": "nonpayable", 24 | "type": "function" 25 | }, 26 | { 27 | "inputs": [ 28 | { 29 | "internalType": "bytes", 30 | "name": "input", 31 | "type": "bytes" 32 | } 33 | ], 34 | "name": "general", 35 | "outputs": [], 36 | "stateMutability": "nonpayable", 37 | "type": "function" 38 | } 39 | ] 40 | } -------------------------------------------------------------------------------- /zksync2/manage_contracts/contract_abi/ITestnetERC20Token.json: -------------------------------------------------------------------------------- 1 | { 2 | "abi": [ 3 | { 4 | "inputs": [], 5 | "name": "decimals", 6 | "outputs": [ 7 | { 8 | "internalType": "uint8", 9 | "name": "", 10 | "type": "uint8" 11 | } 12 | ], 13 | "stateMutability": "nonpayable", 14 | "type": "function" 15 | }, 16 | { 17 | "inputs": [ 18 | { 19 | "internalType": "address", 20 | "name": "_to", 21 | "type": "address" 22 | }, 23 | { 24 | "internalType": "uint256", 25 | "name": "_amount", 26 | "type": "uint256" 27 | } 28 | ], 29 | "name": "mint", 30 | "outputs": [ 31 | { 32 | "internalType": "bool", 33 | "name": "", 34 | "type": "bool" 35 | } 36 | ], 37 | "stateMutability": "nonpayable", 38 | "type": "function" 39 | } 40 | ] 41 | } -------------------------------------------------------------------------------- /zksync2/manage_contracts/contract_abi/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zksync-sdk/zksync2-python/a8118a7c1938a32c88ef2de3bea790b40278e26e/zksync2/manage_contracts/contract_abi/__init__.py -------------------------------------------------------------------------------- /zksync2/manage_contracts/contract_encoder_base.py: -------------------------------------------------------------------------------- 1 | import itertools 2 | import json 3 | from enum import Enum 4 | from pathlib import Path 5 | from typing import Any, Optional, cast, Tuple 6 | from eth_typing import HexStr 7 | from eth_utils import remove_0x_prefix 8 | from web3 import Web3 9 | from web3._utils.contracts import encode_abi 10 | 11 | 12 | class JsonConfiguration(Enum): 13 | COMBINED = "combined" 14 | STANDARD = "standard" 15 | 16 | 17 | class BaseContractEncoder: 18 | @classmethod 19 | def from_json( 20 | cls, 21 | web3: Web3, 22 | compiled_contract: Path, 23 | conf_type: JsonConfiguration = JsonConfiguration.COMBINED, 24 | ): 25 | with compiled_contract.open(mode="r") as json_f: 26 | data = json.load(json_f) 27 | if conf_type == JsonConfiguration.COMBINED: 28 | contracts = list() 29 | for contract_path, contract_data in data["contracts"].items(): 30 | # Check if 'abi' key exists 31 | if "abi" in contract_data and "bin" in contract_data: 32 | abi = contract_data["abi"] 33 | bin = contract_data["bin"] 34 | contracts.append(cls(web3, abi=abi, bytecode=bin)) 35 | 36 | return contracts 37 | else: 38 | return cls(web3, abi=data["abi"], bytecode=data["bytecode"]) 39 | 40 | def __init__(self, web3: Web3, abi, bytecode: Optional[bytes] = None): 41 | self.web3 = web3 42 | self.abi = abi 43 | if bytecode is None: 44 | self.instance_contract = self.web3.eth.contract(abi=self.abi) 45 | else: 46 | self.instance_contract = self.web3.eth.contract( 47 | abi=self.abi, bytecode=bytecode 48 | ) 49 | 50 | def encode_method(self, fn_name, args: tuple) -> HexStr: 51 | return self.instance_contract.encode_abi(fn_name, args) 52 | 53 | @property 54 | def contract(self): 55 | return self.instance_contract 56 | 57 | 58 | class ContractEncoder(BaseContractEncoder): 59 | def __init__(self, web3: Web3, abi, bytecode=None): 60 | super(ContractEncoder, self).__init__(web3, abi, bytecode) 61 | 62 | def encode_constructor(self, *args: Any, **kwargs: Any) -> bytes: 63 | contract = self.web3.eth.contract(abi=self.abi, bytecode=self.bytecode) 64 | constructor_abi = get_constructor_abi(contract.abi) 65 | 66 | if constructor_abi: 67 | if not args: 68 | args = tuple() 69 | if not kwargs: 70 | kwargs = {} 71 | arguments = merge_args_and_kwargs(constructor_abi["inputs"], args, kwargs) 72 | # INFO: it takes affect on the eth_estimate_gas, 73 | # it does not need the bytecode in the front of encoded arguments, see implementation of encode_abi 74 | # uncomment if it's fixed on ZkSync side 75 | # data = encode_abi(self.web3, constructor_abi, arguments, data=self.instance_contract.bytecode) 76 | data = encode_abi(self.web3, constructor_abi, arguments) 77 | data = bytes.fromhex(remove_0x_prefix(data)) 78 | else: 79 | data = self.instance_contract.bytecode 80 | return data 81 | 82 | @property 83 | def bytecode(self): 84 | return self.instance_contract.bytecode 85 | 86 | 87 | def merge_args_and_kwargs(abi_inputs, args, kwargs): 88 | if len(args) + len(kwargs) != len(abi_inputs): 89 | raise TypeError( 90 | f"Incorrect argument count. Expected '{len(abi_inputs)}'" 91 | f". Got '{len(args) + len(kwargs)}'" 92 | ) 93 | 94 | # If no keyword args were given, we don't need to align them 95 | if not kwargs: 96 | return cast(Tuple[Any, ...], args) 97 | 98 | kwarg_names = set(kwargs.keys()) 99 | sorted_arg_names = tuple(arg_abi["name"] for arg_abi in abi_inputs) 100 | args_as_kwargs = dict(zip(sorted_arg_names, args)) 101 | 102 | # Check for duplicate args 103 | duplicate_args = kwarg_names.intersection(args_as_kwargs.keys()) 104 | if duplicate_args: 105 | raise TypeError( 106 | f"{abi_inputs.get('name')}() got multiple values for argument(s) " 107 | f"'{', '.join(duplicate_args)}'" 108 | ) 109 | 110 | # Check for unknown args 111 | unknown_args = kwarg_names.difference(sorted_arg_names) 112 | if unknown_args: 113 | if abi_inputs.get("name"): 114 | raise TypeError( 115 | f"{abi_inputs.get('name')}() got unexpected keyword argument(s)" 116 | f" '{', '.join(unknown_args)}'" 117 | ) 118 | raise TypeError( 119 | f"Type: '{abi_inputs.get('type')}' got unexpected keyword argument(s)" 120 | f" '{', '.join(unknown_args)}'" 121 | ) 122 | 123 | # Sort args according to their position in the ABI and unzip them from their 124 | # names 125 | sorted_args = tuple( 126 | zip( 127 | *sorted( 128 | itertools.chain(kwargs.items(), args_as_kwargs.items()), 129 | key=lambda kv: sorted_arg_names.index(kv[0]), 130 | ) 131 | ) 132 | ) 133 | 134 | if sorted_args: 135 | return sorted_args[1] 136 | else: 137 | return tuple() 138 | 139 | 140 | def get_constructor_abi(contract_abi): 141 | for item in contract_abi: 142 | if item.get("type") == "constructor": 143 | return item 144 | return None 145 | -------------------------------------------------------------------------------- /zksync2/manage_contracts/deploy_addresses.py: -------------------------------------------------------------------------------- 1 | from enum import Enum 2 | from eth_typing import HexStr 3 | 4 | 5 | class ZkSyncAddresses(Enum): 6 | ETH_ADDRESS = HexStr("0x0000000000000000000000000000000000000000") 7 | CONTRACT_DEPLOYER_ADDRESS = HexStr("0x0000000000000000000000000000000000008006") 8 | NONCE_HOLDER_ADDRESS = HexStr("0x0000000000000000000000000000000000008003") 9 | MESSENGER_ADDRESS = HexStr("0x0000000000000000000000000000000000008008") 10 | -------------------------------------------------------------------------------- /zksync2/manage_contracts/paymaster_utils.py: -------------------------------------------------------------------------------- 1 | import importlib.resources as pkg_resources 2 | from web3 import Web3 3 | from eth_typing import HexStr 4 | import json 5 | from zksync2.manage_contracts import contract_abi 6 | from zksync2.manage_contracts.contract_encoder_base import BaseContractEncoder 7 | from zksync2.manage_contracts.utils import paymaster_flow_abi_default 8 | 9 | paymaster_flow_abi_cache = None 10 | 11 | 12 | class PaymasterFlowEncoder(BaseContractEncoder): 13 | def __init__(self, web3: Web3): 14 | super(PaymasterFlowEncoder, self).__init__( 15 | web3, abi=paymaster_flow_abi_default() 16 | ) 17 | 18 | def encode_approval_based( 19 | self, address: HexStr, min_allowance: int, inner_input: bytes 20 | ) -> HexStr: 21 | return self.encode_method( 22 | fn_name="approvalBased", args=(address, min_allowance, inner_input) 23 | ) 24 | 25 | def encode_general(self, inputs: bytes) -> HexStr: 26 | return self.encode_method(fn_name="general", args=tuple([inputs])) 27 | -------------------------------------------------------------------------------- /zksync2/manage_contracts/precompute_contract_deployer.py: -------------------------------------------------------------------------------- 1 | import importlib.resources as pkg_resources 2 | import json 3 | from typing import Optional 4 | 5 | from eth_typing import HexStr 6 | from eth_utils.crypto import keccak 7 | from web3 import Web3 8 | from web3.logs import DISCARD 9 | from web3.types import Nonce, TxReceipt 10 | 11 | from zksync2.core.types import AccountAbstractionVersion 12 | from zksync2.core.utils import pad_front_bytes, to_bytes, int_to_bytes, hash_byte_code 13 | from zksync2.manage_contracts import contract_abi 14 | from zksync2.manage_contracts.contract_encoder_base import BaseContractEncoder 15 | from zksync2.manage_contracts.utils import icontract_deployer_abi_default 16 | 17 | icontract_deployer_abi_cache = None 18 | 19 | 20 | class PrecomputeContractDeployer: 21 | DEFAULT_SALT = b"\0" * 32 22 | CREATE_FUNC = "create" 23 | CREATE2_FUNC = "create2" 24 | CREATE_ACCOUNT_FUNC = "createAccount" 25 | CREATE2_ACCOUNT_FUNC = "create2Account" 26 | MAX_BYTE_CODE_LENGTH = 2**16 27 | EMPTY_BYTES = b"" 28 | 29 | CREATE_PREFIX = keccak(text="zksyncCreate") 30 | CREATE2_PREFIX = keccak(text="zksyncCreate2") 31 | 32 | def __init__(self, web3: Web3, abi: Optional[dict] = None): 33 | self.web3 = web3 34 | if abi is None: 35 | abi = icontract_deployer_abi_default() 36 | self.contract_encoder = BaseContractEncoder(self.web3, abi) 37 | 38 | def encode_create2( 39 | self, 40 | bytecode: bytes, 41 | call_data: Optional[bytes] = None, 42 | salt: Optional[bytes] = None, 43 | ) -> HexStr: 44 | if salt is None: 45 | salt = self.DEFAULT_SALT 46 | if call_data is None: 47 | call_data = self.EMPTY_BYTES 48 | 49 | if len(salt) != 32: 50 | raise OverflowError("Salt data must be 32 length") 51 | 52 | bytecode_hash = hash_byte_code(bytecode) 53 | args = salt, bytecode_hash, call_data 54 | 55 | return self.contract_encoder.encode_method(fn_name=self.CREATE2_FUNC, args=args) 56 | 57 | def encode_create( 58 | self, bytecode: bytes, call_data: Optional[bytes] = None 59 | ) -> HexStr: 60 | if call_data is None: 61 | call_data = self.EMPTY_BYTES 62 | 63 | bytecode_hash = hash_byte_code(bytecode) 64 | args = self.DEFAULT_SALT, bytecode_hash, call_data 65 | 66 | return self.contract_encoder.encode_method(fn_name=self.CREATE_FUNC, args=args) 67 | 68 | def encode_create2_account( 69 | self, 70 | bytecode: bytes, 71 | call_data: Optional[bytes] = None, 72 | salt: Optional[bytes] = None, 73 | version: AccountAbstractionVersion = AccountAbstractionVersion.VERSION_1, 74 | ) -> HexStr: 75 | if salt is None: 76 | salt = self.DEFAULT_SALT 77 | if call_data is None: 78 | call_data = self.EMPTY_BYTES 79 | 80 | if len(salt) != 32: 81 | raise OverflowError("Salt data must be 32 length") 82 | 83 | bytecode_hash = hash_byte_code(bytecode) 84 | args = salt, bytecode_hash, call_data, version.value 85 | 86 | return self.contract_encoder.encode_method( 87 | fn_name=self.CREATE2_ACCOUNT_FUNC, args=args 88 | ) 89 | 90 | def encode_create_account( 91 | self, 92 | bytecode: bytes, 93 | call_data: Optional[bytes] = None, 94 | version: AccountAbstractionVersion = AccountAbstractionVersion.VERSION_1, 95 | ) -> HexStr: 96 | if call_data is None: 97 | call_data = self.EMPTY_BYTES 98 | 99 | bytecode_hash = hash_byte_code(bytecode) 100 | args = self.DEFAULT_SALT, bytecode_hash, call_data, version.value 101 | 102 | return self.contract_encoder.encode_method( 103 | fn_name=self.CREATE_ACCOUNT_FUNC, args=args 104 | ) 105 | 106 | def compute_l2_create_address(self, sender: HexStr, nonce: Nonce) -> HexStr: 107 | sender_bytes = to_bytes(sender) 108 | sender_bytes = pad_front_bytes(sender_bytes, 32) 109 | nonce = int_to_bytes(nonce) 110 | nonce_bytes = pad_front_bytes(nonce, 32) 111 | result = self.CREATE_PREFIX + sender_bytes + nonce_bytes 112 | sha_result = keccak(result) 113 | address = sha_result[12:] 114 | address = "0x" + address.hex() 115 | return HexStr(Web3.to_checksum_address(address)) 116 | 117 | def compute_l2_create2_address( 118 | self, sender: HexStr, bytecode: bytes, constructor: bytes, salt: bytes 119 | ) -> HexStr: 120 | if len(salt) != 32: 121 | raise OverflowError("Salt data must be 32 length") 122 | 123 | sender_bytes = to_bytes(sender) 124 | sender_bytes = pad_front_bytes(sender_bytes, 32) 125 | bytecode_hash = hash_byte_code(bytecode) 126 | ctor_hash = keccak(constructor) 127 | result = self.CREATE2_PREFIX + sender_bytes + salt + bytecode_hash + ctor_hash 128 | sha_result = keccak(result) 129 | address = sha_result[12:] 130 | address = "0x" + address.hex() 131 | return HexStr(Web3.to_checksum_address(address)) 132 | 133 | def extract_contract_address(self, receipt: TxReceipt) -> HexStr: 134 | result = ( 135 | self.contract_encoder.contract.events.ContractDeployed().process_receipt( 136 | receipt, errors=DISCARD 137 | ) 138 | ) 139 | entry = result[1]["args"] 140 | addr = entry["contractAddress"] 141 | return addr 142 | -------------------------------------------------------------------------------- /zksync2/manage_contracts/utils.py: -------------------------------------------------------------------------------- 1 | import importlib.resources as pkg_resources 2 | import json 3 | from typing import Optional 4 | 5 | from web3 import Web3 6 | 7 | from zksync2.manage_contracts import contract_abi 8 | from zksync2.manage_contracts.contract_encoder_base import BaseContractEncoder 9 | 10 | zksync_abi_cache = None 11 | icontract_deployer_abi_cache = None 12 | paymaster_flow_abi_cache = None 13 | nonce_holder_abi_cache = None 14 | l2_bridge_abi_cache = None 15 | l1_bridge_abi_cache = None 16 | eth_token_abi_cache = None 17 | erc_20_abi_cache = None 18 | test_net_erc_20_abi_cache = None 19 | l1_shared_bridge_abi_cache = None 20 | l2_shared_bridge_abi_cache = None 21 | bridgehub_abi_cache = None 22 | zksync_hyperchain_cache = None 23 | 24 | 25 | def zksync_abi_default(): 26 | global zksync_abi_cache 27 | 28 | if zksync_abi_cache is None: 29 | with pkg_resources.path(contract_abi, "IZkSync.json") as p: 30 | with p.open(mode="r") as json_file: 31 | data = json.load(json_file) 32 | zksync_abi_cache = data["abi"] 33 | return zksync_abi_cache 34 | 35 | 36 | def icontract_deployer_abi_default(): 37 | global icontract_deployer_abi_cache 38 | 39 | if icontract_deployer_abi_cache is None: 40 | with pkg_resources.path(contract_abi, "IContractDeployer.json") as p: 41 | with p.open(mode="r") as json_file: 42 | data = json.load(json_file) 43 | icontract_deployer_abi_cache = data["abi"] 44 | return icontract_deployer_abi_cache 45 | 46 | 47 | def paymaster_flow_abi_default(): 48 | global paymaster_flow_abi_cache 49 | 50 | if paymaster_flow_abi_cache is None: 51 | with pkg_resources.path(contract_abi, "IPaymasterFlow.json") as p: 52 | with p.open(mode="r") as json_file: 53 | data = json.load(json_file) 54 | paymaster_flow_abi_cache = data["abi"] 55 | return paymaster_flow_abi_cache 56 | 57 | 58 | def nonce_holder_abi_default(): 59 | global nonce_holder_abi_cache 60 | 61 | if nonce_holder_abi_cache is None: 62 | with pkg_resources.path(contract_abi, "INonceHolder.json") as p: 63 | with p.open(mode="r") as json_file: 64 | nonce_holder_abi_cache = json.load(json_file) 65 | return nonce_holder_abi_cache 66 | 67 | 68 | def l2_bridge_abi_default(): 69 | global l2_bridge_abi_cache 70 | 71 | if l2_bridge_abi_cache is None: 72 | with pkg_resources.path(contract_abi, "IL2Bridge.json") as p: 73 | with p.open(mode="r") as json_file: 74 | data = json.load(json_file) 75 | l2_bridge_abi_cache = data["abi"] 76 | return l2_bridge_abi_cache 77 | 78 | 79 | def l1_bridge_abi_default(): 80 | global l1_bridge_abi_cache 81 | 82 | if l1_bridge_abi_cache is None: 83 | with pkg_resources.path(contract_abi, "IL1Bridge.json") as p: 84 | with p.open(mode="r") as json_file: 85 | data = json.load(json_file) 86 | l1_bridge_abi_cache = data["abi"] 87 | return l1_bridge_abi_cache 88 | 89 | 90 | def bridgehub_abi_default(): 91 | global bridgehub_abi_cache 92 | 93 | if bridgehub_abi_cache is None: 94 | with pkg_resources.path(contract_abi, "IBridgehub.json") as p: 95 | with p.open(mode="r") as json_file: 96 | data = json.load(json_file) 97 | bridgehub_abi_cache = data["abi"] 98 | return bridgehub_abi_cache 99 | 100 | 101 | def l1_shared_bridge_abi_default(): 102 | global l1_shared_bridge_abi_cache 103 | 104 | if l1_shared_bridge_abi_cache is None: 105 | with pkg_resources.path(contract_abi, "IL1SharedBridge.json") as p: 106 | with p.open(mode="r") as json_file: 107 | data = json.load(json_file) 108 | l1_shared_bridge_abi_cache = data["abi"] 109 | return l1_shared_bridge_abi_cache 110 | 111 | 112 | def l2_shared_bridge_abi_default(): 113 | global l2_shared_bridge_abi_cache 114 | 115 | if l2_shared_bridge_abi_cache is None: 116 | with pkg_resources.path(contract_abi, "IL2SharedBridge.json") as p: 117 | with p.open(mode="r") as json_file: 118 | data = json.load(json_file) 119 | l2_shared_bridge_abi_cache = data["abi"] 120 | return l2_shared_bridge_abi_cache 121 | 122 | 123 | def eth_token_abi_default(): 124 | global eth_token_abi_cache 125 | 126 | if eth_token_abi_cache is None: 127 | with pkg_resources.path(contract_abi, "IEthToken.json") as p: 128 | with p.open(mode="r") as json_file: 129 | data = json.load(json_file) 130 | eth_token_abi_cache = data["abi"] 131 | return eth_token_abi_cache 132 | 133 | 134 | def get_erc20_abi(): 135 | global erc_20_abi_cache 136 | 137 | if erc_20_abi_cache is None: 138 | with pkg_resources.path(contract_abi, "IERC20.json") as p: 139 | with p.open(mode="r") as json_file: 140 | data = json.load(json_file) 141 | erc_20_abi_cache = data["abi"] 142 | return erc_20_abi_cache 143 | 144 | 145 | def get_test_net_erc20_token(): 146 | global test_net_erc_20_abi_cache 147 | 148 | if test_net_erc_20_abi_cache is None: 149 | with pkg_resources.path(contract_abi, "ITestnetERC20Token.json") as p: 150 | with p.open(mode="r") as json_file: 151 | data = json.load(json_file) 152 | test_net_erc_20_abi_cache = data["abi"] 153 | return test_net_erc_20_abi_cache 154 | 155 | 156 | def get_zksync_hyperchain(): 157 | global zksync_hyperchain_cache 158 | 159 | if zksync_hyperchain_cache is None: 160 | with pkg_resources.path(contract_abi, "IZkSyncHyperchain.json") as p: 161 | with p.open(mode="r") as json_file: 162 | data = json.load(json_file) 163 | zksync_hyperchain_cache = data["abi"] 164 | return zksync_hyperchain_cache 165 | 166 | 167 | class ERC20Encoder(BaseContractEncoder): 168 | def __init__(self, web3: Web3, abi: Optional[dict] = None): 169 | if abi is None: 170 | abi = get_erc20_abi() 171 | super(ERC20Encoder, self).__init__(web3, abi) 172 | -------------------------------------------------------------------------------- /zksync2/module/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zksync-sdk/zksync2-python/a8118a7c1938a32c88ef2de3bea790b40278e26e/zksync2/module/__init__.py -------------------------------------------------------------------------------- /zksync2/module/middleware.py: -------------------------------------------------------------------------------- 1 | from web3.middleware import Web3Middleware 2 | 3 | 4 | class ZkSyncMiddlewareBuilder(Web3Middleware): 5 | def wrap_make_request(self, make_request): 6 | def middleware(method, params): 7 | return make_request(method, params) 8 | 9 | return middleware 10 | -------------------------------------------------------------------------------- /zksync2/module/module_builder.py: -------------------------------------------------------------------------------- 1 | from typing import Union 2 | 3 | from eth_typing import URI 4 | from web3 import Web3 5 | from web3._utils.module import attach_modules 6 | 7 | from zksync2.module.zksync_module import ZkSync 8 | from zksync2.module.zksync_provider import ZkSyncProvider 9 | 10 | 11 | class ZkWeb3(Web3): 12 | zksync: ZkSync 13 | 14 | def __init__(self, provider): 15 | super().__init__(provider) 16 | # Attach the zksync module 17 | attach_modules(self, {"zksync": (ZkSync,)}) 18 | 19 | 20 | class ZkSyncBuilder: 21 | @classmethod 22 | def build(cls, url: Union[URI, str]) -> ZkWeb3: 23 | zksync_provider = ZkSyncProvider(url) 24 | web3_module = ZkWeb3(zksync_provider) 25 | return web3_module 26 | -------------------------------------------------------------------------------- /zksync2/module/request_types.py: -------------------------------------------------------------------------------- 1 | from enum import Enum 2 | from dataclasses import dataclass 3 | from typing import List, Optional, TypedDict 4 | 5 | from eth_typing import HexStr 6 | from web3.types import AccessList 7 | from zksync2.core.types import PaymasterParams 8 | 9 | 10 | @dataclass 11 | class EIP712Meta: 12 | # GAS_PER_PUB_DATA_DEFAULT = 16 * 10000 13 | # GAS_PER_PUB_DATA_DEFAULT = 20 * 10000 14 | GAS_PER_PUB_DATA_DEFAULT = 50000 15 | 16 | gas_per_pub_data: int = GAS_PER_PUB_DATA_DEFAULT 17 | custom_signature: Optional[bytes] = None 18 | factory_deps: Optional[List[bytes]] = None 19 | paymaster_params: Optional[PaymasterParams] = None 20 | 21 | 22 | Transaction = TypedDict( 23 | "Transaction", 24 | { 25 | "chain_id": int, 26 | "nonce": int, 27 | "from": HexStr, 28 | "to": HexStr, 29 | "gas": int, 30 | "maxFeePerGas": int, 31 | "maxPriorityFeePerGas": int, 32 | "value": int, 33 | "data": HexStr, 34 | "type": int, 35 | "accessList": Optional[AccessList], 36 | "eip712Meta": EIP712Meta, 37 | }, 38 | total=False, 39 | ) 40 | 41 | 42 | class TransactionType(Enum): 43 | EIP_712_TX_TYPE = 113 44 | -------------------------------------------------------------------------------- /zksync2/module/response_types.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | from decimal import Decimal 3 | from typing import TypedDict, NewType, Dict, List 4 | from eth_typing import HexStr 5 | from web3.types import TxData 6 | from zksync2.core.types import Token, VmDebugTrace, Fee 7 | 8 | ZksAccountBalances = Dict[str, int] 9 | 10 | ZksBridgeAddresses = TypedDict( 11 | "ZksBridgeAddresses", 12 | { 13 | "l1EthDefaultBridge": HexStr, 14 | "l2EthDefaultBridge": HexStr, 15 | "l1Erc20DefaultBridge": HexStr, 16 | "l2Erc20DefaultBridge": HexStr, 17 | }, 18 | ) 19 | 20 | ZksContractDebugInfo = TypedDict( 21 | "ZksContractDebugInfo", {"assemblyCode": HexStr, "pcLineMapping": Dict[int, int]} 22 | ) 23 | 24 | ZksBlockRange = TypedDict("ZksBlockRange", {"beginning": int, "end": int}) 25 | 26 | ZksBaseSystemContractsHashes = TypedDict( 27 | "ZksBaseSystemContractsHashes", {"bootloader": str, "defaultAa": str} 28 | ) 29 | ZksBatchDetails = TypedDict( 30 | "ZksBatchDetails", 31 | { 32 | "baseSystemContractsHashes": ZksBaseSystemContractsHashes, 33 | "commitTxHash": str, 34 | "committedAt": datetime, 35 | "executeTxHash": str, 36 | "executedAt": datetime, 37 | "l1GasPrice": int, 38 | "l1TxCount": int, 39 | "l2FairGasPrice": int, 40 | "l2TxCount": int, 41 | "number": int, 42 | "proveTxHash": str, 43 | "provenAt": datetime, 44 | "rootHash": str, 45 | "status": str, 46 | "timestamp": int, 47 | }, 48 | ) 49 | 50 | ZksBlockDetails = TypedDict( 51 | "ZksBlockDetails", 52 | { 53 | "commitTxHash": str, 54 | "committedAt": datetime, 55 | "executeTxHash": str, 56 | "executedAt": datetime, 57 | "l1TxCount": int, 58 | "l2TxCount": int, 59 | "number": int, 60 | "proveTxHash": str, 61 | "provenAt": datetime, 62 | "rootHash": str, 63 | "status": str, 64 | "timestamp": int, 65 | }, 66 | ) 67 | 68 | ZksTransactionDetails = TypedDict( 69 | "ZksTransactionDetails", 70 | { 71 | "ethCommitTxHash": str, 72 | "ethExecuteTxHash": datetime, 73 | "ethProveTxHash": str, 74 | "fee": int, 75 | "initiatorAddress": str, 76 | "isL1Originated": bool, 77 | "receivedAt": datetime, 78 | "status": str, 79 | }, 80 | ) 81 | 82 | ZksL1ToL2Log = TypedDict( 83 | "ZksL1ToL2Log", 84 | { 85 | "blockHash": HexStr, 86 | "blockNumber": HexStr, 87 | "l1BatchNumber": HexStr, 88 | "transactionIndex": HexStr, 89 | "transactionHash": HexStr, 90 | "transactionLogIndex": HexStr, 91 | "shardId": HexStr, 92 | "isService": bool, 93 | "sender": HexStr, 94 | "key": HexStr, 95 | "value": HexStr, 96 | "logIndex": HexStr, 97 | }, 98 | ) 99 | 100 | ZksTransactionReceipt = TypedDict( 101 | "ZksTransactionReceipt", 102 | { 103 | "from": HexStr, 104 | "to": HexStr, 105 | "blockNumber": int, 106 | "l1BatchTxIndex": HexStr, 107 | "l2ToL1Logs": List[ZksL1ToL2Log], 108 | }, 109 | ) 110 | 111 | ZksEstimateFee = NewType("ZksEstimateFee", Fee) 112 | ZksIsTokenLiquid = NewType("ZksIsTokenLiquid", bool) 113 | ZksL1ChainId = NewType("ZksL1ChainId", int) 114 | ZksL1BatchNumber = NewType("ZksL1BatchNumber", int) 115 | ZksMainContract = HexStr 116 | ZksBaseToken = HexStr 117 | ZksSetContractDebugInfoResult = NewType("ZksSetContractDebugInfoResult", bool) 118 | ZksTokenPrice = NewType("ZksTokenPrice", Decimal) 119 | ZksTokens = NewType("ZksTokens", List[Token]) 120 | ZksTransactions = NewType("ZksTransactions", List[TxData]) 121 | ZksTransactionTrace = NewType("ZksTransactionTrace", VmDebugTrace) 122 | -------------------------------------------------------------------------------- /zksync2/module/zksync_provider.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from typing import Union, Optional, Any 3 | from web3 import HTTPProvider 4 | from eth_typing import URI 5 | from web3.types import RPCEndpoint, RPCResponse 6 | 7 | 8 | class ZkSyncProvider(HTTPProvider): 9 | logger = logging.getLogger("ZkSyncProvider") 10 | 11 | def __init__(self, url: Optional[Union[URI, str]]): 12 | super(ZkSyncProvider, self).__init__(url, request_kwargs={"timeout": 1000}) 13 | 14 | def make_request(self, method: RPCEndpoint, params: Any) -> RPCResponse: 15 | self.logger.debug(f"make_request: {method}, params : {params}") 16 | response = HTTPProvider.make_request(self, method, params) 17 | return response 18 | -------------------------------------------------------------------------------- /zksync2/signer/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zksync-sdk/zksync2-python/a8118a7c1938a32c88ef2de3bea790b40278e26e/zksync2/signer/__init__.py -------------------------------------------------------------------------------- /zksync2/signer/eth_signer.py: -------------------------------------------------------------------------------- 1 | from abc import abstractmethod, ABC 2 | 3 | import web3 4 | from eth_account.datastructures import SignedMessage 5 | from eth_account.messages import encode_defunct, SignableMessage 6 | from eth_account.signers.base import BaseAccount 7 | from eth_typing import ChecksumAddress, HexStr 8 | from eth_utils import keccak 9 | 10 | from zksync2.eip712 import make_domain, EIP712Struct 11 | 12 | 13 | class EthSignerBase: 14 | @abstractmethod 15 | def sign_typed_data(self, typed_data: EIP712Struct, domain=None) -> SignedMessage: 16 | raise NotImplemented 17 | 18 | @abstractmethod 19 | def verify_typed_data(self, sig: HexStr, typed_data: EIP712Struct) -> bool: 20 | raise NotImplemented 21 | 22 | 23 | class PrivateKeyEthSigner(EthSignerBase, ABC): 24 | _NAME = "zkSync" 25 | _VERSION = "2" 26 | 27 | def __init__(self, creds: BaseAccount, chain_id: int): 28 | self.credentials = creds 29 | self.chain_id = chain_id 30 | self.default_domain = make_domain( 31 | name=self._NAME, version=self._VERSION, chainId=self.chain_id 32 | ) 33 | 34 | @staticmethod 35 | def get_default_domain(chain_id: int): 36 | return make_domain( 37 | name=PrivateKeyEthSigner._NAME, 38 | version=PrivateKeyEthSigner._VERSION, 39 | chainId=chain_id, 40 | ) 41 | 42 | @property 43 | def address(self) -> ChecksumAddress: 44 | return self.credentials.address 45 | 46 | @property 47 | def domain(self): 48 | return self.default_domain 49 | 50 | def typed_data_to_signed_bytes( 51 | self, typed_data: EIP712Struct, domain=None 52 | ) -> SignableMessage: 53 | d = domain 54 | if d is None: 55 | d = self.domain 56 | msg = typed_data.signable_bytes(d) 57 | return encode_defunct(msg) 58 | 59 | def sign_typed_data(self, typed_data: EIP712Struct, domain=None) -> SignedMessage: 60 | singable_message = self.typed_data_to_signed_bytes(typed_data, domain) 61 | msg_hash = keccak(singable_message.body) 62 | return self.credentials.unsafe_sign_hash(msg_hash) 63 | 64 | def verify_typed_data( 65 | self, sig: HexStr, typed_data: EIP712Struct, domain=None 66 | ) -> bool: 67 | singable_message = self.typed_data_to_signed_bytes(typed_data, domain) 68 | msg_hash = keccak(singable_message.body) 69 | address = web3.Account._recover_hash(message_hash=msg_hash, signature=sig) 70 | return address.lower() == self.address.lower() 71 | 72 | def sign_message(self, message: bytes) -> SignedMessage: 73 | msg_hash = keccak(message) 74 | return self.credentials.unsafe_sign_hash(msg_hash) 75 | -------------------------------------------------------------------------------- /zksync2/transaction/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zksync-sdk/zksync2-python/a8118a7c1938a32c88ef2de3bea790b40278e26e/zksync2/transaction/__init__.py -------------------------------------------------------------------------------- /zksync2/transaction/transaction712.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | from typing import Union, Optional 3 | import rlp 4 | from eth_account.datastructures import SignedMessage 5 | from eth_typing import ChecksumAddress, HexStr 6 | from eth_utils import remove_0x_prefix 7 | from rlp.sedes import big_endian_int, binary 8 | from rlp.sedes import List as rlpList 9 | from web3.types import Nonce 10 | from zksync2.module.request_types import EIP712Meta, Transaction as ZkTx 11 | 12 | from zksync2.eip712 import EIP712Struct, Address, Uint, Bytes, Array 13 | from zksync2.core.utils import to_bytes, hash_byte_code, encode_address, int_to_bytes 14 | 15 | DynamicBytes = Bytes(0) 16 | 17 | 18 | @dataclass 19 | class Transaction712: 20 | EIP_712_TX_TYPE = 113 21 | 22 | chain_id: int 23 | nonce: Nonce 24 | gas_limit: int 25 | to: Union[Address, ChecksumAddress, str] 26 | value: int 27 | data: Union[bytes, HexStr] 28 | maxPriorityFeePerGas: int 29 | maxFeePerGas: int 30 | from_: Union[bytes, HexStr] 31 | meta: EIP712Meta 32 | 33 | def encode(self, signature: Optional[SignedMessage] = None) -> bytes: 34 | factory_deps_data = [] 35 | factory_deps_elements = None 36 | factory_deps = self.meta.factory_deps 37 | if factory_deps is not None and len(factory_deps) > 0: 38 | factory_deps_data = factory_deps 39 | factory_deps_elements = [binary for _ in range(len(factory_deps_data))] 40 | 41 | paymaster_params_data = [] 42 | paymaster_params_elements = None 43 | paymaster_params = self.meta.paymaster_params 44 | if ( 45 | paymaster_params is not None 46 | and paymaster_params.paymaster is not None 47 | and paymaster_params.paymaster_input is not None 48 | ): 49 | paymaster_params_data = [ 50 | bytes.fromhex(remove_0x_prefix(paymaster_params.paymaster)), 51 | paymaster_params.paymaster_input, 52 | ] 53 | paymaster_params_elements = [binary, binary] 54 | 55 | class InternalRepresentation(rlp.Serializable): 56 | fields = [ 57 | ("nonce", big_endian_int), 58 | ("maxPriorityFeePerGas", big_endian_int), 59 | ("maxFeePerGas", big_endian_int), 60 | ("gasLimit", big_endian_int), 61 | ("to", binary), 62 | ("value", big_endian_int), 63 | ("data", binary), 64 | ("chain_id", big_endian_int), 65 | ("unknown1", binary), 66 | ("unknown2", binary), 67 | ("chain_id2", big_endian_int), 68 | ("from", binary), 69 | ("gasPerPubdata", big_endian_int), 70 | ("factoryDeps", rlpList(elements=factory_deps_elements, strict=False)), 71 | ("signature", binary), 72 | ( 73 | "paymaster_params", 74 | rlpList(elements=paymaster_params_elements, strict=False), 75 | ), 76 | ] 77 | 78 | custom_signature = self.meta.custom_signature 79 | if custom_signature is not None: 80 | rlp_signature = custom_signature 81 | elif signature is not None: 82 | rlp_signature = signature.signature 83 | else: 84 | raise RuntimeError("Custom signature and signature can't be None both") 85 | 86 | representation_params = { 87 | "nonce": self.nonce, 88 | "maxPriorityFeePerGas": self.maxPriorityFeePerGas, 89 | "maxFeePerGas": self.maxFeePerGas, 90 | "gasLimit": self.gas_limit, 91 | "to": encode_address(self.to), 92 | "value": self.value, 93 | "data": to_bytes(self.data), 94 | "chain_id": self.chain_id, 95 | "unknown1": b"", 96 | "unknown2": b"", 97 | "chain_id2": self.chain_id, 98 | "from": encode_address(self.from_), 99 | "gasPerPubdata": self.meta.gas_per_pub_data, 100 | "factoryDeps": factory_deps_data, 101 | "signature": rlp_signature, 102 | "paymaster_params": paymaster_params_data, 103 | } 104 | representation = InternalRepresentation(**representation_params) 105 | encoded_rlp = rlp.encode(representation, infer_serializer=True, cache=False) 106 | return int_to_bytes(self.EIP_712_TX_TYPE) + encoded_rlp 107 | 108 | def to_eip712_struct(self) -> EIP712Struct: 109 | class Transaction(EIP712Struct): 110 | pass 111 | 112 | paymaster: int = 0 113 | paymaster_params = self.meta.paymaster_params 114 | if paymaster_params is not None and paymaster_params.paymaster is not None: 115 | paymaster = int(paymaster_params.paymaster, 16) 116 | 117 | data = to_bytes(self.data) 118 | 119 | factory_deps = self.meta.factory_deps 120 | factory_deps_hashes = b"" 121 | if factory_deps is not None and len(factory_deps): 122 | factory_deps_hashes = tuple( 123 | [hash_byte_code(bytecode) for bytecode in factory_deps] 124 | ) 125 | 126 | setattr(Transaction, "txType", Uint(256)) 127 | setattr(Transaction, "from", Uint(256)) 128 | setattr(Transaction, "to", Uint(256)) 129 | setattr(Transaction, "gasLimit", Uint(256)) 130 | setattr(Transaction, "gasPerPubdataByteLimit", Uint(256)) 131 | setattr(Transaction, "maxFeePerGas", Uint(256)) 132 | setattr(Transaction, "maxPriorityFeePerGas", Uint(256)) 133 | setattr(Transaction, "paymaster", Uint(256)) 134 | setattr(Transaction, "nonce", Uint(256)) 135 | setattr(Transaction, "value", Uint(256)) 136 | setattr(Transaction, "data", DynamicBytes) 137 | setattr(Transaction, "factoryDeps", Array(Bytes(32))) 138 | setattr(Transaction, "paymasterInput", DynamicBytes) 139 | 140 | paymaster_input = b"" 141 | if ( 142 | paymaster_params is not None 143 | and paymaster_params.paymaster_input is not None 144 | ): 145 | paymaster_input = paymaster_params.paymaster_input 146 | 147 | kwargs = { 148 | "txType": self.EIP_712_TX_TYPE, 149 | "from": int(self.from_, 16), 150 | "to": int(self.to, 16), 151 | "gasLimit": self.gas_limit, 152 | "gasPerPubdataByteLimit": self.meta.gas_per_pub_data, 153 | "maxFeePerGas": self.maxFeePerGas, 154 | "maxPriorityFeePerGas": self.maxPriorityFeePerGas, 155 | "paymaster": paymaster, 156 | "nonce": self.nonce, 157 | "value": self.value, 158 | "data": data, 159 | "factoryDeps": factory_deps_hashes, 160 | "paymasterInput": paymaster_input, 161 | } 162 | return Transaction(**kwargs) 163 | 164 | def to_zk_transaction(self): 165 | kwargs = { 166 | "chain_id": self.chain_id, 167 | "nonce": self.nonce, 168 | "from": self.from_, 169 | "to": self.to, 170 | "gas": hex(self.gas_limit), 171 | "maxFeePerGas": hex(self.maxFeePerGas), 172 | "maxPriorityFeePerGas": hex(self.maxPriorityFeePerGas), 173 | "value": self.value, 174 | "data": self.data, 175 | "type": hex(self.EIP_712_TX_TYPE), 176 | "eip712Meta": self.meta, 177 | } 178 | return ZkTx(**kwargs) 179 | --------------------------------------------------------------------------------