diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..f54b198 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,10 @@ +# This CODEOWNERS file sets the individuals responsible for code in the zksync2-go Golang SDK repository. + +# These users are the default owners for everything in the repo. +# They will be requested for review when someone opens a pull request. +* @zksync-sdk/txfusion + +# You can also specify code owners for specific directories or files. +# For example: +# /src/ @developer1 @developer2 +# /docs/ @documenter diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md new file mode 100644 index 0000000..c230dbf --- /dev/null +++ b/.github/CONTRIBUTING.md @@ -0,0 +1,84 @@ +# Contributing + +## Welcome! 👋 + +Hello there, contributor! We're delighted that you're considering contributing to the `zksync2-examples` project. This document is here to guide you through the steps and best practices for contributing to this repository. + +Please take a moment to review this document to ensure a smooth and efficient contribution process for everyone involved. + +## Getting Started + +- **Fork the repository.** Begin by forking the main `zksync2-examples` repository to your personal GitHub account. + +- **Clone the repository.** After forking, clone the repository to your local machine: + +```bash +git clone https://github.com//zksync2-examples.git +``` + +- **Create a new branch.** Use descriptive names for your branches to help identify the feature, bugfix, or enhancement you're addressing: + +```bash +git checkout -b feature/description-of-your-feature +``` + +## Making Changes + +### Go examples + +- **Write your code.** Ensure your code is thoroughly tested and functions as expected. Code must be documented adhering to the official Go [commentary](https://golang.org/doc/effective_go.html#commentary) guidelines. +- **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. +- **Lint your code.** Follow basic coding style guidelines and ensure your code is formatted and lint checks pass. + +Use the following commands for these checks: + +```bash +gofmt -w . +got test ./test/... +``` + +### JavaScript examples + +- **Write your code.** Ensure your code is thoroughly tested and functions as expected. Code must be documented adhering to the official Go [commentary](https://golang.org/doc/effective_go.html#commentary) guidelines. +- **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. +- **Lint your code.** Follow basic coding style guidelines and ensure your code is formatted and lint checks pass. + +Use the following commands for these checks: + +```bash +yarn lint +yarn test +yarn types +yarn build +``` + +## Submitting changes + +- **Commit your changes.** Adhere to the [Conventional Commits](https://www.conventionalcommits.org/) standard when writing commit messages. + +- **Push your changes.** Push the changes to your forked repository: + +```bash +git push -u origin feature/description-of-your-feature +``` + +## Submitting a Pull Request + +- **Initiate a pull request (PR).** Go to the main `zksync2-go` 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. + +- **Await a review.** Our maintainers will review your PR. They might request changes or clarifications, so be ready to address any feedback. + + +## Need Assistance? + +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! + +## What's Next? + +Once your PR is approved and merged, your contribution will be integrated into the `zksync2-go` repository. Congratulations, and thank you! We value your contribution and look forward to future collaborations. + +Remember, the best contributions come from enjoying the process, being respectful, and continuously learning. Thanks for being a part of our community! + +--- + +*Last updated: Dec 22, 2023* \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..5e8f33e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,45 @@ +--- +name: Bug report +about: Use this template for reporting issues +title: "" +labels: bug +assignees: '' + +--- + +### 🐛 Bug Report for zksync2-js JavaScript SDK + +#### 📝 Description + +Provide a clear and concise description of the bug. + + +#### 🔄 Reproduction Steps + +1. Step 1 +2. Step 2 +3. ... + +#### 🤔 Expected Behavior + +Describe what you expected to happen. + +#### 😯 Current Behavior + +Describe what actually happened. + +#### 🖥️ Environment + +- **Node version**: [e.g., Node 18.16.1] +- **Operating System & Version**: [e.g., Ubuntu 20.04] +- **Other relevant environment details**: + +#### 📋 Additional Context + +Add any other context about the problem here. If applicable, add screenshots to help explain. + +#### 📎 Log Output + +``` +Paste any relevant log output here. +``` \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..7fa1610 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,11 @@ +blank_issues_enabled: true +contact_links: + - name: zksync-developers Discussion + url: https://github.com/zkSync-Community-Hub/zkync-developers/discussions + about: Please provide feedback, and ask questions here. + - name: zksync-web3 SDK documentation page + url: https://era.zksync.io/docs/api/js/ + about: Please refer to the documentation for immediate answers. + - name: zksync2-js SDK documentation page + url: https://era.zksync.io/docs/api/js/zksync2-js + about: Please refer to the documentation for immediate answers. diff --git a/.github/ISSUE_TEMPLATE/feature_report.md b/.github/ISSUE_TEMPLATE/feature_report.md new file mode 100644 index 0000000..4e30b23 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_report.md @@ -0,0 +1,26 @@ +--- +name: Feature request +about: Use this template for requesting features +title: "" +labels: feat +assignees: '' + +--- + +### 🌟 Feature Request + +#### 📝 Description + +Provide a clear and concise description of the feature you'd like to see. + +#### 🤔 Rationale + +Explain why this feature is important and how it benefits the project. + +#### 🖼️ Mockups/Examples + +If applicable, provide mockups or examples of how the feature would work. + +#### 📋 Additional Context + +Add any other context or information about the feature request here. \ No newline at end of file diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..a45b9c3 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,17 @@ +# What :computer: +* First thing updated with this PR +* Second thing updated with this PR +* Third thing updated with this PR + +# Why :hand: +* Reason why first thing was added to PR +* Reason why second thing was added to PR +* Reason why third thing was added to PR + +# Evidence :camera: +Include screenshots, screen recordings, or `console` output here demonstrating that your changes work as intended + + + +# Notes :memo: +* Any notes/thoughts that the reviewers should know prior to reviewing the code? diff --git a/.github/workflows/test-go.yml b/.github/workflows/test-go.yml new file mode 100644 index 0000000..6f14903 --- /dev/null +++ b/.github/workflows/test-go.yml @@ -0,0 +1,31 @@ +name: Run tests Go +on: + workflow_dispatch: + pull_request: + branch: main + types: [ opened, reopened, synchronize ] + +permissions: + contents: read # for checkout + +jobs: + test: + name: Test + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: Install Go + uses: actions/setup-go@v5.0.0 + - name: Install dependencies + run: cd go && go mod download + - name: Run local-setup + run: | + git clone https://github.com/matter-labs/local-setup.git + pushd local-setup + docker-compose up -d + popd + - name: Run tests + run: cd go && go test ./test/... \ No newline at end of file diff --git a/.github/workflows/test-js.yml b/.github/workflows/test-js.yml new file mode 100644 index 0000000..5830a68 --- /dev/null +++ b/.github/workflows/test-js.yml @@ -0,0 +1,37 @@ +name: Run tests +on: + workflow_dispatch: + pull_request: + branch: main + types: [ opened, reopened, synchronize ] + +permissions: + contents: read # for checkout + +jobs: + test: + name: Test + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: Setup Node.js + uses: actions/setup-node@v3 + with: + node-version: "lts/*" + - name: Install dependencies + run: cd js && yarn install + - name: Run local-setup + run: | + git clone https://github.com/matter-labs/local-setup.git + pushd local-setup + docker-compose up -d + popd + - name: Wait for local-setup to be ready + run: cd js && yarn test:wait + - name: Prepare environment + run: cd js && yarn test:prepare + - name: Run tests + run: cd js && yarn test \ No newline at end of file diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml new file mode 100644 index 0000000..c24e85e --- /dev/null +++ b/.github/workflows/validate.yml @@ -0,0 +1,96 @@ +name: Validate +on: + pull_request: + branch: main + types: [ opened, reopened, synchronize ] + +permissions: + contents: read # for checkout + +jobs: + lint-go: + name: Check code format for Go + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: Install Go + uses: actions/setup-go@v4.0.0 + - name: Run gofmt + run: | + cd go + fmt_output=$(gofmt -l .) + + if [ -n "$fmt_output" ]; then + echo "Code not formatted correctly:" + echo "$fmt_output" + exit 1 + else + echo "Code is formatted correctly" + exit 0 + fi + lint-js: + name: Check code format for JavaScript + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: Setup Node.js + uses: actions/setup-node@v3 + with: + node-version: "lts/*" + - name: Install dependencies + run: cd js && yarn install + - name: Prepare environment + run: cd js && yarn lint:check + commits: + name: Check commits + runs-on: ubuntu-latest + if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Setup Node.js + uses: actions/setup-node@v3 + with: + node-version: "lts/*" + - name: Install dependencies + run: npm install -g @commitlint/cli @commitlint/config-conventional + - name: Configure + run: | + echo 'module.exports = {"extends": ["@commitlint/config-conventional"]}' > commitlint.config.js + - name: Validate + run: | + git fetch + npx commitlint \ + --from ${{ github.event.pull_request.head.sha }}~${{ github.event.pull_request.commits }} \ + --to ${{ github.event.pull_request.head.sha }} \ + --verbose + commits-fork: + name: Check commits from forks + runs-on: ubuntu-latest + if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Setup Node.js + uses: actions/setup-node@v3 + with: + node-version: "lts/*" + - name: Install dependencies + run: npm install -g @commitlint/cli @commitlint/config-conventional + - name: Configure + run: | + echo 'module.exports = {"extends": ["@commitlint/config-conventional"]}' > commitlint.config.js + - name: Validate + run: | + git fetch origin "+refs/pull/${{ github.event.pull_request.number }}/head:refs/pull/${{ github.event.pull_request.number }}/head" + git checkout "refs/pull/${{ github.event.pull_request.number }}/head" + npx commitlint \ + --from HEAD~${{ github.event.pull_request.commits }} \ + --to HEAD \ + --verbose \ No newline at end of file diff --git a/go/.gitignore b/go/.gitignore new file mode 100644 index 0000000..13c2d6c --- /dev/null +++ b/go/.gitignore @@ -0,0 +1 @@ +test/token.json \ No newline at end of file diff --git a/go/08_get_confirmed_tokens.go b/go/08_get_confirmed_tokens.go index 80cc8e8..68454e0 100644 --- a/go/08_get_confirmed_tokens.go +++ b/go/08_get_confirmed_tokens.go @@ -7,6 +7,8 @@ import ( "log" ) +// WARNING +// Method client.ConfirmedTokens will be removed in the future func main() { var ( ZkSyncEraProvider = "https://sepolia.era.zksync.dev" diff --git a/go/go.mod b/go/go.mod index 15cf929..74afcca 100644 --- a/go/go.mod +++ b/go/go.mod @@ -4,6 +4,7 @@ go 1.20 require ( github.com/ethereum/go-ethereum v1.12.0 + github.com/stretchr/testify v1.8.1 github.com/zksync-sdk/zksync2-go v0.3.1 ) @@ -13,6 +14,7 @@ require ( github.com/btcsuite/btcd/btcec/v2 v2.2.0 // indirect github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 // indirect github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce // indirect + github.com/davecgh/go-spew v1.1.1 // indirect github.com/deckarep/golang-set/v2 v2.1.0 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect @@ -23,6 +25,7 @@ require ( github.com/holiman/uint256 v1.2.2-0.20230321075855-87b91420868c // indirect github.com/miguelmota/go-ethereum-hdwallet v0.1.1 // indirect github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible // indirect github.com/tklauser/go-sysconf v0.3.5 // indirect github.com/tklauser/numcpus v0.2.2 // indirect @@ -30,4 +33,5 @@ require ( golang.org/x/crypto v0.1.0 // indirect golang.org/x/sys v0.7.0 // indirect gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go/go.sum b/go/go.sum index c0165f0..c2073e3 100644 --- a/go/go.sum +++ b/go/go.sum @@ -358,12 +358,17 @@ github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4/go.mod h1:RZL github.com/status-im/keycard-go v0.2.0 h1:QDLFswOQu1r5jsycloeQh3bVU8n/NatHHaZobtDnDzA= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.2.0/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/syndtr/goleveldb v1.0.1-0.20210305035536-64b5b1c73954/go.mod h1:u2MKkTVTVJWe5D1rCvame8WqhBd88EuIwODJZ1VHCPM= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= github.com/tinylib/msgp v1.0.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= @@ -586,6 +591,7 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= @@ -603,6 +609,7 @@ gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/go/test/00_setup_test.go b/go/test/00_setup_test.go new file mode 100644 index 0000000..e74e44c --- /dev/null +++ b/go/test/00_setup_test.go @@ -0,0 +1,279 @@ +package test + +import ( + "context" + "crypto/ecdsa" + "encoding/json" + "fmt" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/zksync-sdk/zksync2-go/accounts" + "github.com/zksync-sdk/zksync2-go/clients" + "log" + "math/big" + "os" + "testing" + "time" +) + +const EthereumProvider = "http://localhost:8545" +const ZkSyncEraProvider = "http://localhost:3050" +const PrivateKey = "7726827caac94a7f9e1b160f7ea819f172f7b6f9d2a97f992c38edeab82d4110" +const Address = "0x36615Cf349d7F6344891B1e7CA7C72883F5dc049" +const Receiver = "0xa61464658AfeAf65CccaaFD3a512b69A83B77618" + +const TokenPath = "./token.json" + +type token struct { + L1Address string `json:"l1Address"` + L2Address string `json:"l2Address"` + L1TxHash string `json:"L1TxHash"` + L2TxHash string `json:"L2TxHash"` +} + +func readToken() *token { + file, err := os.Open(TokenPath) + if err != nil { + log.Printf("Coud not find token.json, creating new one") + return nil + } + defer func(file *os.File) { + errClose := file.Close() + if errClose != nil { + log.Fatalf("Error closing file: %s", err) + } + }(file) + + var tokenData token + decoder := json.NewDecoder(file) + if errDecode := decoder.Decode(&tokenData); err != nil { + log.Fatalf("Error decoding JSON: %s", errDecode) + } + return &tokenData +} + +func writeToken(token token) { + file, err := os.Create(TokenPath) + if err != nil { + log.Fatalf("Error creating file: %s", err) + } + defer func(file *os.File) { + errClose := file.Close() + if errClose != nil { + log.Fatalf("Error closing file: %s", err) + } + }(file) + + // Marshal data to JSON + jsonData, err := json.MarshalIndent(token, "", " ") + if err != nil { + log.Fatalf("Error marshaling to JSON: %s", err) + } + + // Write JSON data to the file + _, err = file.Write(jsonData) + if err != nil { + log.Fatalf("Error writing JSON to file: %s", err) + } +} + +func checkIfTokenNeedsToBeCreated(client clients.Client, ethClient *ethclient.Client) (bool, bool) { + tokenData := readToken() + if tokenData == nil { + return true, true + } + _, err := ethClient.CodeAt(context.Background(), common.HexToAddress(tokenData.L1Address), nil) + if err != nil { + return false, false + } + _, err = client.CodeAt(context.Background(), common.HexToAddress(tokenData.L2Address), nil) + if err != nil { + return true, false + } + + return true, true +} + +func createTokenL1(ethClient *ethclient.Client, privateKey *ecdsa.PrivateKey, publicKey common.Address) common.Address { + chainID, err := ethClient.ChainID(context.Background()) + if err != nil { + log.Fatal(err) + } + auth, err := bind.NewKeyedTransactorWithChainID(privateKey, chainID) + if err != nil { + log.Fatal(err) + } + + address, tx, tokenContract, err := DeployToken(auth, ethClient, "DAI", "DAI", 18) + if err != nil { + log.Fatal(err) + } + + _, err = bind.WaitDeployed(context.Background(), ethClient, tx) + if err != nil { + log.Fatal(err) + } + + symbol, err := tokenContract.Symbol(nil) + if err != nil { + log.Fatal(err) + } + decimals, err := tokenContract.Decimals(nil) + if err != nil { + log.Fatal(nil) + } + + auth, err = bind.NewKeyedTransactorWithChainID(privateKey, chainID) + if err != nil { + log.Fatal(err) + } + tx, err = tokenContract.Mint(auth, publicKey, big.NewInt(100_000_000)) + if err != nil { + log.Fatal(err) + } + + _, err = bind.WaitMined(context.Background(), ethClient, tx) + if err != nil { + log.Fatal("Wait mint: ", err) + } + + balance, err := tokenContract.BalanceOf(nil, publicKey) + if err != nil { + log.Fatal(err) + } + + log.Println("Token address: ", address) + log.Println("Symbol:", symbol) + log.Println("Decimals:", decimals) + log.Println("Balance L1: ", balance) + + return address +} + +func createTokenL2(wallet *accounts.Wallet, client clients.Client, ethClient *ethclient.Client, l1Token common.Address) (common.Address, common.Hash, common.Hash) { + tx, err := wallet.Deposit(nil, accounts.DepositTransaction{ + Token: l1Token, + Amount: big.NewInt(30), + To: wallet.Address(), + ApproveERC20: true, + RefundRecipient: wallet.Address(), + }) + if err != nil { + log.Fatal(err) + } + + _, err = bind.WaitMined(context.Background(), ethClient, tx) + if err != nil { + log.Fatal(err) + } + + l1Receipt, err := ethClient.TransactionReceipt(context.Background(), tx.Hash()) + if err != nil { + log.Fatal(err) + } + + l2Tx, err := client.L2TransactionFromPriorityOp(context.Background(), l1Receipt) + if err != nil { + log.Fatal(err) + } + _, err = client.WaitMined(context.Background(), l2Tx.Hash) + if err != nil { + log.Fatal(err) + } + + tokenL2Address, err := client.L2TokenAddress(context.Background(), l1Token) + if err != nil { + log.Panic(err) + } + + tokenL2Balance, err := wallet.Balance(context.Background(), tokenL2Address, nil) + if err != nil { + log.Panic(err) + } + + fmt.Println("Balance L2: ", tokenL2Balance) + + return tokenL2Address, tx.Hash(), l2Tx.Hash +} + +func wait() { + const maxAttempts = 30 + + nodeURL := "http://localhost:3050" + client, err := clients.Dial(nodeURL) + if err != nil { + log.Fatal(err) + } + defer client.Close() + + for i := 0; i < maxAttempts; i++ { + _, err := client.NetworkID(context.Background()) + if err == nil { + log.Println("Node is ready to receive traffic.") + return + } + + log.Println("Node not ready yet. Retrying...") + time.Sleep(20 * time.Second) + } + + log.Fatal("Maximum retries exceeded.") +} + +func TestMain(m *testing.M) { + wait() + + client, err := clients.Dial(ZkSyncEraProvider) + if err != nil { + log.Panic(err) + } + defer client.Close() + + ethClient, err := ethclient.Dial(EthereumProvider) + if err != nil { + log.Fatal(err) + } + + privateKey, err := crypto.HexToECDSA(PrivateKey) + if err != nil { + log.Fatal(err) + } + + publicKeyECDSA, ok := privateKey.Public().(*ecdsa.PublicKey) + if !ok { + log.Fatal("cannot assert type: publicKey is not of type *ecdsa.PublicKey") + } + publicKey := crypto.PubkeyToAddress(*publicKeyECDSA) + + wallet, err := accounts.NewWallet(common.Hex2Bytes(PrivateKey), &client, ethClient) + if err != nil { + log.Fatal(err) + } + + shouldCreateL1Token, shouldCreateL2Token := checkIfTokenNeedsToBeCreated(client, ethClient) + if shouldCreateL1Token { + l1TokenAddress := createTokenL1(ethClient, privateKey, publicKey) + l2TokenAddress, l1Tx, l2Tx := createTokenL2(wallet, client, ethClient, l1TokenAddress) + writeToken(token{ + L1Address: l1TokenAddress.Hex(), + L2Address: l2TokenAddress.Hex(), + L1TxHash: l1Tx.Hex(), + L2TxHash: l2Tx.Hex(), + }) + + } else if !shouldCreateL1Token && shouldCreateL2Token { + tokenData := readToken() + l2TokenAddress, l1Tx, l2Tx := createTokenL2(wallet, client, ethClient, common.HexToAddress(tokenData.L1Address)) + tokenData.L2Address = l2TokenAddress.Hex() + tokenData.L1TxHash = l1Tx.Hex() + tokenData.L1TxHash = l2Tx.Hex() + + writeToken(*tokenData) + } else { + fmt.Println("Token has been already created.") + } + + os.Exit(m.Run()) +} diff --git a/go/test/01_deposit_test.go b/go/test/01_deposit_test.go new file mode 100644 index 0000000..ee3744c --- /dev/null +++ b/go/test/01_deposit_test.go @@ -0,0 +1,62 @@ +package test + +import ( + "context" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/stretchr/testify/assert" + "github.com/zksync-sdk/zksync2-go/accounts" + "github.com/zksync-sdk/zksync2-go/clients" + "github.com/zksync-sdk/zksync2-go/utils" + "math/big" + "testing" +) + +func TestDeposit(t *testing.T) { + amount := big.NewInt(7_000_000_000) + + client, err := clients.Dial(ZkSyncEraProvider) + defer client.Close() + assert.NoError(t, err, "clients.Dial should not return an error") + + ethClient, err := ethclient.Dial(EthereumProvider) + assert.NoError(t, err, "ethclient.Dial should not return an error") + defer ethClient.Close() + + wallet, err := accounts.NewWallet(common.Hex2Bytes(PrivateKey), &client, ethClient) + assert.NoError(t, err, "NewWallet should not return an error") + + l2BalanceBeforeDeposit, err := wallet.Balance(context.Background(), utils.EthAddress, nil) + assert.NoError(t, err, "Balance should not return an error") + + l1BalanceBeforeDeposit, err := wallet.BalanceL1(nil, utils.EthAddress) + assert.NoError(t, err, "BalanceL1 should not return an error") + + tx, err := wallet.Deposit(nil, accounts.DepositTransaction{ + To: wallet.Address(), + Token: utils.EthAddress, + Amount: amount, + RefundRecipient: wallet.Address(), + }) + assert.NoError(t, err, "Deposit should not return an error") + + l1Receipt, err := bind.WaitMined(context.Background(), ethClient, tx) + assert.NoError(t, err, "bind.WaitMined should not return an error") + + l2Tx, err := client.L2TransactionFromPriorityOp(context.Background(), l1Receipt) + assert.NoError(t, err, "L2TransactionFromPriorityOp should not return an error") + + l2Receipt, err := client.WaitMined(context.Background(), l2Tx.Hash) + assert.NoError(t, err, "bind.WaitMined should not return an error") + assert.NotNil(t, l2Receipt.BlockHash, "Transaction should be mined") + + l2BalanceAfterDeposit, err := wallet.Balance(context.Background(), utils.EthAddress, nil) + assert.NoError(t, err, "Balance should not return an error") + + l1BalanceAfterDeposit, err := wallet.BalanceL1(nil, utils.EthAddress) + assert.NoError(t, err, "BalanceL1 should not return an error") + + assert.True(t, new(big.Int).Sub(l2BalanceAfterDeposit, l2BalanceBeforeDeposit).Cmp(amount) >= 0, "Balance on L2 should be increased") + assert.True(t, new(big.Int).Sub(l1BalanceBeforeDeposit, l1BalanceAfterDeposit).Cmp(amount) >= 0, "Balance on L1 should be decreased") +} diff --git a/go/test/02_transfer_test.go b/go/test/02_transfer_test.go new file mode 100644 index 0000000..51d6511 --- /dev/null +++ b/go/test/02_transfer_test.go @@ -0,0 +1,55 @@ +package test + +import ( + "context" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/stretchr/testify/assert" + "github.com/zksync-sdk/zksync2-go/accounts" + "github.com/zksync-sdk/zksync2-go/clients" + "github.com/zksync-sdk/zksync2-go/utils" + "math/big" + "testing" +) + +func TestTransfer(t *testing.T) { + amount := big.NewInt(7_000_000_000) + receiver := common.HexToAddress(Receiver) + + client, err := clients.Dial(ZkSyncEraProvider) + defer client.Close() + assert.NoError(t, err, "clients.Dial should not return an error") + + ethClient, err := ethclient.Dial(EthereumProvider) + assert.NoError(t, err, "ethclient.Dial should not return an error") + defer ethClient.Close() + + wallet, err := accounts.NewWallet(common.Hex2Bytes(PrivateKey), &client, ethClient) + assert.NoError(t, err, "NewWallet should not return an error") + + balanceBeforeTransferSender, err := wallet.Balance(context.Background(), utils.EthAddress, nil) + assert.NoError(t, err, "Balance should not return an error") + + balanceBeforeTransferReceiver, err := client.BalanceAt(context.Background(), receiver, nil) + assert.NoError(t, err, "BalanceAt should not return an error") + + tx, err := wallet.Transfer(nil, accounts.TransferTransaction{ + To: receiver, + Amount: amount, + Token: utils.EthAddress, + }) + assert.NoError(t, err, "Transfer should not return an error") + + receipt, err := client.WaitMined(context.Background(), tx.Hash()) + assert.NoError(t, err, "client.WaitMined should not return an error") + assert.NotNil(t, receipt.BlockHash, "Transaction should be mined") + + balanceAfterTransferSender, err := wallet.Balance(context.Background(), utils.EthAddress, nil) + assert.NoError(t, err, "Balance should not return an error") + + balanceAfterTransferReceiver, err := wallet.BalanceL1(nil, utils.EthAddress) + assert.NoError(t, err, "BalanceL1 should not return an error") + + assert.True(t, new(big.Int).Sub(balanceBeforeTransferSender, balanceAfterTransferSender).Cmp(amount) >= 0, "Sender balance should be decreased") + assert.True(t, new(big.Int).Sub(balanceAfterTransferReceiver, balanceBeforeTransferReceiver).Cmp(amount) >= 0, "Receiver balance should be increased") +} diff --git a/go/test/03_withdraw_test.go b/go/test/03_withdraw_test.go new file mode 100644 index 0000000..d82aadd --- /dev/null +++ b/go/test/03_withdraw_test.go @@ -0,0 +1,54 @@ +package test + +import ( + "context" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/stretchr/testify/assert" + "github.com/zksync-sdk/zksync2-go/accounts" + "github.com/zksync-sdk/zksync2-go/clients" + "github.com/zksync-sdk/zksync2-go/utils" + "math/big" + "testing" +) + +func TestWithdraw(t *testing.T) { + amount := big.NewInt(7_000_000_000) + + client, err := clients.Dial(ZkSyncEraProvider) + defer client.Close() + assert.NoError(t, err, "clients.Dial should not return an error") + + ethClient, err := ethclient.Dial(EthereumProvider) + assert.NoError(t, err, "ethclient.Dial should not return an error") + defer ethClient.Close() + + wallet, err := accounts.NewWallet(common.Hex2Bytes(PrivateKey), &client, ethClient) + assert.NoError(t, err, "NewWallet should not return an error") + + l2BalanceBeforeWithdrawal, err := wallet.Balance(context.Background(), utils.EthAddress, nil) + assert.NoError(t, err, "Balance should not return an error") + + //l1BalanceBeforeWithdrawal, err := wallet.BalanceL1(nil, l1TokenAddress) + //assert.NoError(t, err, "BalanceL1 should not return an error") + + tx, err := wallet.Withdraw(nil, accounts.WithdrawalTransaction{ + To: wallet.Address(), + Amount: amount, + Token: utils.EthAddress, + }) + assert.NoError(t, err, "Withdraw should not return an error") + + receipt, err := client.WaitMined(context.Background(), tx.Hash()) + assert.NoError(t, err, "client.WaitMined should not return an error") + assert.NotNil(t, receipt.BlockHash, "Transaction should be mined") + + l2BalanceAfterWithdrawal, err := wallet.Balance(context.Background(), utils.EthAddress, nil) + assert.NoError(t, err, "Balance should not return an error") + + //l1BalanceAfterWithdrawal, err := wallet.BalanceL1(nil, l1TokenAddress) + //assert.NoError(t, err, "BalanceL1 should not return an error") + + assert.True(t, new(big.Int).Sub(l2BalanceBeforeWithdrawal, l2BalanceAfterWithdrawal).Cmp(amount) >= 0, "Balance on L2 should be decreased") + //assert.True(t, new(big.Int).Sub(l1BalanceBeforeDeposit, l1BalanceAfterDeposit).Cmp(amount) >= 0, "Balance on L1 should be decreased") +} diff --git a/go/test/05_deposit_token_test.go b/go/test/05_deposit_token_test.go new file mode 100644 index 0000000..8759439 --- /dev/null +++ b/go/test/05_deposit_token_test.go @@ -0,0 +1,65 @@ +package test + +import ( + "context" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/stretchr/testify/assert" + "github.com/zksync-sdk/zksync2-go/accounts" + "github.com/zksync-sdk/zksync2-go/clients" + "math/big" + "testing" +) + +func TestDepositToken(t *testing.T) { + tokenData := readToken() + amount := big.NewInt(5) + l1TokenAddress := common.HexToAddress(tokenData.L1Address) + l2TokenAddress := common.HexToAddress(tokenData.L2Address) + + client, err := clients.Dial(ZkSyncEraProvider) + defer client.Close() + assert.NoError(t, err, "clients.Dial should not return an error") + + ethClient, err := ethclient.Dial(EthereumProvider) + assert.NoError(t, err, "ethclient.Dial should not return an error") + defer ethClient.Close() + + wallet, err := accounts.NewWallet(common.Hex2Bytes(PrivateKey), &client, ethClient) + assert.NoError(t, err, "NewWallet should not return an error") + + l2BalanceBeforeDeposit, err := wallet.Balance(context.Background(), l2TokenAddress, nil) + assert.NoError(t, err, "Balance should not return an error") + + l1BalanceBeforeDeposit, err := wallet.BalanceL1(nil, l1TokenAddress) + assert.NoError(t, err, "BalanceL1 should not return an error") + + tx, err := wallet.Deposit(nil, accounts.DepositTransaction{ + To: wallet.Address(), + Token: l1TokenAddress, + Amount: amount, + ApproveERC20: true, + RefundRecipient: wallet.Address(), + }) + assert.NoError(t, err, "Deposit should not return an error") + + l1Receipt, err := bind.WaitMined(context.Background(), ethClient, tx) + assert.NoError(t, err, "bind.WaitMined should not return an error") + + l2Tx, err := client.L2TransactionFromPriorityOp(context.Background(), l1Receipt) + assert.NoError(t, err, "L2TransactionFromPriorityOp should not return an error") + + l2Receipt, err := client.WaitMined(context.Background(), l2Tx.Hash) + assert.NoError(t, err, "bind.WaitMined should not return an error") + assert.NotNil(t, l2Receipt.BlockHash, "Transaction should be mined") + + l2BalanceAfterDeposit, err := wallet.Balance(context.Background(), l2TokenAddress, nil) + assert.NoError(t, err, "Balance should not return an error") + + l1BalanceAfterDeposit, err := wallet.BalanceL1(nil, l1TokenAddress) + assert.NoError(t, err, "BalanceL1 should not return an error") + + assert.True(t, new(big.Int).Sub(l2BalanceAfterDeposit, l2BalanceBeforeDeposit).Cmp(amount) >= 0, "Balance on L2 should be increased") + assert.True(t, new(big.Int).Sub(l1BalanceBeforeDeposit, l1BalanceAfterDeposit).Cmp(amount) >= 0, "Balance on L1 should be decreased") +} diff --git a/go/test/06_transfer_token_test.go b/go/test/06_transfer_token_test.go new file mode 100644 index 0000000..f6e2d1c --- /dev/null +++ b/go/test/06_transfer_token_test.go @@ -0,0 +1,60 @@ +package test + +import ( + "context" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/stretchr/testify/assert" + "github.com/zksync-sdk/zksync2-go/accounts" + "github.com/zksync-sdk/zksync2-go/clients" + "github.com/zksync-sdk/zksync2-go/contracts/erc20" + "math/big" + "testing" +) + +func TestTransferToken(t *testing.T) { + tokenData := readToken() + amount := big.NewInt(5) + tokenAddress := common.HexToAddress(tokenData.L2Address) + receiver := common.HexToAddress(Receiver) + + client, err := clients.Dial(ZkSyncEraProvider) + defer client.Close() + assert.NoError(t, err, "clients.Dial should not return an error") + + ethClient, err := ethclient.Dial(EthereumProvider) + assert.NoError(t, err, "ethclient.Dial should not return an error") + defer ethClient.Close() + + wallet, err := accounts.NewWallet(common.Hex2Bytes(PrivateKey), &client, ethClient) + assert.NoError(t, err, "NewWallet should not return an error") + + tokenContract, err := erc20.NewIERC20(tokenAddress, client) + assert.NoError(t, err, "NewIERC20 should not return an error") + + balanceBeforeTransferSender, err := wallet.Balance(context.Background(), tokenAddress, nil) + assert.NoError(t, err, "Balance should not return an error") + + balanceBeforeTransferReceiver, err := tokenContract.BalanceOf(nil, receiver) + assert.NoError(t, err, "BalanceOf should not return an error") + + tx, err := wallet.Transfer(nil, accounts.TransferTransaction{ + To: receiver, + Amount: amount, + Token: tokenAddress, + }) + assert.NoError(t, err, "Transfer should not return an error") + + receipt, err := client.WaitMined(context.Background(), tx.Hash()) + assert.NoError(t, err, "client.WaitMined should not return an error") + assert.NotNil(t, receipt.BlockHash, "Transaction should be mined") + + balanceAfterTransferSender, err := wallet.Balance(context.Background(), tokenAddress, nil) + assert.NoError(t, err, "Balance should not return an error") + + balanceAfterTransferReceiver, err := tokenContract.BalanceOf(nil, receiver) + assert.NoError(t, err, "BalanceOf should not return an error") + + assert.True(t, new(big.Int).Sub(balanceBeforeTransferSender, balanceAfterTransferSender).Cmp(amount) >= 0, "Sender balance should be decreased") + assert.True(t, new(big.Int).Sub(balanceAfterTransferReceiver, balanceBeforeTransferReceiver).Cmp(amount) >= 0, "Receiver balance should be increased") +} diff --git a/go/test/07_withdraw_token_test.go b/go/test/07_withdraw_token_test.go new file mode 100644 index 0000000..201cca5 --- /dev/null +++ b/go/test/07_withdraw_token_test.go @@ -0,0 +1,56 @@ +package test + +import ( + "context" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/stretchr/testify/assert" + "github.com/zksync-sdk/zksync2-go/accounts" + "github.com/zksync-sdk/zksync2-go/clients" + "math/big" + "testing" +) + +func TestWithdrawToken(t *testing.T) { + tokenData := readToken() + amount := big.NewInt(5) + //l1TokenAddress := common.HexToAddress(tokenData.L1Address) + l2TokenAddress := common.HexToAddress(tokenData.L2Address) + + client, err := clients.Dial(ZkSyncEraProvider) + defer client.Close() + assert.NoError(t, err, "clients.Dial should not return an error") + + ethClient, err := ethclient.Dial(EthereumProvider) + assert.NoError(t, err, "ethclient.Dial should not return an error") + defer ethClient.Close() + + wallet, err := accounts.NewWallet(common.Hex2Bytes(PrivateKey), &client, ethClient) + assert.NoError(t, err, "NewWallet should not return an error") + + l2BalanceBeforeWithdrawal, err := wallet.Balance(context.Background(), l2TokenAddress, nil) + assert.NoError(t, err, "Balance should not return an error") + + //l1BalanceBeforeWithdrawal, err := wallet.BalanceL1(nil, l1TokenAddress) + //assert.NoError(t, err, "BalanceL1 should not return an error") + + tx, err := wallet.Withdraw(nil, accounts.WithdrawalTransaction{ + To: wallet.Address(), + Amount: amount, + Token: l2TokenAddress, + }) + assert.NoError(t, err, "Withdraw should not return an error") + + receipt, err := client.WaitMined(context.Background(), tx.Hash()) + assert.NoError(t, err, "client.WaitMined should not return an error") + assert.NotNil(t, receipt.BlockHash, "Transaction should be mined") + + l2BalanceAfterWithdrawal, err := wallet.Balance(context.Background(), l2TokenAddress, nil) + assert.NoError(t, err, "Balance should not return an error") + + //l1BalanceAfterWithdrawal, err := wallet.BalanceL1(nil, l1TokenAddress) + //assert.NoError(t, err, "BalanceL1 should not return an error") + + assert.True(t, new(big.Int).Sub(l2BalanceBeforeWithdrawal, l2BalanceAfterWithdrawal).Cmp(amount) >= 0, "Balance on L2 should be decreased") + //assert.True(t, new(big.Int).Sub(l1BalanceBeforeDeposit, l1BalanceAfterDeposit).Cmp(amount) >= 0, "Balance on L1 should be decreased") +} diff --git a/go/test/09_deploy_create_test.go b/go/test/09_deploy_create_test.go new file mode 100644 index 0000000..657049b --- /dev/null +++ b/go/test/09_deploy_create_test.go @@ -0,0 +1,83 @@ +package test + +import ( + "context" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/assert" + "github.com/zksync-sdk/zksync2-go/accounts" + "github.com/zksync-sdk/zksync2-go/clients" + "math/big" + "os" + "testing" + "zksync2-examples/contracts/storage" +) + +func TestDeployCreate(t *testing.T) { + client, err := clients.Dial(ZkSyncEraProvider) + defer client.Close() + assert.NoError(t, err, "clients.Dial should not return an error") + + wallet, err := accounts.NewWallet(common.Hex2Bytes(PrivateKey), &client, nil) + assert.NoError(t, err, "NewWallet should not return an error") + + bytecode, err := os.ReadFile("../../solidity/storage/build/Storage.zbin") + assert.NoError(t, err, "ReadFile should not return an error") + + hash, err := wallet.DeployWithCreate(nil, accounts.CreateTransaction{Bytecode: bytecode}) + assert.NoError(t, err, "DeployWithCreate should not return an error") + + receipt, err := client.WaitMined(context.Background(), hash) + assert.NoError(t, err, "client.WaitMined should not return an error") + + contractAddress := receipt.ContractAddress + assert.NotNil(t, contractAddress, "Contract should be deployed") + + storageContract, err := storage.NewStorage(contractAddress, client) + assert.NoError(t, err, "NewStorage should not return an error") + + abi, err := storage.StorageMetaData.GetAbi() + assert.NoError(t, err, "GetAbi should not return an error") + + setArguments, err := abi.Pack("set", big.NewInt(700)) + assert.NoError(t, err, "Pack should not return an error") + + result, err := wallet.CallContract(context.Background(), accounts.CallMsg{ + To: &contractAddress, + Data: setArguments, + }, nil) + assert.NotNil(t, result, "Result from contract should be non-nil value") + + value, err := storageContract.Get(nil) + assert.NoError(t, err, "Get should not return an error") + assert.True(t, value.Cmp(big.NewInt(0)) == 0, "Values should be the same") + + opts, err := bind.NewKeyedTransactorWithChainID(wallet.Signer().PrivateKey(), wallet.Signer().Domain().ChainId) + assert.NoError(t, err, "NewKeyedTransactorWithChainID should not return an error") + + tx, err := storageContract.Set(opts, big.NewInt(200)) + assert.NoError(t, err, "Set should not return an error") + + _, err = client.WaitMined(context.Background(), tx.Hash()) + assert.NoError(t, err, "client.WaitMined should not return an error") + + value, err = storageContract.Get(nil) + assert.NoError(t, err, "Get should not return an error") + assert.True(t, value.Cmp(big.NewInt(200)) == 0, "Values should be the same") + + setArguments, err = abi.Pack("set", big.NewInt(500)) + assert.NoError(t, err, "Pack should not return an error") + + execute, err := wallet.SendTransaction(context.Background(), &accounts.Transaction{ + To: &contractAddress, + Data: setArguments, + }) + assert.NoError(t, err, "SendTransaction should not return an error") + + _, err = client.WaitMined(context.Background(), execute) + assert.NoError(t, err, "client.WaitMined should not return an error") + + value, err = storageContract.Get(nil) + assert.NoError(t, err, "Get should not return an error") + assert.True(t, value.Cmp(big.NewInt(500)) == 0, "Values should be the same") +} diff --git a/go/test/12_deploy_create2_test.go b/go/test/12_deploy_create2_test.go new file mode 100644 index 0000000..a6bf22c --- /dev/null +++ b/go/test/12_deploy_create2_test.go @@ -0,0 +1,52 @@ +package test + +import ( + "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/assert" + "github.com/zksync-sdk/zksync2-go/accounts" + "github.com/zksync-sdk/zksync2-go/clients" + "os" + "testing" +) + +func TestDeployCreate2(t *testing.T) { + client, err := clients.Dial(ZkSyncEraProvider) + defer client.Close() + assert.NoError(t, err, "clients.Dial should not return an error") + + wallet, err := accounts.NewWallet(common.Hex2Bytes(PrivateKey), &client, nil) + assert.NoError(t, err, "NewWallet should not return an error") + + bytecode, err := os.ReadFile("../../solidity/storage/build/Storage.zbin") + assert.NoError(t, err, "ReadFile should not return an error") + + _, err = wallet.Deploy(nil, accounts.Create2Transaction{Bytecode: bytecode}) + //assert.NoError(t, err, "Deploy should not return an error") + + //receipt, err := client.WaitMined(context.Background(), hash) + //assert.NoError(t, err, "client.WaitMined should not return an error") + //assert.NotNil(t, receipt.ContractAddress, "Contract should be deployed") + // + //contractAddress, err := utils.Create2Address(wallet.Address(), bytecode, nil, nil) + //assert.Equal(t, contractAddress, receipt.ContractAddress, "Addresses should be the same") + // + //storageContract, err := storage.NewStorage(contractAddress, client) + //assert.NoError(t, err, "NewStorage should not return an error") + // + //value, err := storageContract.Get(nil) + //assert.NoError(t, err, "Get should not return an error") + //assert.True(t, value.Cmp(big.NewInt(0)) == 0, "Values should be the same") + // + //opts, err := bind.NewKeyedTransactorWithChainID(wallet.Signer().PrivateKey(), wallet.Signer().Domain().ChainId) + //assert.NoError(t, err, "NewKeyedTransactorWithChainID should not return an error") + // + //tx, err := storageContract.Set(opts, big.NewInt(200)) + //assert.NoError(t, err, "Set should not return an error") + // + //_, err = client.WaitMined(context.Background(), tx.Hash()) + //assert.NoError(t, err, "client.WaitMined should not return an error") + // + //value, err = storageContract.Get(nil) + //assert.NoError(t, err, "Get should not return an error") + //assert.True(t, value.Cmp(big.NewInt(200)) == 0, "Values should be the same") +} diff --git a/go/test/token.go b/go/test/token.go new file mode 100644 index 0000000..0c736a6 --- /dev/null +++ b/go/test/token.go @@ -0,0 +1,823 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package test + +import ( + "errors" + "math/big" + "strings" + + ethereum "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = errors.New + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription + _ = abi.ConvertType +) + +// TokenMetaData contains all meta data concerning the Token contract. +var TokenMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[{\"internalType\":\"string\",\"name\":\"name_\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"symbol_\",\"type\":\"string\"},{\"internalType\":\"uint8\",\"name\":\"decimals_\",\"type\":\"uint8\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"}],\"name\":\"allowance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"decimals\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"subtractedValue\",\"type\":\"uint256\"}],\"name\":\"decreaseAllowance\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"addedValue\",\"type\":\"uint256\"}],\"name\":\"increaseAllowance\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"mint\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"transfer\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Bin: "0x60806040523480156200001157600080fd5b5060405162001a8038038062001a80833981810160405281019062000037919062000254565b828281600390816200004a919062000539565b5080600490816200005c919062000539565b50505080600560006101000a81548160ff021916908360ff16021790555050505062000620565b6000604051905090565b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b620000ec82620000a1565b810181811067ffffffffffffffff821117156200010e576200010d620000b2565b5b80604052505050565b60006200012362000083565b9050620001318282620000e1565b919050565b600067ffffffffffffffff821115620001545762000153620000b2565b5b6200015f82620000a1565b9050602081019050919050565b60005b838110156200018c5780820151818401526020810190506200016f565b60008484015250505050565b6000620001af620001a98462000136565b62000117565b905082815260208101848484011115620001ce57620001cd6200009c565b5b620001db8482856200016c565b509392505050565b600082601f830112620001fb57620001fa62000097565b5b81516200020d84826020860162000198565b91505092915050565b600060ff82169050919050565b6200022e8162000216565b81146200023a57600080fd5b50565b6000815190506200024e8162000223565b92915050565b60008060006060848603121562000270576200026f6200008d565b5b600084015167ffffffffffffffff81111562000291576200029062000092565b5b6200029f86828701620001e3565b935050602084015167ffffffffffffffff811115620002c357620002c262000092565b5b620002d186828701620001e3565b9250506040620002e4868287016200023d565b9150509250925092565b600081519050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b600060028204905060018216806200034157607f821691505b602082108103620003575762000356620002f9565b5b50919050565b60008190508160005260206000209050919050565b60006020601f8301049050919050565b600082821b905092915050565b600060088302620003c17fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8262000382565b620003cd868362000382565b95508019841693508086168417925050509392505050565b6000819050919050565b6000819050919050565b60006200041a620004146200040e84620003e5565b620003ef565b620003e5565b9050919050565b6000819050919050565b6200043683620003f9565b6200044e620004458262000421565b8484546200038f565b825550505050565b600090565b6200046562000456565b620004728184846200042b565b505050565b5b818110156200049a576200048e6000826200045b565b60018101905062000478565b5050565b601f821115620004e957620004b3816200035d565b620004be8462000372565b81016020851015620004ce578190505b620004e6620004dd8562000372565b83018262000477565b50505b505050565b600082821c905092915050565b60006200050e60001984600802620004ee565b1980831691505092915050565b6000620005298383620004fb565b9150826002028217905092915050565b6200054482620002ee565b67ffffffffffffffff81111562000560576200055f620000b2565b5b6200056c825462000328565b620005798282856200049e565b600060209050601f831160018114620005b157600084156200059c578287015190505b620005a885826200051b565b86555062000618565b601f198416620005c1866200035d565b60005b82811015620005eb57848901518255600182019150602085019450602081019050620005c4565b868310156200060b578489015162000607601f891682620004fb565b8355505b6001600288020188555050505b505050505050565b61145080620006306000396000f3fe608060405234801561001057600080fd5b50600436106100b45760003560e01c806340c10f191161007157806340c10f19146101a357806370a08231146101d357806395d89b4114610203578063a457c2d714610221578063a9059cbb14610251578063dd62ed3e14610281576100b4565b806306fdde03146100b9578063095ea7b3146100d757806318160ddd1461010757806323b872dd14610125578063313ce567146101555780633950935114610173575b600080fd5b6100c16102b1565b6040516100ce9190610cc1565b60405180910390f35b6100f160048036038101906100ec9190610d7c565b610343565b6040516100fe9190610dd7565b60405180910390f35b61010f610366565b60405161011c9190610e01565b60405180910390f35b61013f600480360381019061013a9190610e1c565b610370565b60405161014c9190610dd7565b60405180910390f35b61015d61039f565b60405161016a9190610e8b565b60405180910390f35b61018d60048036038101906101889190610d7c565b6103b6565b60405161019a9190610dd7565b60405180910390f35b6101bd60048036038101906101b89190610d7c565b6103ed565b6040516101ca9190610dd7565b60405180910390f35b6101ed60048036038101906101e89190610ea6565b610403565b6040516101fa9190610e01565b60405180910390f35b61020b61044b565b6040516102189190610cc1565b60405180910390f35b61023b60048036038101906102369190610d7c565b6104dd565b6040516102489190610dd7565b60405180910390f35b61026b60048036038101906102669190610d7c565b610554565b6040516102789190610dd7565b60405180910390f35b61029b60048036038101906102969190610ed3565b610577565b6040516102a89190610e01565b60405180910390f35b6060600380546102c090610f42565b80601f01602080910402602001604051908101604052809291908181526020018280546102ec90610f42565b80156103395780601f1061030e57610100808354040283529160200191610339565b820191906000526020600020905b81548152906001019060200180831161031c57829003601f168201915b5050505050905090565b60008061034e6105fe565b905061035b818585610606565b600191505092915050565b6000600254905090565b60008061037b6105fe565b90506103888582856107cf565b61039385858561085b565b60019150509392505050565b6000600560009054906101000a900460ff16905090565b6000806103c16105fe565b90506103e28185856103d38589610577565b6103dd9190610fa2565b610606565b600191505092915050565b60006103f98383610ad1565b6001905092915050565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b60606004805461045a90610f42565b80601f016020809104026020016040519081016040528092919081815260200182805461048690610f42565b80156104d35780601f106104a8576101008083540402835291602001916104d3565b820191906000526020600020905b8154815290600101906020018083116104b657829003601f168201915b5050505050905090565b6000806104e86105fe565b905060006104f68286610577565b90508381101561053b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161053290611048565b60405180910390fd5b6105488286868403610606565b60019250505092915050565b60008061055f6105fe565b905061056c81858561085b565b600191505092915050565b6000600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905092915050565b600033905090565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603610675576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161066c906110da565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036106e4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106db9061116c565b60405180910390fd5b80600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925836040516107c29190610e01565b60405180910390a3505050565b60006107db8484610577565b90507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146108555781811015610847576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161083e906111d8565b60405180910390fd5b6108548484848403610606565b5b50505050565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16036108ca576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108c19061126a565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610939576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610930906112fc565b60405180910390fd5b610944838383610c27565b60008060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050818110156109ca576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109c19061138e565b60405180910390fd5b8181036000808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84604051610ab89190610e01565b60405180910390a3610acb848484610c2c565b50505050565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610b40576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b37906113fa565b60405180910390fd5b610b4c60008383610c27565b8060026000828254610b5e9190610fa2565b92505081905550806000808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508173ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef83604051610c0f9190610e01565b60405180910390a3610c2360008383610c2c565b5050565b505050565b505050565b600081519050919050565b600082825260208201905092915050565b60005b83811015610c6b578082015181840152602081019050610c50565b60008484015250505050565b6000601f19601f8301169050919050565b6000610c9382610c31565b610c9d8185610c3c565b9350610cad818560208601610c4d565b610cb681610c77565b840191505092915050565b60006020820190508181036000830152610cdb8184610c88565b905092915050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000610d1382610ce8565b9050919050565b610d2381610d08565b8114610d2e57600080fd5b50565b600081359050610d4081610d1a565b92915050565b6000819050919050565b610d5981610d46565b8114610d6457600080fd5b50565b600081359050610d7681610d50565b92915050565b60008060408385031215610d9357610d92610ce3565b5b6000610da185828601610d31565b9250506020610db285828601610d67565b9150509250929050565b60008115159050919050565b610dd181610dbc565b82525050565b6000602082019050610dec6000830184610dc8565b92915050565b610dfb81610d46565b82525050565b6000602082019050610e166000830184610df2565b92915050565b600080600060608486031215610e3557610e34610ce3565b5b6000610e4386828701610d31565b9350506020610e5486828701610d31565b9250506040610e6586828701610d67565b9150509250925092565b600060ff82169050919050565b610e8581610e6f565b82525050565b6000602082019050610ea06000830184610e7c565b92915050565b600060208284031215610ebc57610ebb610ce3565b5b6000610eca84828501610d31565b91505092915050565b60008060408385031215610eea57610ee9610ce3565b5b6000610ef885828601610d31565b9250506020610f0985828601610d31565b9150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b60006002820490506001821680610f5a57607f821691505b602082108103610f6d57610f6c610f13565b5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000610fad82610d46565b9150610fb883610d46565b9250828201905080821115610fd057610fcf610f73565b5b92915050565b7f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f7760008201527f207a65726f000000000000000000000000000000000000000000000000000000602082015250565b6000611032602583610c3c565b915061103d82610fd6565b604082019050919050565b6000602082019050818103600083015261106181611025565b9050919050565b7f45524332303a20617070726f76652066726f6d20746865207a65726f2061646460008201527f7265737300000000000000000000000000000000000000000000000000000000602082015250565b60006110c4602483610c3c565b91506110cf82611068565b604082019050919050565b600060208201905081810360008301526110f3816110b7565b9050919050565b7f45524332303a20617070726f766520746f20746865207a65726f20616464726560008201527f7373000000000000000000000000000000000000000000000000000000000000602082015250565b6000611156602283610c3c565b9150611161826110fa565b604082019050919050565b6000602082019050818103600083015261118581611149565b9050919050565b7f45524332303a20696e73756666696369656e7420616c6c6f77616e6365000000600082015250565b60006111c2601d83610c3c565b91506111cd8261118c565b602082019050919050565b600060208201905081810360008301526111f1816111b5565b9050919050565b7f45524332303a207472616e736665722066726f6d20746865207a65726f20616460008201527f6472657373000000000000000000000000000000000000000000000000000000602082015250565b6000611254602583610c3c565b915061125f826111f8565b604082019050919050565b6000602082019050818103600083015261128381611247565b9050919050565b7f45524332303a207472616e7366657220746f20746865207a65726f206164647260008201527f6573730000000000000000000000000000000000000000000000000000000000602082015250565b60006112e6602383610c3c565b91506112f18261128a565b604082019050919050565b60006020820190508181036000830152611315816112d9565b9050919050565b7f45524332303a207472616e7366657220616d6f756e742065786365656473206260008201527f616c616e63650000000000000000000000000000000000000000000000000000602082015250565b6000611378602683610c3c565b91506113838261131c565b604082019050919050565b600060208201905081810360008301526113a78161136b565b9050919050565b7f45524332303a206d696e7420746f20746865207a65726f206164647265737300600082015250565b60006113e4601f83610c3c565b91506113ef826113ae565b602082019050919050565b60006020820190508181036000830152611413816113d7565b905091905056fea2646970667358221220000337f45cfac5d1f414a2e9ac8d9051c93d7cab29f64c5a5d1f8167426908db64736f6c63430008130033", +} + +// TokenABI is the input ABI used to generate the binding from. +// Deprecated: Use TokenMetaData.ABI instead. +var TokenABI = TokenMetaData.ABI + +// TokenBin is the compiled bytecode used for deploying new contracts. +// Deprecated: Use TokenMetaData.Bin instead. +var TokenBin = TokenMetaData.Bin + +// DeployToken deploys a new Ethereum contract, binding an instance of Token to it. +func DeployToken(auth *bind.TransactOpts, backend bind.ContractBackend, name_ string, symbol_ string, decimals_ uint8) (common.Address, *types.Transaction, *Token, error) { + parsed, err := TokenMetaData.GetAbi() + if err != nil { + return common.Address{}, nil, nil, err + } + if parsed == nil { + return common.Address{}, nil, nil, errors.New("GetABI returned nil") + } + + address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(TokenBin), backend, name_, symbol_, decimals_) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &Token{TokenCaller: TokenCaller{contract: contract}, TokenTransactor: TokenTransactor{contract: contract}, TokenFilterer: TokenFilterer{contract: contract}}, nil +} + +// Token is an auto generated Go binding around an Ethereum contract. +type Token struct { + TokenCaller // Read-only binding to the contract + TokenTransactor // Write-only binding to the contract + TokenFilterer // Log filterer for contract events +} + +// TokenCaller is an auto generated read-only Go binding around an Ethereum contract. +type TokenCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// TokenTransactor is an auto generated write-only Go binding around an Ethereum contract. +type TokenTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// TokenFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type TokenFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// TokenSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type TokenSession struct { + Contract *Token // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// TokenCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type TokenCallerSession struct { + Contract *TokenCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// TokenTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type TokenTransactorSession struct { + Contract *TokenTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// TokenRaw is an auto generated low-level Go binding around an Ethereum contract. +type TokenRaw struct { + Contract *Token // Generic contract binding to access the raw methods on +} + +// TokenCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type TokenCallerRaw struct { + Contract *TokenCaller // Generic read-only contract binding to access the raw methods on +} + +// TokenTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type TokenTransactorRaw struct { + Contract *TokenTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewToken creates a new instance of Token, bound to a specific deployed contract. +func NewToken(address common.Address, backend bind.ContractBackend) (*Token, error) { + contract, err := bindToken(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &Token{TokenCaller: TokenCaller{contract: contract}, TokenTransactor: TokenTransactor{contract: contract}, TokenFilterer: TokenFilterer{contract: contract}}, nil +} + +// NewTokenCaller creates a new read-only instance of Token, bound to a specific deployed contract. +func NewTokenCaller(address common.Address, caller bind.ContractCaller) (*TokenCaller, error) { + contract, err := bindToken(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &TokenCaller{contract: contract}, nil +} + +// NewTokenTransactor creates a new write-only instance of Token, bound to a specific deployed contract. +func NewTokenTransactor(address common.Address, transactor bind.ContractTransactor) (*TokenTransactor, error) { + contract, err := bindToken(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &TokenTransactor{contract: contract}, nil +} + +// NewTokenFilterer creates a new log filterer instance of Token, bound to a specific deployed contract. +func NewTokenFilterer(address common.Address, filterer bind.ContractFilterer) (*TokenFilterer, error) { + contract, err := bindToken(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &TokenFilterer{contract: contract}, nil +} + +// bindToken binds a generic wrapper to an already deployed contract. +func bindToken(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := TokenMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_Token *TokenRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _Token.Contract.TokenCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_Token *TokenRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Token.Contract.TokenTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Token *TokenRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Token.Contract.TokenTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_Token *TokenCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _Token.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_Token *TokenTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Token.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Token *TokenTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Token.Contract.contract.Transact(opts, method, params...) +} + +// Allowance is a free data retrieval call binding the contract method 0xdd62ed3e. +// +// Solidity: function allowance(address owner, address spender) view returns(uint256) +func (_Token *TokenCaller) Allowance(opts *bind.CallOpts, owner common.Address, spender common.Address) (*big.Int, error) { + var out []interface{} + err := _Token.contract.Call(opts, &out, "allowance", owner, spender) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// Allowance is a free data retrieval call binding the contract method 0xdd62ed3e. +// +// Solidity: function allowance(address owner, address spender) view returns(uint256) +func (_Token *TokenSession) Allowance(owner common.Address, spender common.Address) (*big.Int, error) { + return _Token.Contract.Allowance(&_Token.CallOpts, owner, spender) +} + +// Allowance is a free data retrieval call binding the contract method 0xdd62ed3e. +// +// Solidity: function allowance(address owner, address spender) view returns(uint256) +func (_Token *TokenCallerSession) Allowance(owner common.Address, spender common.Address) (*big.Int, error) { + return _Token.Contract.Allowance(&_Token.CallOpts, owner, spender) +} + +// BalanceOf is a free data retrieval call binding the contract method 0x70a08231. +// +// Solidity: function balanceOf(address account) view returns(uint256) +func (_Token *TokenCaller) BalanceOf(opts *bind.CallOpts, account common.Address) (*big.Int, error) { + var out []interface{} + err := _Token.contract.Call(opts, &out, "balanceOf", account) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// BalanceOf is a free data retrieval call binding the contract method 0x70a08231. +// +// Solidity: function balanceOf(address account) view returns(uint256) +func (_Token *TokenSession) BalanceOf(account common.Address) (*big.Int, error) { + return _Token.Contract.BalanceOf(&_Token.CallOpts, account) +} + +// BalanceOf is a free data retrieval call binding the contract method 0x70a08231. +// +// Solidity: function balanceOf(address account) view returns(uint256) +func (_Token *TokenCallerSession) BalanceOf(account common.Address) (*big.Int, error) { + return _Token.Contract.BalanceOf(&_Token.CallOpts, account) +} + +// Decimals is a free data retrieval call binding the contract method 0x313ce567. +// +// Solidity: function decimals() view returns(uint8) +func (_Token *TokenCaller) Decimals(opts *bind.CallOpts) (uint8, error) { + var out []interface{} + err := _Token.contract.Call(opts, &out, "decimals") + + if err != nil { + return *new(uint8), err + } + + out0 := *abi.ConvertType(out[0], new(uint8)).(*uint8) + + return out0, err + +} + +// Decimals is a free data retrieval call binding the contract method 0x313ce567. +// +// Solidity: function decimals() view returns(uint8) +func (_Token *TokenSession) Decimals() (uint8, error) { + return _Token.Contract.Decimals(&_Token.CallOpts) +} + +// Decimals is a free data retrieval call binding the contract method 0x313ce567. +// +// Solidity: function decimals() view returns(uint8) +func (_Token *TokenCallerSession) Decimals() (uint8, error) { + return _Token.Contract.Decimals(&_Token.CallOpts) +} + +// Name is a free data retrieval call binding the contract method 0x06fdde03. +// +// Solidity: function name() view returns(string) +func (_Token *TokenCaller) Name(opts *bind.CallOpts) (string, error) { + var out []interface{} + err := _Token.contract.Call(opts, &out, "name") + + if err != nil { + return *new(string), err + } + + out0 := *abi.ConvertType(out[0], new(string)).(*string) + + return out0, err + +} + +// Name is a free data retrieval call binding the contract method 0x06fdde03. +// +// Solidity: function name() view returns(string) +func (_Token *TokenSession) Name() (string, error) { + return _Token.Contract.Name(&_Token.CallOpts) +} + +// Name is a free data retrieval call binding the contract method 0x06fdde03. +// +// Solidity: function name() view returns(string) +func (_Token *TokenCallerSession) Name() (string, error) { + return _Token.Contract.Name(&_Token.CallOpts) +} + +// Symbol is a free data retrieval call binding the contract method 0x95d89b41. +// +// Solidity: function symbol() view returns(string) +func (_Token *TokenCaller) Symbol(opts *bind.CallOpts) (string, error) { + var out []interface{} + err := _Token.contract.Call(opts, &out, "symbol") + + if err != nil { + return *new(string), err + } + + out0 := *abi.ConvertType(out[0], new(string)).(*string) + + return out0, err + +} + +// Symbol is a free data retrieval call binding the contract method 0x95d89b41. +// +// Solidity: function symbol() view returns(string) +func (_Token *TokenSession) Symbol() (string, error) { + return _Token.Contract.Symbol(&_Token.CallOpts) +} + +// Symbol is a free data retrieval call binding the contract method 0x95d89b41. +// +// Solidity: function symbol() view returns(string) +func (_Token *TokenCallerSession) Symbol() (string, error) { + return _Token.Contract.Symbol(&_Token.CallOpts) +} + +// TotalSupply is a free data retrieval call binding the contract method 0x18160ddd. +// +// Solidity: function totalSupply() view returns(uint256) +func (_Token *TokenCaller) TotalSupply(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _Token.contract.Call(opts, &out, "totalSupply") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// TotalSupply is a free data retrieval call binding the contract method 0x18160ddd. +// +// Solidity: function totalSupply() view returns(uint256) +func (_Token *TokenSession) TotalSupply() (*big.Int, error) { + return _Token.Contract.TotalSupply(&_Token.CallOpts) +} + +// TotalSupply is a free data retrieval call binding the contract method 0x18160ddd. +// +// Solidity: function totalSupply() view returns(uint256) +func (_Token *TokenCallerSession) TotalSupply() (*big.Int, error) { + return _Token.Contract.TotalSupply(&_Token.CallOpts) +} + +// Approve is a paid mutator transaction binding the contract method 0x095ea7b3. +// +// Solidity: function approve(address spender, uint256 amount) returns(bool) +func (_Token *TokenTransactor) Approve(opts *bind.TransactOpts, spender common.Address, amount *big.Int) (*types.Transaction, error) { + return _Token.contract.Transact(opts, "approve", spender, amount) +} + +// Approve is a paid mutator transaction binding the contract method 0x095ea7b3. +// +// Solidity: function approve(address spender, uint256 amount) returns(bool) +func (_Token *TokenSession) Approve(spender common.Address, amount *big.Int) (*types.Transaction, error) { + return _Token.Contract.Approve(&_Token.TransactOpts, spender, amount) +} + +// Approve is a paid mutator transaction binding the contract method 0x095ea7b3. +// +// Solidity: function approve(address spender, uint256 amount) returns(bool) +func (_Token *TokenTransactorSession) Approve(spender common.Address, amount *big.Int) (*types.Transaction, error) { + return _Token.Contract.Approve(&_Token.TransactOpts, spender, amount) +} + +// DecreaseAllowance is a paid mutator transaction binding the contract method 0xa457c2d7. +// +// Solidity: function decreaseAllowance(address spender, uint256 subtractedValue) returns(bool) +func (_Token *TokenTransactor) DecreaseAllowance(opts *bind.TransactOpts, spender common.Address, subtractedValue *big.Int) (*types.Transaction, error) { + return _Token.contract.Transact(opts, "decreaseAllowance", spender, subtractedValue) +} + +// DecreaseAllowance is a paid mutator transaction binding the contract method 0xa457c2d7. +// +// Solidity: function decreaseAllowance(address spender, uint256 subtractedValue) returns(bool) +func (_Token *TokenSession) DecreaseAllowance(spender common.Address, subtractedValue *big.Int) (*types.Transaction, error) { + return _Token.Contract.DecreaseAllowance(&_Token.TransactOpts, spender, subtractedValue) +} + +// DecreaseAllowance is a paid mutator transaction binding the contract method 0xa457c2d7. +// +// Solidity: function decreaseAllowance(address spender, uint256 subtractedValue) returns(bool) +func (_Token *TokenTransactorSession) DecreaseAllowance(spender common.Address, subtractedValue *big.Int) (*types.Transaction, error) { + return _Token.Contract.DecreaseAllowance(&_Token.TransactOpts, spender, subtractedValue) +} + +// IncreaseAllowance is a paid mutator transaction binding the contract method 0x39509351. +// +// Solidity: function increaseAllowance(address spender, uint256 addedValue) returns(bool) +func (_Token *TokenTransactor) IncreaseAllowance(opts *bind.TransactOpts, spender common.Address, addedValue *big.Int) (*types.Transaction, error) { + return _Token.contract.Transact(opts, "increaseAllowance", spender, addedValue) +} + +// IncreaseAllowance is a paid mutator transaction binding the contract method 0x39509351. +// +// Solidity: function increaseAllowance(address spender, uint256 addedValue) returns(bool) +func (_Token *TokenSession) IncreaseAllowance(spender common.Address, addedValue *big.Int) (*types.Transaction, error) { + return _Token.Contract.IncreaseAllowance(&_Token.TransactOpts, spender, addedValue) +} + +// IncreaseAllowance is a paid mutator transaction binding the contract method 0x39509351. +// +// Solidity: function increaseAllowance(address spender, uint256 addedValue) returns(bool) +func (_Token *TokenTransactorSession) IncreaseAllowance(spender common.Address, addedValue *big.Int) (*types.Transaction, error) { + return _Token.Contract.IncreaseAllowance(&_Token.TransactOpts, spender, addedValue) +} + +// Mint is a paid mutator transaction binding the contract method 0x40c10f19. +// +// Solidity: function mint(address _to, uint256 _amount) returns(bool) +func (_Token *TokenTransactor) Mint(opts *bind.TransactOpts, _to common.Address, _amount *big.Int) (*types.Transaction, error) { + return _Token.contract.Transact(opts, "mint", _to, _amount) +} + +// Mint is a paid mutator transaction binding the contract method 0x40c10f19. +// +// Solidity: function mint(address _to, uint256 _amount) returns(bool) +func (_Token *TokenSession) Mint(_to common.Address, _amount *big.Int) (*types.Transaction, error) { + return _Token.Contract.Mint(&_Token.TransactOpts, _to, _amount) +} + +// Mint is a paid mutator transaction binding the contract method 0x40c10f19. +// +// Solidity: function mint(address _to, uint256 _amount) returns(bool) +func (_Token *TokenTransactorSession) Mint(_to common.Address, _amount *big.Int) (*types.Transaction, error) { + return _Token.Contract.Mint(&_Token.TransactOpts, _to, _amount) +} + +// Transfer is a paid mutator transaction binding the contract method 0xa9059cbb. +// +// Solidity: function transfer(address to, uint256 amount) returns(bool) +func (_Token *TokenTransactor) Transfer(opts *bind.TransactOpts, to common.Address, amount *big.Int) (*types.Transaction, error) { + return _Token.contract.Transact(opts, "transfer", to, amount) +} + +// Transfer is a paid mutator transaction binding the contract method 0xa9059cbb. +// +// Solidity: function transfer(address to, uint256 amount) returns(bool) +func (_Token *TokenSession) Transfer(to common.Address, amount *big.Int) (*types.Transaction, error) { + return _Token.Contract.Transfer(&_Token.TransactOpts, to, amount) +} + +// Transfer is a paid mutator transaction binding the contract method 0xa9059cbb. +// +// Solidity: function transfer(address to, uint256 amount) returns(bool) +func (_Token *TokenTransactorSession) Transfer(to common.Address, amount *big.Int) (*types.Transaction, error) { + return _Token.Contract.Transfer(&_Token.TransactOpts, to, amount) +} + +// TransferFrom is a paid mutator transaction binding the contract method 0x23b872dd. +// +// Solidity: function transferFrom(address from, address to, uint256 amount) returns(bool) +func (_Token *TokenTransactor) TransferFrom(opts *bind.TransactOpts, from common.Address, to common.Address, amount *big.Int) (*types.Transaction, error) { + return _Token.contract.Transact(opts, "transferFrom", from, to, amount) +} + +// TransferFrom is a paid mutator transaction binding the contract method 0x23b872dd. +// +// Solidity: function transferFrom(address from, address to, uint256 amount) returns(bool) +func (_Token *TokenSession) TransferFrom(from common.Address, to common.Address, amount *big.Int) (*types.Transaction, error) { + return _Token.Contract.TransferFrom(&_Token.TransactOpts, from, to, amount) +} + +// TransferFrom is a paid mutator transaction binding the contract method 0x23b872dd. +// +// Solidity: function transferFrom(address from, address to, uint256 amount) returns(bool) +func (_Token *TokenTransactorSession) TransferFrom(from common.Address, to common.Address, amount *big.Int) (*types.Transaction, error) { + return _Token.Contract.TransferFrom(&_Token.TransactOpts, from, to, amount) +} + +// TokenApprovalIterator is returned from FilterApproval and is used to iterate over the raw logs and unpacked data for Approval events raised by the Token contract. +type TokenApprovalIterator struct { + Event *TokenApproval // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *TokenApprovalIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(TokenApproval) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(TokenApproval) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *TokenApprovalIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *TokenApprovalIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// TokenApproval represents a Approval event raised by the Token contract. +type TokenApproval struct { + Owner common.Address + Spender common.Address + Value *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterApproval is a free log retrieval operation binding the contract event 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925. +// +// Solidity: event Approval(address indexed owner, address indexed spender, uint256 value) +func (_Token *TokenFilterer) FilterApproval(opts *bind.FilterOpts, owner []common.Address, spender []common.Address) (*TokenApprovalIterator, error) { + + var ownerRule []interface{} + for _, ownerItem := range owner { + ownerRule = append(ownerRule, ownerItem) + } + var spenderRule []interface{} + for _, spenderItem := range spender { + spenderRule = append(spenderRule, spenderItem) + } + + logs, sub, err := _Token.contract.FilterLogs(opts, "Approval", ownerRule, spenderRule) + if err != nil { + return nil, err + } + return &TokenApprovalIterator{contract: _Token.contract, event: "Approval", logs: logs, sub: sub}, nil +} + +// WatchApproval is a free log subscription operation binding the contract event 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925. +// +// Solidity: event Approval(address indexed owner, address indexed spender, uint256 value) +func (_Token *TokenFilterer) WatchApproval(opts *bind.WatchOpts, sink chan<- *TokenApproval, owner []common.Address, spender []common.Address) (event.Subscription, error) { + + var ownerRule []interface{} + for _, ownerItem := range owner { + ownerRule = append(ownerRule, ownerItem) + } + var spenderRule []interface{} + for _, spenderItem := range spender { + spenderRule = append(spenderRule, spenderItem) + } + + logs, sub, err := _Token.contract.WatchLogs(opts, "Approval", ownerRule, spenderRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(TokenApproval) + if err := _Token.contract.UnpackLog(event, "Approval", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseApproval is a log parse operation binding the contract event 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925. +// +// Solidity: event Approval(address indexed owner, address indexed spender, uint256 value) +func (_Token *TokenFilterer) ParseApproval(log types.Log) (*TokenApproval, error) { + event := new(TokenApproval) + if err := _Token.contract.UnpackLog(event, "Approval", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// TokenTransferIterator is returned from FilterTransfer and is used to iterate over the raw logs and unpacked data for Transfer events raised by the Token contract. +type TokenTransferIterator struct { + Event *TokenTransfer // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *TokenTransferIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(TokenTransfer) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(TokenTransfer) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *TokenTransferIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *TokenTransferIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// TokenTransfer represents a Transfer event raised by the Token contract. +type TokenTransfer struct { + From common.Address + To common.Address + Value *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterTransfer is a free log retrieval operation binding the contract event 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef. +// +// Solidity: event Transfer(address indexed from, address indexed to, uint256 value) +func (_Token *TokenFilterer) FilterTransfer(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*TokenTransferIterator, error) { + + var fromRule []interface{} + for _, fromItem := range from { + fromRule = append(fromRule, fromItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _Token.contract.FilterLogs(opts, "Transfer", fromRule, toRule) + if err != nil { + return nil, err + } + return &TokenTransferIterator{contract: _Token.contract, event: "Transfer", logs: logs, sub: sub}, nil +} + +// WatchTransfer is a free log subscription operation binding the contract event 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef. +// +// Solidity: event Transfer(address indexed from, address indexed to, uint256 value) +func (_Token *TokenFilterer) WatchTransfer(opts *bind.WatchOpts, sink chan<- *TokenTransfer, from []common.Address, to []common.Address) (event.Subscription, error) { + + var fromRule []interface{} + for _, fromItem := range from { + fromRule = append(fromRule, fromItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _Token.contract.WatchLogs(opts, "Transfer", fromRule, toRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(TokenTransfer) + if err := _Token.contract.UnpackLog(event, "Transfer", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseTransfer is a log parse operation binding the contract event 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef. +// +// Solidity: event Transfer(address indexed from, address indexed to, uint256 value) +func (_Token *TokenFilterer) ParseTransfer(log types.Log) (*TokenTransfer, error) { + event := new(TokenTransfer) + if err := _Token.contract.UnpackLog(event, "Transfer", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} diff --git a/js/.gitignore b/js/.gitignore index b7dab5e..1738f88 100644 --- a/js/.gitignore +++ b/js/.gitignore @@ -1,2 +1,3 @@ node_modules -build \ No newline at end of file +build +tests/token.json \ No newline at end of file diff --git a/js/.prettierignore b/js/.prettierignore new file mode 100644 index 0000000..bf14ccc --- /dev/null +++ b/js/.prettierignore @@ -0,0 +1,5 @@ +node_modules +.github +.idea +.nycrc +tests/files \ No newline at end of file diff --git a/js/.prettierrc b/js/.prettierrc new file mode 100644 index 0000000..72db770 --- /dev/null +++ b/js/.prettierrc @@ -0,0 +1,4 @@ +{ + "printWidth": 105, + "tabWidth": 4 +} diff --git a/js/package.json b/js/package.json index d59759a..8c77c71 100644 --- a/js/package.json +++ b/js/package.json @@ -1,17 +1,31 @@ { - "name": "zksync2-js-examples", - "version": "0.1.0", - "license": "MIT", - "devDependencies": { - "@types/node": "^20.5.2", - "ethers": "^6.7.1", - "ts-node": "^10.9.1", - "typescript": "^5.1.6" - }, - "peerDependencies": { - "ethers": "^6.7.1" - }, - "dependencies": { - "zksync-ethers": "^6.0.0" - } -} \ No newline at end of file + "name": "zksync2-js-examples", + "version": "0.1.0", + "license": "MIT", + "devDependencies": { + "@types/chai": "^4.3.9", + "@types/mocha": "^10.0.1", + "@types/node": "^20.5.2", + "c8": "^8.0.1", + "chai": "^4.3.10", + "ethers": "^6.7.1", + "mocha": "^10.2.0", + "prettier": "3.0.3", + "ts-node": "^10.9.1", + "typescript": "^5.1.6" + }, + "peerDependencies": { + "ethers": "^6.9.0" + }, + "dependencies": { + "zksync-ethers": "^6.0.0" + }, + "scripts": { + "test:prepare": "cd tests/setup/ && ./setup.sh && cd ../..", + "test:wait": "ts-node tests/wait.ts", + "test": "mocha -r ts-node/register tests/*.test.ts", + "lint": "prettier . --write", + "lint:check": "prettier . --check", + "watch": "tsc --watch" + } +} diff --git a/js/src/01_deposit.ts b/js/src/01_deposit.ts index aba2f6d..b2182a9 100644 --- a/js/src/01_deposit.ts +++ b/js/src/01_deposit.ts @@ -1,12 +1,11 @@ -import {Provider, types, utils, Wallet} from "zksync-ethers"; -import {ethers} from "ethers"; +import { Provider, types, utils, Wallet } from "zksync-ethers"; +import { ethers } from "ethers"; const provider = Provider.getDefaultProvider(types.Network.Sepolia); const ethProvider = ethers.getDefaultProvider("sepolia"); const PRIVATE_KEY = process.env.PRIVATE_KEY; const wallet = new Wallet(PRIVATE_KEY, provider, ethProvider); - async function main() { console.log(`L2 balance before deposit: ${await wallet.getBalance()}`); console.log(`L1 balance before deposit: ${await wallet.getBalanceL1()}`); @@ -15,15 +14,17 @@ async function main() { token: utils.ETH_ADDRESS, to: await wallet.getAddress(), amount: ethers.parseEther("0.00020"), - refundRecipient: await wallet.getAddress() + refundRecipient: await wallet.getAddress(), }); - const receipt = await tx.wait(); + const receipt = await tx.wait(); console.log(`Tx: ${receipt.hash}`); console.log(`L2 balance after deposit: ${await wallet.getBalance()}`); console.log(`L1 balance after deposit: ${await wallet.getBalanceL1()}`); } -main().then().catch(error => { - console.log(`Error: ${error}`); -}) \ No newline at end of file +main() + .then() + .catch((error) => { + console.log(`Error: ${error}`); + }); diff --git a/js/src/02_transfer.ts b/js/src/02_transfer.ts index 18cd07e..c74789a 100644 --- a/js/src/02_transfer.ts +++ b/js/src/02_transfer.ts @@ -1,12 +1,11 @@ -import {Provider, types, Wallet} from "zksync-ethers"; -import {ethers} from "ethers"; +import { Provider, types, Wallet } from "zksync-ethers"; +import { ethers } from "ethers"; const provider = Provider.getDefaultProvider(types.Network.Sepolia); const ethProvider = ethers.getDefaultProvider("sepolia"); const PRIVATE_KEY = process.env.PRIVATE_KEY; const wallet = new Wallet(PRIVATE_KEY, provider, ethProvider); - async function main() { const receiver = "0x81E9D85b65E9CC8618D85A1110e4b1DF63fA30d9"; @@ -17,13 +16,15 @@ async function main() { to: receiver, amount: ethers.parseEther("0.01"), }); - const receipt = await tx.wait(); + const receipt = await tx.wait(); console.log(`Tx: ${receipt.hash}`); console.log(`Account1 balance after transfer: ${await wallet.getBalance()}`); console.log(`Account2 balance after transfer: ${await provider.getBalance(receiver)}`); } -main().then().catch(error => { - console.log(`Error: ${error}`); -}) \ No newline at end of file +main() + .then() + .catch((error) => { + console.log(`Error: ${error}`); + }); diff --git a/js/src/03_withdraw.ts b/js/src/03_withdraw.ts index 46547cf..303a28d 100644 --- a/js/src/03_withdraw.ts +++ b/js/src/03_withdraw.ts @@ -1,12 +1,11 @@ -import {Provider, types, utils, Wallet} from "zksync-ethers"; -import {ethers} from "ethers"; +import { Provider, types, utils, Wallet } from "zksync-ethers"; +import { ethers } from "ethers"; const provider = Provider.getDefaultProvider(types.Network.Sepolia); const ethProvider = ethers.getDefaultProvider("sepolia"); const PRIVATE_KEY = process.env.PRIVATE_KEY; const wallet = new Wallet(PRIVATE_KEY, provider, ethProvider); - async function main() { console.log(`L2 balance before withdraw: ${await wallet.getBalance()}`); console.log(`L1 balance before withdraw: ${await wallet.getBalanceL1()}`); @@ -16,7 +15,7 @@ async function main() { to: await wallet.getAddress(), amount: ethers.parseEther("0.00020"), }); - const receipt = await tx.wait(); + const receipt = await tx.wait(); console.log(`Tx: ${receipt.hash}`); // The duration for submitting a withdrawal transaction to L1 can last up to 24 hours. For additional information, @@ -25,6 +24,8 @@ async function main() { // To learn more about how to achieve this, please take a look at the 04_finalize_withdraw.ts script. } -main().then().catch(error => { - console.log(`Error: ${error}`); -}) \ No newline at end of file +main() + .then() + .catch((error) => { + console.log(`Error: ${error}`); + }); diff --git a/js/src/04_finalize_withdraw.ts b/js/src/04_finalize_withdraw.ts index 81416c8..f21f98f 100644 --- a/js/src/04_finalize_withdraw.ts +++ b/js/src/04_finalize_withdraw.ts @@ -1,5 +1,5 @@ -import {Provider, types, Wallet} from "zksync-ethers"; -import {ethers} from "ethers"; +import { Provider, types, Wallet } from "zksync-ethers"; +import { ethers } from "ethers"; const provider = Provider.getDefaultProvider(types.Network.Sepolia); const ethProvider = ethers.getDefaultProvider("sepolia"); @@ -9,12 +9,11 @@ const wallet = new Wallet(PRIVATE_KEY, provider, ethProvider); const WITHDRAW_TX = process.env.WITHDRAW_TX; async function main() { - // Perform the finalize withdrawal if it has not been already finalized. // On the testnet, withdrawals are automatically finalized. For additional information, please refer // to the documentation: https://era.zksync.io/docs/reference/concepts/bridging-asset.html#withdrawals-to-l1. // There is no need to execute FinalizeWithdraw, otherwise, an error with code `jj` would occur. - if (! (await wallet.isWithdrawalFinalized(WITHDRAW_TX))) { + if (!(await wallet.isWithdrawalFinalized(WITHDRAW_TX))) { const finalizeWithdrawTx = await wallet.finalizeWithdrawal(WITHDRAW_TX); const receipt = await finalizeWithdrawTx.wait(); console.log(`Tx: ${receipt.hash}`); @@ -24,6 +23,8 @@ async function main() { } } -main().then().catch(error => { - console.log(`Error: ${error}`); -}) \ No newline at end of file +main() + .then() + .catch((error) => { + console.log(`Error: ${error}`); + }); diff --git a/js/src/05_deposit_token.ts b/js/src/05_deposit_token.ts index a96f480..6121ee7 100644 --- a/js/src/05_deposit_token.ts +++ b/js/src/05_deposit_token.ts @@ -1,13 +1,11 @@ -import {Provider, types, Wallet} from "zksync-ethers"; -import {ethers} from "ethers"; +import { Provider, types, Wallet } from "zksync-ethers"; +import { ethers } from "ethers"; const provider = Provider.getDefaultProvider(types.Network.Sepolia); const ethProvider = ethers.getDefaultProvider("sepolia"); const PRIVATE_KEY = process.env.PRIVATE_KEY; const wallet = new Wallet(PRIVATE_KEY, provider, ethProvider); - - async function main() { // Crown token which can be mint for free const tokenL1 = "0x56E69Fa1BB0d1402c89E3A4E3417882DeA6B14Be"; @@ -21,16 +19,17 @@ async function main() { to: await wallet.getAddress(), amount: 5, approveERC20: true, - refundRecipient: await wallet.getAddress() + refundRecipient: await wallet.getAddress(), }); - const receipt = await tx.wait(); + const receipt = await tx.wait(); console.log(`Tx: ${receipt.hash}`); console.log(`L2 balance after deposit: ${await wallet.getBalance(tokenL2)}`); console.log(`L1 balance after deposit: ${await wallet.getBalanceL1(tokenL1)}`); - } -main().then().catch(error => { - console.log(`Error: ${error}`); -}) \ No newline at end of file +main() + .then() + .catch((error) => { + console.log(`Error: ${error}`); + }); diff --git a/js/src/06_transfer_token.ts b/js/src/06_transfer_token.ts index d64005b..e1ddd10 100644 --- a/js/src/06_transfer_token.ts +++ b/js/src/06_transfer_token.ts @@ -1,31 +1,36 @@ -import {Provider, types, Wallet} from "zksync-ethers"; -import {ethers} from "ethers"; +import { Provider, types, Wallet } from "zksync-ethers"; +import { ethers } from "ethers"; const provider = Provider.getDefaultProvider(types.Network.Sepolia); const ethProvider = ethers.getDefaultProvider("sepolia"); const PRIVATE_KEY = process.env.PRIVATE_KEY; const wallet = new Wallet(PRIVATE_KEY, provider, ethProvider); - async function main() { const token = "0x6a4Fb925583F7D4dF82de62d98107468aE846FD1"; const receiver = "0x81E9D85b65E9CC8618D85A1110e4b1DF63fA30d9"; console.log(`Account1 balance before transfer: ${await wallet.getBalance(token)}`); - console.log(`Account2 balance before transfer: ${await provider.getBalance(receiver, 'latest', token)}`); + console.log( + `Account2 balance before transfer: ${await provider.getBalance(receiver, "latest", token)}`, + ); const tx = await wallet.transfer({ token: token, to: receiver, amount: 5, }); - const receipt = await tx.wait(); + const receipt = await tx.wait(); console.log(`Tx: ${receipt.hash}`); console.log(`Account1 balance after transfer: ${await wallet.getBalance(token)}`); - console.log(`Account2 balance after transfer: ${await provider.getBalance(receiver, 'latest', token)}`); + console.log( + `Account2 balance after transfer: ${await provider.getBalance(receiver, "latest", token)}`, + ); } -main().then().catch(error => { - console.log(`Error: ${error}`); -}) \ No newline at end of file +main() + .then() + .catch((error) => { + console.log(`Error: ${error}`); + }); diff --git a/js/src/07_withdraw_token.ts b/js/src/07_withdraw_token.ts index 001c847..bcd3427 100644 --- a/js/src/07_withdraw_token.ts +++ b/js/src/07_withdraw_token.ts @@ -1,12 +1,11 @@ -import {Provider, types, Wallet} from "zksync-ethers"; -import {ethers} from "ethers"; +import { Provider, types, Wallet } from "zksync-ethers"; +import { ethers } from "ethers"; const provider = Provider.getDefaultProvider(types.Network.Sepolia); const ethProvider = ethers.getDefaultProvider("sepolia"); const PRIVATE_KEY = process.env.PRIVATE_KEY; const wallet = new Wallet(PRIVATE_KEY, provider, ethProvider); - async function main() { const token = "0x6a4Fb925583F7D4dF82de62d98107468aE846FD1"; @@ -18,7 +17,7 @@ async function main() { to: await wallet.getAddress(), amount: 5, }); - const receipt = await tx.wait(); + const receipt = await tx.wait(); console.log(`Tx: ${receipt.hash}`); // The duration for submitting a withdrawal transaction to L1 can last up to 24 hours. For additional information, @@ -27,6 +26,8 @@ async function main() { // To learn more about how to achieve this, please take a look at the 04_finalize_withdraw.ts script. } -main().then().catch(error => { - console.log(`Error: ${error}`); -}) \ No newline at end of file +main() + .then() + .catch((error) => { + console.log(`Error: ${error}`); + }); diff --git a/js/src/08_get_confirmed_tokens.ts b/js/src/08_get_confirmed_tokens.ts index b49fb6d..138ba60 100644 --- a/js/src/08_get_confirmed_tokens.ts +++ b/js/src/08_get_confirmed_tokens.ts @@ -1,10 +1,10 @@ -import {Provider, types} from "zksync-ethers"; +import { Provider, types } from "zksync-ethers"; const provider = Provider.getDefaultProvider(types.Network.Sepolia); function toJSON(object: any): string { return JSON.stringify(object, (key, value) => { - if (typeof value === 'bigint') { + if (typeof value === "bigint") { return value.toString(); // Convert BigInt to string } return value; @@ -15,6 +15,8 @@ async function main() { console.log(`Confirmed tokens: ${toJSON(await provider.getConfirmedTokens())}`); } -main().then().catch(error => { - console.log(`Error: ${error}`); -}) \ No newline at end of file +main() + .then() + .catch((error) => { + console.log(`Error: ${error}`); + }); diff --git a/js/src/09_deploy_create.ts b/js/src/09_deploy_create.ts index 76721d8..a8dd99b 100644 --- a/js/src/09_deploy_create.ts +++ b/js/src/09_deploy_create.ts @@ -1,5 +1,5 @@ -import {Provider, types, Wallet, ContractFactory, Contract} from "zksync-ethers"; -import {ethers, Typed} from "ethers"; +import { Provider, types, Wallet, ContractFactory, Contract } from "zksync-ethers"; +import { ethers, Typed } from "ethers"; const provider = Provider.getDefaultProvider(types.Network.Sepolia); const PRIVATE_KEY = process.env.PRIVATE_KEY; @@ -11,7 +11,7 @@ async function main() { const bytecode: string = conf.contracts["Storage.sol:Storage"].bin; const factory = new ContractFactory(abi, bytecode, wallet); - const storage = await factory.deploy() as Contract; + const storage = (await factory.deploy()) as Contract; console.log(`Contract address: ${await storage.getAddress()}`); console.log(`Value: ${await storage.get()}`); @@ -22,6 +22,8 @@ async function main() { console.log(`Value: ${await storage.get()}`); } -main().then().catch(error => { - console.log(`Error: ${error}`); -}) \ No newline at end of file +main() + .then() + .catch((error) => { + console.log(`Error: ${error}`); + }); diff --git a/js/src/10_deploy_create_with_constructor.ts b/js/src/10_deploy_create_with_constructor.ts index 48f341f..2110df3 100644 --- a/js/src/10_deploy_create_with_constructor.ts +++ b/js/src/10_deploy_create_with_constructor.ts @@ -1,4 +1,4 @@ -import {Provider, types, Wallet, ContractFactory, Contract} from "zksync-ethers"; +import { Provider, types, Wallet, ContractFactory, Contract } from "zksync-ethers"; const provider = Provider.getDefaultProvider(types.Network.Sepolia); const PRIVATE_KEY = process.env.PRIVATE_KEY; @@ -10,7 +10,7 @@ async function main() { const bytecode: string = conf.contracts["Incrementer.sol:Incrementer"].bin; const factory = new ContractFactory(abi, bytecode, wallet); - const incrementer = await factory.deploy(2) as Contract; + const incrementer = (await factory.deploy(2)) as Contract; console.log(`Contract address: ${await incrementer.getAddress()}`); console.log(`Value before Increment method execution: ${await incrementer.get()}`); @@ -21,6 +21,8 @@ async function main() { console.log(`Value after Increment method execution: ${await incrementer.get()}`); } -main().then().catch(error => { - console.log(`Error: ${error}`); -}) \ No newline at end of file +main() + .then() + .catch((error) => { + console.log(`Error: ${error}`); + }); diff --git a/js/src/11_deploy_create_with_deps.ts b/js/src/11_deploy_create_with_deps.ts index 47d7334..d5f22ad 100644 --- a/js/src/11_deploy_create_with_deps.ts +++ b/js/src/11_deploy_create_with_deps.ts @@ -1,4 +1,4 @@ -import {Provider, types, Wallet, ContractFactory, Contract} from "zksync-ethers"; +import { Provider, types, Wallet, ContractFactory, Contract } from "zksync-ethers"; const provider = Provider.getDefaultProvider(types.Network.Sepolia); const PRIVATE_KEY = process.env.PRIVATE_KEY; @@ -10,14 +10,16 @@ async function main() { const bytecode: string = conf.contracts["Demo.sol:Demo"].bin; const factory = new ContractFactory(abi, bytecode, wallet); - const demo = await factory.deploy({ - customData: {factoryDeps: [conf.contracts["Foo.sol:Foo"].bin]} - }) as Contract; + const demo = (await factory.deploy({ + customData: { factoryDeps: [conf.contracts["Foo.sol:Foo"].bin] }, + })) as Contract; console.log(`Contract address: ${await demo.getAddress()}`); console.log(`Value: ${await demo.getFooName()}`); } -main().then().catch(error => { - console.log(`Error: ${error}`); -}) \ No newline at end of file +main() + .then() + .catch((error) => { + console.log(`Error: ${error}`); + }); diff --git a/js/src/12_deploy_create2.ts b/js/src/12_deploy_create2.ts index 4536590..4f5a84b 100644 --- a/js/src/12_deploy_create2.ts +++ b/js/src/12_deploy_create2.ts @@ -1,5 +1,5 @@ -import {Provider, types, Wallet, ContractFactory, Contract} from "zksync-ethers"; -import {ethers, Typed} from "ethers"; +import { Provider, types, Wallet, ContractFactory, Contract } from "zksync-ethers"; +import { ethers, Typed } from "ethers"; const provider = Provider.getDefaultProvider(types.Network.Sepolia); const PRIVATE_KEY = process.env.PRIVATE_KEY; @@ -11,9 +11,9 @@ async function main() { const bytecode: string = conf.contracts["Storage.sol:Storage"].bin; const factory = new ContractFactory(abi, bytecode, wallet, "create2"); - const storage = await factory.deploy({ - customData: {salt: ethers.hexlify(ethers.randomBytes(32))} - }) as Contract; + const storage = (await factory.deploy({ + customData: { salt: ethers.hexlify(ethers.randomBytes(32)) }, + })) as Contract; console.log(`Contract address: ${await storage.getAddress()}`); console.log(`Value: ${await storage.get()}`); @@ -24,6 +24,8 @@ async function main() { console.log(`Value: ${await storage.get()}`); } -main().then().catch(error => { - console.log(`Error: ${error}`); -}) \ No newline at end of file +main() + .then() + .catch((error) => { + console.log(`Error: ${error}`); + }); diff --git a/js/src/13_deploy_create2_with_constructor.ts b/js/src/13_deploy_create2_with_constructor.ts index 62a77d4..462d045 100644 --- a/js/src/13_deploy_create2_with_constructor.ts +++ b/js/src/13_deploy_create2_with_constructor.ts @@ -1,5 +1,5 @@ -import {Provider, types, Wallet, ContractFactory, Contract} from "zksync-ethers"; -import {ethers} from "ethers"; +import { Provider, types, Wallet, ContractFactory, Contract } from "zksync-ethers"; +import { ethers } from "ethers"; const provider = Provider.getDefaultProvider(types.Network.Sepolia); const PRIVATE_KEY = process.env.PRIVATE_KEY; @@ -11,9 +11,9 @@ async function main() { const bytecode: string = conf.contracts["Incrementer.sol:Incrementer"].bin; const factory = new ContractFactory(abi, bytecode, wallet, "create2"); - const incrementer = await factory.deploy(2, { - customData: {salt: ethers.hexlify(ethers.randomBytes(32))} - }) as Contract; + const incrementer = (await factory.deploy(2, { + customData: { salt: ethers.hexlify(ethers.randomBytes(32)) }, + })) as Contract; console.log(`Contract address: ${await incrementer.getAddress()}`); console.log(`Value before Increment method execution: ${await incrementer.get()}`); @@ -24,6 +24,8 @@ async function main() { console.log(`Value after Increment method execution: ${await incrementer.get()}`); } -main().then().catch(error => { - console.log(`Error: ${error}`); -}) \ No newline at end of file +main() + .then() + .catch((error) => { + console.log(`Error: ${error}`); + }); diff --git a/js/src/14_deploy_create2_with_deps.ts b/js/src/14_deploy_create2_with_deps.ts index ac15e05..f3245da 100644 --- a/js/src/14_deploy_create2_with_deps.ts +++ b/js/src/14_deploy_create2_with_deps.ts @@ -1,5 +1,5 @@ -import {Provider, types, Wallet, ContractFactory, Contract} from "zksync-ethers"; -import {ethers} from "ethers"; +import { Provider, types, Wallet, ContractFactory, Contract } from "zksync-ethers"; +import { ethers } from "ethers"; const provider = Provider.getDefaultProvider(types.Network.Sepolia); const PRIVATE_KEY = process.env.PRIVATE_KEY; @@ -11,17 +11,19 @@ async function main() { const bytecode: string = conf.contracts["Demo.sol:Demo"].bin; const factory = new ContractFactory(abi, bytecode, wallet, "create2"); - const demo = await factory.deploy({ + const demo = (await factory.deploy({ customData: { salt: ethers.hexlify(ethers.randomBytes(32)), - factoryDeps: [conf.contracts["Foo.sol:Foo"].bin] - } - }) as Contract; + factoryDeps: [conf.contracts["Foo.sol:Foo"].bin], + }, + })) as Contract; console.log(`Contract address: ${await demo.getAddress()}`); console.log(`Value: ${await demo.getFooName()}`); } -main().then().catch(error => { - console.log(`Error: ${error}`); -}) \ No newline at end of file +main() + .then() + .catch((error) => { + console.log(`Error: ${error}`); + }); diff --git a/js/src/15_deploy_token_create.ts b/js/src/15_deploy_token_create.ts index 560a3d6..3b62a0b 100644 --- a/js/src/15_deploy_token_create.ts +++ b/js/src/15_deploy_token_create.ts @@ -1,5 +1,5 @@ -import {Provider, types, Wallet, ContractFactory, Contract} from "zksync-ethers"; -import {Typed} from "ethers"; +import { Provider, types, Wallet, ContractFactory, Contract } from "zksync-ethers"; +import { Typed } from "ethers"; const provider = Provider.getDefaultProvider(types.Network.Sepolia); const PRIVATE_KEY = process.env.PRIVATE_KEY; @@ -11,7 +11,7 @@ async function main() { const bytecode: string = conf.bytecode; const factory = new ContractFactory(abi, bytecode, wallet); - const token = await factory.deploy("Crown", "Crown", 18) as Contract; + const token = (await factory.deploy("Crown", "Crown", 18)) as Contract; const tokenAddress = await token.getAddress(); console.log(`Contract address: ${tokenAddress}`); @@ -20,6 +20,8 @@ async function main() { console.log(`Crown tokens: ${await wallet.getBalance(tokenAddress)}`); } -main().then().catch(error => { - console.log(`Error: ${error}`); -}) \ No newline at end of file +main() + .then() + .catch((error) => { + console.log(`Error: ${error}`); + }); diff --git a/js/src/16_deploy_token_create2.ts b/js/src/16_deploy_token_create2.ts index 84108bf..7c252ae 100644 --- a/js/src/16_deploy_token_create2.ts +++ b/js/src/16_deploy_token_create2.ts @@ -1,5 +1,5 @@ -import {Provider, types, Wallet, ContractFactory, Contract} from "zksync-ethers"; -import {ethers, Typed} from "ethers"; +import { Provider, types, Wallet, ContractFactory, Contract } from "zksync-ethers"; +import { ethers, Typed } from "ethers"; const provider = Provider.getDefaultProvider(types.Network.Sepolia); const PRIVATE_KEY = process.env.PRIVATE_KEY; @@ -11,9 +11,9 @@ async function main() { const bytecode: string = conf.bytecode; const factory = new ContractFactory(abi, bytecode, wallet, "create2"); - const token = await factory.deploy("Crown", "Crown", 18,{ - customData: {salt: ethers.hexlify(ethers.randomBytes(32))} - }) as Contract; + const token = (await factory.deploy("Crown", "Crown", 18, { + customData: { salt: ethers.hexlify(ethers.randomBytes(32)) }, + })) as Contract; const tokenAddress = await token.getAddress(); console.log(`Contract address: ${tokenAddress}`); @@ -22,6 +22,8 @@ async function main() { console.log(`Crown tokens: ${await wallet.getBalance(tokenAddress)}`); } -main().then().catch(error => { - console.log(`Error: ${error}`); -}) \ No newline at end of file +main() + .then() + .catch((error) => { + console.log(`Error: ${error}`); + }); diff --git a/js/src/17_deploy_create_account.ts b/js/src/17_deploy_create_account.ts index 3755546..5bd0955 100644 --- a/js/src/17_deploy_create_account.ts +++ b/js/src/17_deploy_create_account.ts @@ -1,4 +1,4 @@ -import {Provider, types, Wallet, ContractFactory} from "zksync-ethers"; +import { Provider, types, Wallet, ContractFactory } from "zksync-ethers"; const provider = Provider.getDefaultProvider(types.Network.Sepolia); const PRIVATE_KEY = process.env.PRIVATE_KEY; @@ -11,11 +11,13 @@ async function main() { const abi = conf.abi; const bytecode: string = conf.bytecode; - const factory = new ContractFactory(abi, bytecode, wallet, 'createAccount'); + const factory = new ContractFactory(abi, bytecode, wallet, "createAccount"); const account = await factory.deploy(tokenAddress); console.log(`Account address: ${await account.getAddress()}`); } -main().then().catch(error => { - console.log(`Error: ${error}`); -}) \ No newline at end of file +main() + .then() + .catch((error) => { + console.log(`Error: ${error}`); + }); diff --git a/js/src/18_deploy_create2_account.ts b/js/src/18_deploy_create2_account.ts index 69724fd..4c3e889 100644 --- a/js/src/18_deploy_create2_account.ts +++ b/js/src/18_deploy_create2_account.ts @@ -1,5 +1,5 @@ -import {Provider, types, Wallet, ContractFactory} from "zksync-ethers"; -import {ethers} from "ethers"; +import { Provider, types, Wallet, ContractFactory } from "zksync-ethers"; +import { ethers } from "ethers"; const provider = Provider.getDefaultProvider(types.Network.Sepolia); const PRIVATE_KEY = process.env.PRIVATE_KEY; @@ -12,13 +12,15 @@ async function main() { const abi = conf.abi; const bytecode: string = conf.bytecode; - const factory = new ContractFactory(abi, bytecode, wallet, 'create2Account'); + const factory = new ContractFactory(abi, bytecode, wallet, "create2Account"); const account = await factory.deploy(tokenAddress, { - customData: {salt: ethers.hexlify(ethers.randomBytes(32))} + customData: { salt: ethers.hexlify(ethers.randomBytes(32)) }, }); console.log(`Account address: ${await account.getAddress()}`); } -main().then().catch(error => { - console.log(`Error: ${error}`); -}) \ No newline at end of file +main() + .then() + .catch((error) => { + console.log(`Error: ${error}`); + }); diff --git a/js/src/19_use_paymaster.ts b/js/src/19_use_paymaster.ts index a721f16..91c7573 100644 --- a/js/src/19_use_paymaster.ts +++ b/js/src/19_use_paymaster.ts @@ -1,16 +1,16 @@ -import {Provider, types, utils, Wallet} from "zksync-ethers"; -import {ethers} from "ethers"; +import { Provider, types, utils, Wallet } from "zksync-ethers"; +import { ethers } from "ethers"; const provider = Provider.getDefaultProvider(types.Network.Sepolia); const ethProvider = ethers.getDefaultProvider("sepolia"); const PRIVATE_KEY = process.env.PRIVATE_KEY; const wallet = new Wallet(PRIVATE_KEY, provider, ethProvider); - const tokenAddress = "0x765F5AF819D818a8e8ee6ff63D8d0e8056DBE150"; // Crown token which can be minted for free const paymasterAddress = "0x57F48f0d845E0ed7C9Bf066cEbFF64FbeBE6AFEF"; // Paymaster for Crown token -const token = new ethers.Interface(require('../../solidity/custom_paymaster/token/build/Token.json').abi); - +const token = new ethers.Interface( + require("../../solidity/custom_paymaster/token/build/Token.json").abi, +); /* This example demonstrates how to use a paymaster to facilitate fee payment with an ERC20 token. @@ -20,13 +20,19 @@ During transaction execution, the paymaster receives the ERC20 token from the us async function main() { console.log(`Paymaster balance before mint: ${await provider.getBalance(paymasterAddress)}`); console.log(`Wallet address before mint: ${await wallet.getBalance()}`); - console.log(`Paymaster Crown tokens before mint: ${await provider.getBalance(paymasterAddress, 'latest', tokenAddress)}`); + console.log( + `Paymaster Crown tokens before mint: ${await provider.getBalance( + paymasterAddress, + "latest", + tokenAddress, + )}`, + ); console.log(`Wallet Crown tokens before mint: ${await wallet.getBalance(tokenAddress)}`); // Also mint some tokens to user account, so it can offer to pay fee with it const mintTx = await wallet.sendTransaction({ to: tokenAddress, - data: token.encodeFunctionData('mint', [await wallet.getAddress(), 10]), + data: token.encodeFunctionData("mint", [await wallet.getAddress(), 10]), }); await mintTx.wait(); @@ -34,35 +40,42 @@ async function main() { const faucetTx = await wallet.transfer({ token: utils.ETH_ADDRESS, to: paymasterAddress, - amount: ethers.parseEther('0.1') + amount: ethers.parseEther("0.1"), }); await faucetTx.wait(); - // In order to use paymaster, EIP712 transaction // need to be created with configured paymaster parameters const tx = await wallet.sendTransaction({ type: utils.EIP712_TX_TYPE, to: tokenAddress, - data: token.encodeFunctionData('mint', [await wallet.getAddress(), 3]), + data: token.encodeFunctionData("mint", [await wallet.getAddress(), 3]), customData: { gasPerPubdata: utils.DEFAULT_GAS_PER_PUBDATA_LIMIT, paymasterParams: utils.getPaymasterParams(paymasterAddress, { - type: 'ApprovalBased', + type: "ApprovalBased", token: tokenAddress, minimalAllowance: 1, - innerInput: new Uint8Array() - }) - } + innerInput: new Uint8Array(), + }), + }, }); await tx.wait(); console.log(`Paymaster balance after mint: ${await provider.getBalance(paymasterAddress)}`); console.log(`Wallet address after mint: ${await wallet.getBalance()}`); - console.log(`Paymaster Crown tokens after mint: ${await provider.getBalance(paymasterAddress, 'latest', tokenAddress)}`); + console.log( + `Paymaster Crown tokens after mint: ${await provider.getBalance( + paymasterAddress, + "latest", + tokenAddress, + )}`, + ); console.log(`Wallet Crown tokens after mint: ${await wallet.getBalance(tokenAddress)}`); } -main().then().catch(error => { - console.log(`Error: ${error}`); -}) \ No newline at end of file +main() + .then() + .catch((error) => { + console.log(`Error: ${error}`); + }); diff --git a/js/tests/01_deposit.test.ts b/js/tests/01_deposit.test.ts new file mode 100644 index 0000000..abed029 --- /dev/null +++ b/js/tests/01_deposit.test.ts @@ -0,0 +1,33 @@ +import * as chai from "chai"; +import "./custom-matchers"; +import { Provider, types, utils, Wallet } from "zksync-ethers"; +import { ethers } from "ethers"; +import * as fs from "fs"; + +const { expect } = chai; + +describe("Deposit", () => { + const PRIVATE_KEY = "0x7726827caac94a7f9e1b160f7ea819f172f7b6f9d2a97f992c38edeab82d4110"; + + const provider = Provider.getDefaultProvider(types.Network.Localhost); + const ethProvider = ethers.getDefaultProvider("http://localhost:8545"); + const wallet = new Wallet(PRIVATE_KEY, provider, ethProvider); + + it("should deposit ETH to L2 network", async () => { + const amount = 7_000_000_000; + const l2BalanceBeforeDeposit = await wallet.getBalance(); + const l1BalanceBeforeDeposit = await wallet.getBalanceL1(); + const tx = await wallet.deposit({ + token: utils.ETH_ADDRESS, + to: await wallet.getAddress(), + amount: amount, + refundRecipient: await wallet.getAddress(), + }); + const result = await tx.wait(); + const l2BalanceAfterDeposit = await wallet.getBalance(); + const l1BalanceAfterDeposit = await wallet.getBalanceL1(); + expect(result).not.to.be.null; + expect(l2BalanceAfterDeposit - l2BalanceBeforeDeposit >= BigInt(amount)).to.be.true; + expect(l1BalanceBeforeDeposit - l1BalanceAfterDeposit >= BigInt(amount)).to.be.true; + }).timeout(10_000); +}); diff --git a/js/tests/02_transfer.test.ts b/js/tests/02_transfer.test.ts new file mode 100644 index 0000000..403ac98 --- /dev/null +++ b/js/tests/02_transfer.test.ts @@ -0,0 +1,32 @@ +import * as chai from "chai"; +import "./custom-matchers"; +import { Provider, types, utils, Wallet } from "zksync-ethers"; +import { ethers } from "ethers"; +import * as fs from "fs"; + +const { expect } = chai; + +describe("Transfer token", () => { + const PRIVATE_KEY = "0x7726827caac94a7f9e1b160f7ea819f172f7b6f9d2a97f992c38edeab82d4110"; + const RECEIVER = "0xa61464658AfeAf65CccaaFD3a512b69A83B77618"; + + const provider = Provider.getDefaultProvider(types.Network.Localhost); + const ethProvider = ethers.getDefaultProvider("http://localhost:8545"); + const wallet = new Wallet(PRIVATE_KEY, provider, ethProvider); + + const DAI = require("./token.json"); + + it("should transfer ETH", async () => { + const amount = 7_000_000_000; + const balanceBeforeTransfer = await provider.getBalance(RECEIVER); + const tx = await wallet.transfer({ + token: utils.ETH_ADDRESS, + to: RECEIVER, + amount: amount, + }); + const result = await tx.wait(); + const balanceAfterTransfer = await provider.getBalance(RECEIVER); + expect(result).not.to.be.null; + expect(balanceAfterTransfer - balanceBeforeTransfer).to.be.equal(BigInt(amount)); + }).timeout(25_000); +}); diff --git a/js/tests/05_deposit_token.test.ts b/js/tests/05_deposit_token.test.ts new file mode 100644 index 0000000..c71a2f4 --- /dev/null +++ b/js/tests/05_deposit_token.test.ts @@ -0,0 +1,37 @@ +import * as chai from "chai"; +import "./custom-matchers"; +import { Provider, types, utils, Wallet } from "zksync-ethers"; +import { ethers } from "ethers"; +import * as fs from "fs"; + +const { expect } = chai; + +describe("Deposit token", () => { + const PRIVATE_KEY = "0x7726827caac94a7f9e1b160f7ea819f172f7b6f9d2a97f992c38edeab82d4110"; + + const provider = Provider.getDefaultProvider(types.Network.Localhost); + const ethProvider = ethers.getDefaultProvider("http://localhost:8545"); + const wallet = new Wallet(PRIVATE_KEY, provider, ethProvider); + + const DAI = require("./token.json"); + + it("should deposit DAI to L2 network", async () => { + const amount = 5; + const l2DAI = await provider.l2TokenAddress(DAI.l1Address); + const l2BalanceBeforeDeposit = await wallet.getBalance(l2DAI); + const l1BalanceBeforeDeposit = await wallet.getBalanceL1(DAI.l1Address); + const tx = await wallet.deposit({ + token: DAI.l1Address, + to: await wallet.getAddress(), + amount: amount, + approveERC20: true, + refundRecipient: await wallet.getAddress(), + }); + const result = await tx.wait(); + const l2BalanceAfterDeposit = await wallet.getBalance(l2DAI); + const l1BalanceAfterDeposit = await wallet.getBalanceL1(DAI.l1Address); + expect(result).not.to.be.null; + expect(l2BalanceAfterDeposit - l2BalanceBeforeDeposit === BigInt(amount)).to.be.true; + expect(l1BalanceBeforeDeposit - l1BalanceAfterDeposit === BigInt(amount)).to.be.true; + }).timeout(25_000); +}); diff --git a/js/tests/06_transfer_token.test.ts b/js/tests/06_transfer_token.test.ts new file mode 100644 index 0000000..64380cf --- /dev/null +++ b/js/tests/06_transfer_token.test.ts @@ -0,0 +1,33 @@ +import * as chai from "chai"; +import "./custom-matchers"; +import { Provider, types, utils, Wallet } from "zksync-ethers"; +import { ethers } from "ethers"; +import * as fs from "fs"; + +const { expect } = chai; + +describe("Transfer token", () => { + const PRIVATE_KEY = "0x7726827caac94a7f9e1b160f7ea819f172f7b6f9d2a97f992c38edeab82d4110"; + const RECEIVER = "0xa61464658AfeAf65CccaaFD3a512b69A83B77618"; + + const provider = Provider.getDefaultProvider(types.Network.Localhost); + const ethProvider = ethers.getDefaultProvider("http://localhost:8545"); + const wallet = new Wallet(PRIVATE_KEY, provider, ethProvider); + + const DAI = require("./token.json"); + + it("should transfer DAI", async () => { + const amount = 5; + const l2DAI = await provider.l2TokenAddress(DAI.l1Address); + const balanceBeforeTransfer = await provider.getBalance(RECEIVER, "latest", l2DAI); + const tx = await wallet.transfer({ + token: l2DAI, + to: RECEIVER, + amount: amount, + }); + const result = await tx.wait(); + const balanceAfterTransfer = await provider.getBalance(RECEIVER, "latest", l2DAI); + expect(result).not.to.be.null; + expect(balanceAfterTransfer - balanceBeforeTransfer).to.be.equal(BigInt(amount)); + }).timeout(25_000); +}); diff --git a/js/tests/custom-matchers.ts b/js/tests/custom-matchers.ts new file mode 100644 index 0000000..46d77b2 --- /dev/null +++ b/js/tests/custom-matchers.ts @@ -0,0 +1,22 @@ +import * as chai from "chai"; + +declare global { + namespace Chai { + interface Assertion { + deepEqualExcluding(expected: Record, excludeFields: string[]): Assertion; + } + } +} + +chai.Assertion.addMethod( + "deepEqualExcluding", + function (expected: Record, excludeFields: string[]) { + const obj1 = this._obj; + + for (const key in obj1) { + if (!excludeFields.includes(key)) { + chai.expect(obj1[key]).to.deep.equal(expected[key]); + } + } + }, +); diff --git a/js/tests/setup/entrypoint.sh b/js/tests/setup/entrypoint.sh new file mode 100755 index 0000000..af9dc75 --- /dev/null +++ b/js/tests/setup/entrypoint.sh @@ -0,0 +1,1083 @@ +#!/bin/bash + +cd /root || exit +mkdir setup +cd setup || exit + +go mod init setup +go get github.com/zksync-sdk/zksync2-go@v0.3.2 + +mkdir crown_l1 +cat << EOF > crown_l1/crown_l1.go +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package crown_l1 + +import ( + "errors" + "math/big" + "strings" + + ethereum "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = errors.New + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription + _ = abi.ConvertType +) + +// Crownl1MetaData contains all meta data concerning the Crownl1 contract. +var Crownl1MetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[{\"internalType\":\"string\",\"name\":\"name_\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"symbol_\",\"type\":\"string\"},{\"internalType\":\"uint8\",\"name\":\"decimals_\",\"type\":\"uint8\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"}],\"name\":\"allowance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"decimals\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"subtractedValue\",\"type\":\"uint256\"}],\"name\":\"decreaseAllowance\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"addedValue\",\"type\":\"uint256\"}],\"name\":\"increaseAllowance\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"mint\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"transfer\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Bin: "0x60806040523480156200001157600080fd5b5060405162001a8038038062001a80833981810160405281019062000037919062000254565b828281600390816200004a919062000539565b5080600490816200005c919062000539565b50505080600560006101000a81548160ff021916908360ff16021790555050505062000620565b6000604051905090565b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b620000ec82620000a1565b810181811067ffffffffffffffff821117156200010e576200010d620000b2565b5b80604052505050565b60006200012362000083565b9050620001318282620000e1565b919050565b600067ffffffffffffffff821115620001545762000153620000b2565b5b6200015f82620000a1565b9050602081019050919050565b60005b838110156200018c5780820151818401526020810190506200016f565b60008484015250505050565b6000620001af620001a98462000136565b62000117565b905082815260208101848484011115620001ce57620001cd6200009c565b5b620001db8482856200016c565b509392505050565b600082601f830112620001fb57620001fa62000097565b5b81516200020d84826020860162000198565b91505092915050565b600060ff82169050919050565b6200022e8162000216565b81146200023a57600080fd5b50565b6000815190506200024e8162000223565b92915050565b60008060006060848603121562000270576200026f6200008d565b5b600084015167ffffffffffffffff81111562000291576200029062000092565b5b6200029f86828701620001e3565b935050602084015167ffffffffffffffff811115620002c357620002c262000092565b5b620002d186828701620001e3565b9250506040620002e4868287016200023d565b9150509250925092565b600081519050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b600060028204905060018216806200034157607f821691505b602082108103620003575762000356620002f9565b5b50919050565b60008190508160005260206000209050919050565b60006020601f8301049050919050565b600082821b905092915050565b600060088302620003c17fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8262000382565b620003cd868362000382565b95508019841693508086168417925050509392505050565b6000819050919050565b6000819050919050565b60006200041a620004146200040e84620003e5565b620003ef565b620003e5565b9050919050565b6000819050919050565b6200043683620003f9565b6200044e620004458262000421565b8484546200038f565b825550505050565b600090565b6200046562000456565b620004728184846200042b565b505050565b5b818110156200049a576200048e6000826200045b565b60018101905062000478565b5050565b601f821115620004e957620004b3816200035d565b620004be8462000372565b81016020851015620004ce578190505b620004e6620004dd8562000372565b83018262000477565b50505b505050565b600082821c905092915050565b60006200050e60001984600802620004ee565b1980831691505092915050565b6000620005298383620004fb565b9150826002028217905092915050565b6200054482620002ee565b67ffffffffffffffff81111562000560576200055f620000b2565b5b6200056c825462000328565b620005798282856200049e565b600060209050601f831160018114620005b157600084156200059c578287015190505b620005a885826200051b565b86555062000618565b601f198416620005c1866200035d565b60005b82811015620005eb57848901518255600182019150602085019450602081019050620005c4565b868310156200060b578489015162000607601f891682620004fb565b8355505b6001600288020188555050505b505050505050565b61145080620006306000396000f3fe608060405234801561001057600080fd5b50600436106100b45760003560e01c806340c10f191161007157806340c10f19146101a357806370a08231146101d357806395d89b4114610203578063a457c2d714610221578063a9059cbb14610251578063dd62ed3e14610281576100b4565b806306fdde03146100b9578063095ea7b3146100d757806318160ddd1461010757806323b872dd14610125578063313ce567146101555780633950935114610173575b600080fd5b6100c16102b1565b6040516100ce9190610cc1565b60405180910390f35b6100f160048036038101906100ec9190610d7c565b610343565b6040516100fe9190610dd7565b60405180910390f35b61010f610366565b60405161011c9190610e01565b60405180910390f35b61013f600480360381019061013a9190610e1c565b610370565b60405161014c9190610dd7565b60405180910390f35b61015d61039f565b60405161016a9190610e8b565b60405180910390f35b61018d60048036038101906101889190610d7c565b6103b6565b60405161019a9190610dd7565b60405180910390f35b6101bd60048036038101906101b89190610d7c565b6103ed565b6040516101ca9190610dd7565b60405180910390f35b6101ed60048036038101906101e89190610ea6565b610403565b6040516101fa9190610e01565b60405180910390f35b61020b61044b565b6040516102189190610cc1565b60405180910390f35b61023b60048036038101906102369190610d7c565b6104dd565b6040516102489190610dd7565b60405180910390f35b61026b60048036038101906102669190610d7c565b610554565b6040516102789190610dd7565b60405180910390f35b61029b60048036038101906102969190610ed3565b610577565b6040516102a89190610e01565b60405180910390f35b6060600380546102c090610f42565b80601f01602080910402602001604051908101604052809291908181526020018280546102ec90610f42565b80156103395780601f1061030e57610100808354040283529160200191610339565b820191906000526020600020905b81548152906001019060200180831161031c57829003601f168201915b5050505050905090565b60008061034e6105fe565b905061035b818585610606565b600191505092915050565b6000600254905090565b60008061037b6105fe565b90506103888582856107cf565b61039385858561085b565b60019150509392505050565b6000600560009054906101000a900460ff16905090565b6000806103c16105fe565b90506103e28185856103d38589610577565b6103dd9190610fa2565b610606565b600191505092915050565b60006103f98383610ad1565b6001905092915050565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b60606004805461045a90610f42565b80601f016020809104026020016040519081016040528092919081815260200182805461048690610f42565b80156104d35780601f106104a8576101008083540402835291602001916104d3565b820191906000526020600020905b8154815290600101906020018083116104b657829003601f168201915b5050505050905090565b6000806104e86105fe565b905060006104f68286610577565b90508381101561053b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161053290611048565b60405180910390fd5b6105488286868403610606565b60019250505092915050565b60008061055f6105fe565b905061056c81858561085b565b600191505092915050565b6000600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905092915050565b600033905090565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603610675576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161066c906110da565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036106e4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106db9061116c565b60405180910390fd5b80600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925836040516107c29190610e01565b60405180910390a3505050565b60006107db8484610577565b90507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146108555781811015610847576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161083e906111d8565b60405180910390fd5b6108548484848403610606565b5b50505050565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16036108ca576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108c19061126a565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610939576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610930906112fc565b60405180910390fd5b610944838383610c27565b60008060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050818110156109ca576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109c19061138e565b60405180910390fd5b8181036000808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84604051610ab89190610e01565b60405180910390a3610acb848484610c2c565b50505050565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610b40576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b37906113fa565b60405180910390fd5b610b4c60008383610c27565b8060026000828254610b5e9190610fa2565b92505081905550806000808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508173ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef83604051610c0f9190610e01565b60405180910390a3610c2360008383610c2c565b5050565b505050565b505050565b600081519050919050565b600082825260208201905092915050565b60005b83811015610c6b578082015181840152602081019050610c50565b60008484015250505050565b6000601f19601f8301169050919050565b6000610c9382610c31565b610c9d8185610c3c565b9350610cad818560208601610c4d565b610cb681610c77565b840191505092915050565b60006020820190508181036000830152610cdb8184610c88565b905092915050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000610d1382610ce8565b9050919050565b610d2381610d08565b8114610d2e57600080fd5b50565b600081359050610d4081610d1a565b92915050565b6000819050919050565b610d5981610d46565b8114610d6457600080fd5b50565b600081359050610d7681610d50565b92915050565b60008060408385031215610d9357610d92610ce3565b5b6000610da185828601610d31565b9250506020610db285828601610d67565b9150509250929050565b60008115159050919050565b610dd181610dbc565b82525050565b6000602082019050610dec6000830184610dc8565b92915050565b610dfb81610d46565b82525050565b6000602082019050610e166000830184610df2565b92915050565b600080600060608486031215610e3557610e34610ce3565b5b6000610e4386828701610d31565b9350506020610e5486828701610d31565b9250506040610e6586828701610d67565b9150509250925092565b600060ff82169050919050565b610e8581610e6f565b82525050565b6000602082019050610ea06000830184610e7c565b92915050565b600060208284031215610ebc57610ebb610ce3565b5b6000610eca84828501610d31565b91505092915050565b60008060408385031215610eea57610ee9610ce3565b5b6000610ef885828601610d31565b9250506020610f0985828601610d31565b9150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b60006002820490506001821680610f5a57607f821691505b602082108103610f6d57610f6c610f13565b5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000610fad82610d46565b9150610fb883610d46565b9250828201905080821115610fd057610fcf610f73565b5b92915050565b7f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f7760008201527f207a65726f000000000000000000000000000000000000000000000000000000602082015250565b6000611032602583610c3c565b915061103d82610fd6565b604082019050919050565b6000602082019050818103600083015261106181611025565b9050919050565b7f45524332303a20617070726f76652066726f6d20746865207a65726f2061646460008201527f7265737300000000000000000000000000000000000000000000000000000000602082015250565b60006110c4602483610c3c565b91506110cf82611068565b604082019050919050565b600060208201905081810360008301526110f3816110b7565b9050919050565b7f45524332303a20617070726f766520746f20746865207a65726f20616464726560008201527f7373000000000000000000000000000000000000000000000000000000000000602082015250565b6000611156602283610c3c565b9150611161826110fa565b604082019050919050565b6000602082019050818103600083015261118581611149565b9050919050565b7f45524332303a20696e73756666696369656e7420616c6c6f77616e6365000000600082015250565b60006111c2601d83610c3c565b91506111cd8261118c565b602082019050919050565b600060208201905081810360008301526111f1816111b5565b9050919050565b7f45524332303a207472616e736665722066726f6d20746865207a65726f20616460008201527f6472657373000000000000000000000000000000000000000000000000000000602082015250565b6000611254602583610c3c565b915061125f826111f8565b604082019050919050565b6000602082019050818103600083015261128381611247565b9050919050565b7f45524332303a207472616e7366657220746f20746865207a65726f206164647260008201527f6573730000000000000000000000000000000000000000000000000000000000602082015250565b60006112e6602383610c3c565b91506112f18261128a565b604082019050919050565b60006020820190508181036000830152611315816112d9565b9050919050565b7f45524332303a207472616e7366657220616d6f756e742065786365656473206260008201527f616c616e63650000000000000000000000000000000000000000000000000000602082015250565b6000611378602683610c3c565b91506113838261131c565b604082019050919050565b600060208201905081810360008301526113a78161136b565b9050919050565b7f45524332303a206d696e7420746f20746865207a65726f206164647265737300600082015250565b60006113e4601f83610c3c565b91506113ef826113ae565b602082019050919050565b60006020820190508181036000830152611413816113d7565b905091905056fea2646970667358221220000337f45cfac5d1f414a2e9ac8d9051c93d7cab29f64c5a5d1f8167426908db64736f6c63430008130033", +} + +// Crownl1ABI is the input ABI used to generate the binding from. +// Deprecated: Use Crownl1MetaData.ABI instead. +var Crownl1ABI = Crownl1MetaData.ABI + +// Crownl1Bin is the compiled bytecode used for deploying new contracts. +// Deprecated: Use Crownl1MetaData.Bin instead. +var Crownl1Bin = Crownl1MetaData.Bin + +// DeployCrownl1 deploys a new Ethereum contract, binding an instance of Crownl1 to it. +func DeployCrownl1(auth *bind.TransactOpts, backend bind.ContractBackend, name_ string, symbol_ string, decimals_ uint8) (common.Address, *types.Transaction, *Crownl1, error) { + parsed, err := Crownl1MetaData.GetAbi() + if err != nil { + return common.Address{}, nil, nil, err + } + if parsed == nil { + return common.Address{}, nil, nil, errors.New("GetABI returned nil") + } + + address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(Crownl1Bin), backend, name_, symbol_, decimals_) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &Crownl1{Crownl1Caller: Crownl1Caller{contract: contract}, Crownl1Transactor: Crownl1Transactor{contract: contract}, Crownl1Filterer: Crownl1Filterer{contract: contract}}, nil +} + +// Crownl1 is an auto generated Go binding around an Ethereum contract. +type Crownl1 struct { + Crownl1Caller // Read-only binding to the contract + Crownl1Transactor // Write-only binding to the contract + Crownl1Filterer // Log filterer for contract events +} + +// Crownl1Caller is an auto generated read-only Go binding around an Ethereum contract. +type Crownl1Caller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// Crownl1Transactor is an auto generated write-only Go binding around an Ethereum contract. +type Crownl1Transactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// Crownl1Filterer is an auto generated log filtering Go binding around an Ethereum contract events. +type Crownl1Filterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// Crownl1Session is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type Crownl1Session struct { + Contract *Crownl1 // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// Crownl1CallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type Crownl1CallerSession struct { + Contract *Crownl1Caller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// Crownl1TransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type Crownl1TransactorSession struct { + Contract *Crownl1Transactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// Crownl1Raw is an auto generated low-level Go binding around an Ethereum contract. +type Crownl1Raw struct { + Contract *Crownl1 // Generic contract binding to access the raw methods on +} + +// Crownl1CallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type Crownl1CallerRaw struct { + Contract *Crownl1Caller // Generic read-only contract binding to access the raw methods on +} + +// Crownl1TransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type Crownl1TransactorRaw struct { + Contract *Crownl1Transactor // Generic write-only contract binding to access the raw methods on +} + +// NewCrownl1 creates a new instance of Crownl1, bound to a specific deployed contract. +func NewCrownl1(address common.Address, backend bind.ContractBackend) (*Crownl1, error) { + contract, err := bindCrownl1(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &Crownl1{Crownl1Caller: Crownl1Caller{contract: contract}, Crownl1Transactor: Crownl1Transactor{contract: contract}, Crownl1Filterer: Crownl1Filterer{contract: contract}}, nil +} + +// NewCrownl1Caller creates a new read-only instance of Crownl1, bound to a specific deployed contract. +func NewCrownl1Caller(address common.Address, caller bind.ContractCaller) (*Crownl1Caller, error) { + contract, err := bindCrownl1(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &Crownl1Caller{contract: contract}, nil +} + +// NewCrownl1Transactor creates a new write-only instance of Crownl1, bound to a specific deployed contract. +func NewCrownl1Transactor(address common.Address, transactor bind.ContractTransactor) (*Crownl1Transactor, error) { + contract, err := bindCrownl1(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &Crownl1Transactor{contract: contract}, nil +} + +// NewCrownl1Filterer creates a new log filterer instance of Crownl1, bound to a specific deployed contract. +func NewCrownl1Filterer(address common.Address, filterer bind.ContractFilterer) (*Crownl1Filterer, error) { + contract, err := bindCrownl1(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &Crownl1Filterer{contract: contract}, nil +} + +// bindCrownl1 binds a generic wrapper to an already deployed contract. +func bindCrownl1(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := Crownl1MetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_Crownl1 *Crownl1Raw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _Crownl1.Contract.Crownl1Caller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_Crownl1 *Crownl1Raw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Crownl1.Contract.Crownl1Transactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Crownl1 *Crownl1Raw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Crownl1.Contract.Crownl1Transactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_Crownl1 *Crownl1CallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _Crownl1.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_Crownl1 *Crownl1TransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Crownl1.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Crownl1 *Crownl1TransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Crownl1.Contract.contract.Transact(opts, method, params...) +} + +// Allowance is a free data retrieval call binding the contract method 0xdd62ed3e. +// +// Solidity: function allowance(address owner, address spender) view returns(uint256) +func (_Crownl1 *Crownl1Caller) Allowance(opts *bind.CallOpts, owner common.Address, spender common.Address) (*big.Int, error) { + var out []interface{} + err := _Crownl1.contract.Call(opts, &out, "allowance", owner, spender) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// Allowance is a free data retrieval call binding the contract method 0xdd62ed3e. +// +// Solidity: function allowance(address owner, address spender) view returns(uint256) +func (_Crownl1 *Crownl1Session) Allowance(owner common.Address, spender common.Address) (*big.Int, error) { + return _Crownl1.Contract.Allowance(&_Crownl1.CallOpts, owner, spender) +} + +// Allowance is a free data retrieval call binding the contract method 0xdd62ed3e. +// +// Solidity: function allowance(address owner, address spender) view returns(uint256) +func (_Crownl1 *Crownl1CallerSession) Allowance(owner common.Address, spender common.Address) (*big.Int, error) { + return _Crownl1.Contract.Allowance(&_Crownl1.CallOpts, owner, spender) +} + +// BalanceOf is a free data retrieval call binding the contract method 0x70a08231. +// +// Solidity: function balanceOf(address account) view returns(uint256) +func (_Crownl1 *Crownl1Caller) BalanceOf(opts *bind.CallOpts, account common.Address) (*big.Int, error) { + var out []interface{} + err := _Crownl1.contract.Call(opts, &out, "balanceOf", account) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// BalanceOf is a free data retrieval call binding the contract method 0x70a08231. +// +// Solidity: function balanceOf(address account) view returns(uint256) +func (_Crownl1 *Crownl1Session) BalanceOf(account common.Address) (*big.Int, error) { + return _Crownl1.Contract.BalanceOf(&_Crownl1.CallOpts, account) +} + +// BalanceOf is a free data retrieval call binding the contract method 0x70a08231. +// +// Solidity: function balanceOf(address account) view returns(uint256) +func (_Crownl1 *Crownl1CallerSession) BalanceOf(account common.Address) (*big.Int, error) { + return _Crownl1.Contract.BalanceOf(&_Crownl1.CallOpts, account) +} + +// Decimals is a free data retrieval call binding the contract method 0x313ce567. +// +// Solidity: function decimals() view returns(uint8) +func (_Crownl1 *Crownl1Caller) Decimals(opts *bind.CallOpts) (uint8, error) { + var out []interface{} + err := _Crownl1.contract.Call(opts, &out, "decimals") + + if err != nil { + return *new(uint8), err + } + + out0 := *abi.ConvertType(out[0], new(uint8)).(*uint8) + + return out0, err + +} + +// Decimals is a free data retrieval call binding the contract method 0x313ce567. +// +// Solidity: function decimals() view returns(uint8) +func (_Crownl1 *Crownl1Session) Decimals() (uint8, error) { + return _Crownl1.Contract.Decimals(&_Crownl1.CallOpts) +} + +// Decimals is a free data retrieval call binding the contract method 0x313ce567. +// +// Solidity: function decimals() view returns(uint8) +func (_Crownl1 *Crownl1CallerSession) Decimals() (uint8, error) { + return _Crownl1.Contract.Decimals(&_Crownl1.CallOpts) +} + +// Name is a free data retrieval call binding the contract method 0x06fdde03. +// +// Solidity: function name() view returns(string) +func (_Crownl1 *Crownl1Caller) Name(opts *bind.CallOpts) (string, error) { + var out []interface{} + err := _Crownl1.contract.Call(opts, &out, "name") + + if err != nil { + return *new(string), err + } + + out0 := *abi.ConvertType(out[0], new(string)).(*string) + + return out0, err + +} + +// Name is a free data retrieval call binding the contract method 0x06fdde03. +// +// Solidity: function name() view returns(string) +func (_Crownl1 *Crownl1Session) Name() (string, error) { + return _Crownl1.Contract.Name(&_Crownl1.CallOpts) +} + +// Name is a free data retrieval call binding the contract method 0x06fdde03. +// +// Solidity: function name() view returns(string) +func (_Crownl1 *Crownl1CallerSession) Name() (string, error) { + return _Crownl1.Contract.Name(&_Crownl1.CallOpts) +} + +// Symbol is a free data retrieval call binding the contract method 0x95d89b41. +// +// Solidity: function symbol() view returns(string) +func (_Crownl1 *Crownl1Caller) Symbol(opts *bind.CallOpts) (string, error) { + var out []interface{} + err := _Crownl1.contract.Call(opts, &out, "symbol") + + if err != nil { + return *new(string), err + } + + out0 := *abi.ConvertType(out[0], new(string)).(*string) + + return out0, err + +} + +// Symbol is a free data retrieval call binding the contract method 0x95d89b41. +// +// Solidity: function symbol() view returns(string) +func (_Crownl1 *Crownl1Session) Symbol() (string, error) { + return _Crownl1.Contract.Symbol(&_Crownl1.CallOpts) +} + +// Symbol is a free data retrieval call binding the contract method 0x95d89b41. +// +// Solidity: function symbol() view returns(string) +func (_Crownl1 *Crownl1CallerSession) Symbol() (string, error) { + return _Crownl1.Contract.Symbol(&_Crownl1.CallOpts) +} + +// TotalSupply is a free data retrieval call binding the contract method 0x18160ddd. +// +// Solidity: function totalSupply() view returns(uint256) +func (_Crownl1 *Crownl1Caller) TotalSupply(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _Crownl1.contract.Call(opts, &out, "totalSupply") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// TotalSupply is a free data retrieval call binding the contract method 0x18160ddd. +// +// Solidity: function totalSupply() view returns(uint256) +func (_Crownl1 *Crownl1Session) TotalSupply() (*big.Int, error) { + return _Crownl1.Contract.TotalSupply(&_Crownl1.CallOpts) +} + +// TotalSupply is a free data retrieval call binding the contract method 0x18160ddd. +// +// Solidity: function totalSupply() view returns(uint256) +func (_Crownl1 *Crownl1CallerSession) TotalSupply() (*big.Int, error) { + return _Crownl1.Contract.TotalSupply(&_Crownl1.CallOpts) +} + +// Approve is a paid mutator transaction binding the contract method 0x095ea7b3. +// +// Solidity: function approve(address spender, uint256 amount) returns(bool) +func (_Crownl1 *Crownl1Transactor) Approve(opts *bind.TransactOpts, spender common.Address, amount *big.Int) (*types.Transaction, error) { + return _Crownl1.contract.Transact(opts, "approve", spender, amount) +} + +// Approve is a paid mutator transaction binding the contract method 0x095ea7b3. +// +// Solidity: function approve(address spender, uint256 amount) returns(bool) +func (_Crownl1 *Crownl1Session) Approve(spender common.Address, amount *big.Int) (*types.Transaction, error) { + return _Crownl1.Contract.Approve(&_Crownl1.TransactOpts, spender, amount) +} + +// Approve is a paid mutator transaction binding the contract method 0x095ea7b3. +// +// Solidity: function approve(address spender, uint256 amount) returns(bool) +func (_Crownl1 *Crownl1TransactorSession) Approve(spender common.Address, amount *big.Int) (*types.Transaction, error) { + return _Crownl1.Contract.Approve(&_Crownl1.TransactOpts, spender, amount) +} + +// DecreaseAllowance is a paid mutator transaction binding the contract method 0xa457c2d7. +// +// Solidity: function decreaseAllowance(address spender, uint256 subtractedValue) returns(bool) +func (_Crownl1 *Crownl1Transactor) DecreaseAllowance(opts *bind.TransactOpts, spender common.Address, subtractedValue *big.Int) (*types.Transaction, error) { + return _Crownl1.contract.Transact(opts, "decreaseAllowance", spender, subtractedValue) +} + +// DecreaseAllowance is a paid mutator transaction binding the contract method 0xa457c2d7. +// +// Solidity: function decreaseAllowance(address spender, uint256 subtractedValue) returns(bool) +func (_Crownl1 *Crownl1Session) DecreaseAllowance(spender common.Address, subtractedValue *big.Int) (*types.Transaction, error) { + return _Crownl1.Contract.DecreaseAllowance(&_Crownl1.TransactOpts, spender, subtractedValue) +} + +// DecreaseAllowance is a paid mutator transaction binding the contract method 0xa457c2d7. +// +// Solidity: function decreaseAllowance(address spender, uint256 subtractedValue) returns(bool) +func (_Crownl1 *Crownl1TransactorSession) DecreaseAllowance(spender common.Address, subtractedValue *big.Int) (*types.Transaction, error) { + return _Crownl1.Contract.DecreaseAllowance(&_Crownl1.TransactOpts, spender, subtractedValue) +} + +// IncreaseAllowance is a paid mutator transaction binding the contract method 0x39509351. +// +// Solidity: function increaseAllowance(address spender, uint256 addedValue) returns(bool) +func (_Crownl1 *Crownl1Transactor) IncreaseAllowance(opts *bind.TransactOpts, spender common.Address, addedValue *big.Int) (*types.Transaction, error) { + return _Crownl1.contract.Transact(opts, "increaseAllowance", spender, addedValue) +} + +// IncreaseAllowance is a paid mutator transaction binding the contract method 0x39509351. +// +// Solidity: function increaseAllowance(address spender, uint256 addedValue) returns(bool) +func (_Crownl1 *Crownl1Session) IncreaseAllowance(spender common.Address, addedValue *big.Int) (*types.Transaction, error) { + return _Crownl1.Contract.IncreaseAllowance(&_Crownl1.TransactOpts, spender, addedValue) +} + +// IncreaseAllowance is a paid mutator transaction binding the contract method 0x39509351. +// +// Solidity: function increaseAllowance(address spender, uint256 addedValue) returns(bool) +func (_Crownl1 *Crownl1TransactorSession) IncreaseAllowance(spender common.Address, addedValue *big.Int) (*types.Transaction, error) { + return _Crownl1.Contract.IncreaseAllowance(&_Crownl1.TransactOpts, spender, addedValue) +} + +// Mint is a paid mutator transaction binding the contract method 0x40c10f19. +// +// Solidity: function mint(address _to, uint256 _amount) returns(bool) +func (_Crownl1 *Crownl1Transactor) Mint(opts *bind.TransactOpts, _to common.Address, _amount *big.Int) (*types.Transaction, error) { + return _Crownl1.contract.Transact(opts, "mint", _to, _amount) +} + +// Mint is a paid mutator transaction binding the contract method 0x40c10f19. +// +// Solidity: function mint(address _to, uint256 _amount) returns(bool) +func (_Crownl1 *Crownl1Session) Mint(_to common.Address, _amount *big.Int) (*types.Transaction, error) { + return _Crownl1.Contract.Mint(&_Crownl1.TransactOpts, _to, _amount) +} + +// Mint is a paid mutator transaction binding the contract method 0x40c10f19. +// +// Solidity: function mint(address _to, uint256 _amount) returns(bool) +func (_Crownl1 *Crownl1TransactorSession) Mint(_to common.Address, _amount *big.Int) (*types.Transaction, error) { + return _Crownl1.Contract.Mint(&_Crownl1.TransactOpts, _to, _amount) +} + +// Transfer is a paid mutator transaction binding the contract method 0xa9059cbb. +// +// Solidity: function transfer(address to, uint256 amount) returns(bool) +func (_Crownl1 *Crownl1Transactor) Transfer(opts *bind.TransactOpts, to common.Address, amount *big.Int) (*types.Transaction, error) { + return _Crownl1.contract.Transact(opts, "transfer", to, amount) +} + +// Transfer is a paid mutator transaction binding the contract method 0xa9059cbb. +// +// Solidity: function transfer(address to, uint256 amount) returns(bool) +func (_Crownl1 *Crownl1Session) Transfer(to common.Address, amount *big.Int) (*types.Transaction, error) { + return _Crownl1.Contract.Transfer(&_Crownl1.TransactOpts, to, amount) +} + +// Transfer is a paid mutator transaction binding the contract method 0xa9059cbb. +// +// Solidity: function transfer(address to, uint256 amount) returns(bool) +func (_Crownl1 *Crownl1TransactorSession) Transfer(to common.Address, amount *big.Int) (*types.Transaction, error) { + return _Crownl1.Contract.Transfer(&_Crownl1.TransactOpts, to, amount) +} + +// TransferFrom is a paid mutator transaction binding the contract method 0x23b872dd. +// +// Solidity: function transferFrom(address from, address to, uint256 amount) returns(bool) +func (_Crownl1 *Crownl1Transactor) TransferFrom(opts *bind.TransactOpts, from common.Address, to common.Address, amount *big.Int) (*types.Transaction, error) { + return _Crownl1.contract.Transact(opts, "transferFrom", from, to, amount) +} + +// TransferFrom is a paid mutator transaction binding the contract method 0x23b872dd. +// +// Solidity: function transferFrom(address from, address to, uint256 amount) returns(bool) +func (_Crownl1 *Crownl1Session) TransferFrom(from common.Address, to common.Address, amount *big.Int) (*types.Transaction, error) { + return _Crownl1.Contract.TransferFrom(&_Crownl1.TransactOpts, from, to, amount) +} + +// TransferFrom is a paid mutator transaction binding the contract method 0x23b872dd. +// +// Solidity: function transferFrom(address from, address to, uint256 amount) returns(bool) +func (_Crownl1 *Crownl1TransactorSession) TransferFrom(from common.Address, to common.Address, amount *big.Int) (*types.Transaction, error) { + return _Crownl1.Contract.TransferFrom(&_Crownl1.TransactOpts, from, to, amount) +} + +// Crownl1ApprovalIterator is returned from FilterApproval and is used to iterate over the raw logs and unpacked data for Approval events raised by the Crownl1 contract. +type Crownl1ApprovalIterator struct { + Event *Crownl1Approval // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *Crownl1ApprovalIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(Crownl1Approval) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(Crownl1Approval) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *Crownl1ApprovalIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *Crownl1ApprovalIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// Crownl1Approval represents a Approval event raised by the Crownl1 contract. +type Crownl1Approval struct { + Owner common.Address + Spender common.Address + Value *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterApproval is a free log retrieval operation binding the contract event 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925. +// +// Solidity: event Approval(address indexed owner, address indexed spender, uint256 value) +func (_Crownl1 *Crownl1Filterer) FilterApproval(opts *bind.FilterOpts, owner []common.Address, spender []common.Address) (*Crownl1ApprovalIterator, error) { + + var ownerRule []interface{} + for _, ownerItem := range owner { + ownerRule = append(ownerRule, ownerItem) + } + var spenderRule []interface{} + for _, spenderItem := range spender { + spenderRule = append(spenderRule, spenderItem) + } + + logs, sub, err := _Crownl1.contract.FilterLogs(opts, "Approval", ownerRule, spenderRule) + if err != nil { + return nil, err + } + return &Crownl1ApprovalIterator{contract: _Crownl1.contract, event: "Approval", logs: logs, sub: sub}, nil +} + +// WatchApproval is a free log subscription operation binding the contract event 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925. +// +// Solidity: event Approval(address indexed owner, address indexed spender, uint256 value) +func (_Crownl1 *Crownl1Filterer) WatchApproval(opts *bind.WatchOpts, sink chan<- *Crownl1Approval, owner []common.Address, spender []common.Address) (event.Subscription, error) { + + var ownerRule []interface{} + for _, ownerItem := range owner { + ownerRule = append(ownerRule, ownerItem) + } + var spenderRule []interface{} + for _, spenderItem := range spender { + spenderRule = append(spenderRule, spenderItem) + } + + logs, sub, err := _Crownl1.contract.WatchLogs(opts, "Approval", ownerRule, spenderRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(Crownl1Approval) + if err := _Crownl1.contract.UnpackLog(event, "Approval", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseApproval is a log parse operation binding the contract event 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925. +// +// Solidity: event Approval(address indexed owner, address indexed spender, uint256 value) +func (_Crownl1 *Crownl1Filterer) ParseApproval(log types.Log) (*Crownl1Approval, error) { + event := new(Crownl1Approval) + if err := _Crownl1.contract.UnpackLog(event, "Approval", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// Crownl1TransferIterator is returned from FilterTransfer and is used to iterate over the raw logs and unpacked data for Transfer events raised by the Crownl1 contract. +type Crownl1TransferIterator struct { + Event *Crownl1Transfer // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *Crownl1TransferIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(Crownl1Transfer) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(Crownl1Transfer) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *Crownl1TransferIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *Crownl1TransferIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// Crownl1Transfer represents a Transfer event raised by the Crownl1 contract. +type Crownl1Transfer struct { + From common.Address + To common.Address + Value *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterTransfer is a free log retrieval operation binding the contract event 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef. +// +// Solidity: event Transfer(address indexed from, address indexed to, uint256 value) +func (_Crownl1 *Crownl1Filterer) FilterTransfer(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*Crownl1TransferIterator, error) { + + var fromRule []interface{} + for _, fromItem := range from { + fromRule = append(fromRule, fromItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _Crownl1.contract.FilterLogs(opts, "Transfer", fromRule, toRule) + if err != nil { + return nil, err + } + return &Crownl1TransferIterator{contract: _Crownl1.contract, event: "Transfer", logs: logs, sub: sub}, nil +} + +// WatchTransfer is a free log subscription operation binding the contract event 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef. +// +// Solidity: event Transfer(address indexed from, address indexed to, uint256 value) +func (_Crownl1 *Crownl1Filterer) WatchTransfer(opts *bind.WatchOpts, sink chan<- *Crownl1Transfer, from []common.Address, to []common.Address) (event.Subscription, error) { + + var fromRule []interface{} + for _, fromItem := range from { + fromRule = append(fromRule, fromItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _Crownl1.contract.WatchLogs(opts, "Transfer", fromRule, toRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(Crownl1Transfer) + if err := _Crownl1.contract.UnpackLog(event, "Transfer", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseTransfer is a log parse operation binding the contract event 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef. +// +// Solidity: event Transfer(address indexed from, address indexed to, uint256 value) +func (_Crownl1 *Crownl1Filterer) ParseTransfer(log types.Log) (*Crownl1Transfer, error) { + event := new(Crownl1Transfer) + if err := _Crownl1.contract.UnpackLog(event, "Transfer", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} +EOF + + +cat << 'EOF' > setup.go +package main + +import ( + "context" + "crypto/ecdsa" + "encoding/json" + "fmt" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/zksync-sdk/zksync2-go/accounts" + "github.com/zksync-sdk/zksync2-go/clients" + "setup/crown_l1" + "log" + "math/big" + "os" +) + +const TokenPath = "./token.json" + +type Token struct { + L1Address string `json:"l1Address"` + L2Address string `json:"l2Address"` +} + +func readToken() *Token { + file, err := os.Open(TokenPath) + if err != nil { + log.Printf("Could not find token.json, creating new one") + return nil + } + defer func(file *os.File) { + errClose := file.Close() + if errClose != nil { + log.Fatalf("Error closing file: %s", err) + } + }(file) + + var token Token + decoder := json.NewDecoder(file) + if errDecode := decoder.Decode(&token); err != nil { + log.Fatalf("Error decoding JSON: %s", errDecode) + } + return &token +} + +func writeToken(token Token) { + file, err := os.Create(TokenPath) + if err != nil { + log.Fatalf("Error creating file: %s", err) + } + defer func(file *os.File) { + errClose := file.Close() + if errClose != nil { + log.Fatalf("Error closing file: %s", err) + } + }(file) + + // Marshal data to JSON + jsonData, err := json.MarshalIndent(token, "", " ") + if err != nil { + log.Fatalf("Error marshaling to JSON: %s", err) + } + + // Write JSON data to the file + _, err = file.Write(jsonData) + if err != nil { + log.Fatalf("Error writing JSON to file: %s", err) + } + + log.Println("Token: ", token) +} + +func checkIfTokenNeedsToBeCreated(client clients.Client, ethClient *ethclient.Client) (bool, bool) { + token := readToken() + if token == nil { + return true, true + } + _, err := ethClient.CodeAt(context.Background(), common.HexToAddress(token.L1Address), nil) + if err != nil { + return false, false + } + _, err = client.CodeAt(context.Background(), common.HexToAddress(token.L2Address), nil) + if err != nil { + return true, false + } + + return true, true +} + +func createTokenL1(ethClient *ethclient.Client, privateKey *ecdsa.PrivateKey, publicKey common.Address) common.Address { + chainID, err := ethClient.ChainID(context.Background()) + if err != nil { + log.Fatal(err) + } + auth, err := bind.NewKeyedTransactorWithChainID(privateKey, chainID) + if err != nil { + log.Fatal(err) + } + + address, tx, token, err := crown_l1.DeployCrownl1(auth, ethClient, "DAI", "DAI", 18) + if err != nil { + log.Fatal(err) + } + + _, err = bind.WaitDeployed(context.Background(), ethClient, tx) + if err != nil { + log.Fatal(err) + } + + symbol, err := token.Symbol(nil) + if err != nil { + log.Fatal(err) + } + decimals, err := token.Decimals(nil) + if err != nil { + log.Fatal(nil) + } + + auth, err = bind.NewKeyedTransactorWithChainID(privateKey, chainID) + if err != nil { + log.Fatal(err) + } + tx, err = token.Mint(auth, publicKey, big.NewInt(100_000_000)) + if err != nil { + log.Fatal(err) + } + + _, err = bind.WaitMined(context.Background(), ethClient, tx) + if err != nil { + log.Fatal("Wait mint: ", err) + } + + balance, err := token.BalanceOf(nil, publicKey) + if err != nil { + log.Fatal(err) + } + + log.Println("Token address: ", address) + log.Println("Symbol:", symbol) + log.Println("Decimals:", decimals) + log.Println("Balance L1: ", balance) + + return address +} + +func createTokenL2(wallet *accounts.Wallet, client clients.Client, ethClient *ethclient.Client, l1Token common.Address) common.Address { + tx, err := wallet.Deposit(nil, accounts.DepositTransaction{ + Token: l1Token, + Amount: big.NewInt(30), + To: wallet.Address(), + ApproveERC20: true, + RefundRecipient: wallet.Address(), + }) + if err != nil { + log.Fatal(err) + } + + _, err = bind.WaitMined(context.Background(), ethClient, tx) + if err != nil { + log.Fatal(err) + } + + l1Receipt, err := ethClient.TransactionReceipt(context.Background(), tx.Hash()) + if err != nil { + log.Fatal(err) + } + + l2Tx, err := client.L2TransactionFromPriorityOp(context.Background(), l1Receipt) + if err != nil { + log.Fatal(err) + } + _, err = client.WaitMined(context.Background(), l2Tx.Hash) + if err != nil { + log.Fatal(err) + } + + tokenL2Address, err := client.L2TokenAddress(context.Background(), l1Token) + if err != nil { + log.Panic(err) + } + + tokenL2Balance, err := wallet.Balance(context.Background(), tokenL2Address, nil) + if err != nil { + log.Panic(err) + } + + fmt.Println("Balance L2: ", tokenL2Balance) + + return tokenL2Address +} + +func main() { + var ( + PrivateKey = "7726827caac94a7f9e1b160f7ea819f172f7b6f9d2a97f992c38edeab82d4110" + ZkSyncEraProvider = "http://127.0.0.1:3050" + EthereumProvider = "http://127.0.0.1:8545" + ) + + client, err := clients.Dial(ZkSyncEraProvider) + if err != nil { + log.Panic(err) + } + defer client.Close() + + ethClient, err := ethclient.Dial(EthereumProvider) + if err != nil { + log.Fatal(err) + } + + privateKey, err := crypto.HexToECDSA(PrivateKey) + if err != nil { + log.Fatal(err) + } + + publicKeyECDSA, ok := privateKey.Public().(*ecdsa.PublicKey) + if !ok { + log.Fatal("cannot assert type: publicKey is not of type *ecdsa.PublicKey") + } + publicKey := crypto.PubkeyToAddress(*publicKeyECDSA) + + wallet, err := accounts.NewWallet(common.Hex2Bytes(PrivateKey), &client, ethClient) + if err != nil { + log.Fatal(err) + } + + shouldCreateL1Token, shouldCreateL2Token := checkIfTokenNeedsToBeCreated(client, ethClient) + if shouldCreateL1Token { + l1TokenAddress := createTokenL1(ethClient, privateKey, publicKey) + l2TokenAddress := createTokenL2(wallet, client, ethClient, l1TokenAddress) + writeToken(Token{L1Address: l1TokenAddress.Hex(), L2Address: l2TokenAddress.Hex()}) + + } else if !shouldCreateL1Token && shouldCreateL2Token { + l1TokenAddress := readToken().L1Address + l2TokenAddress := createTokenL2(wallet, client, ethClient, common.HexToAddress(l1TokenAddress)) + writeToken(Token{L1Address: l1TokenAddress, L2Address: l2TokenAddress.Hex()}) + } else { + fmt.Println("Token has been already created.") + } +} +EOF + +go mod tidy +go run setup.go diff --git a/js/tests/setup/setup.sh b/js/tests/setup/setup.sh new file mode 100755 index 0000000..28f0481 --- /dev/null +++ b/js/tests/setup/setup.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +docker create -it --name golang --network host --entrypoint /usr/local/bin/entrypoint.sh golang:1.20 +docker cp entrypoint.sh golang:/usr/local/bin/entrypoint.sh +docker start -i golang # this will wait for container to execute only if the script is run in interactive mode +docker wait golang +docker logs golang +docker cp golang:/root/setup/token.json ../token.json || exit 1 +docker rm golang +cat ../token.json \ No newline at end of file diff --git a/js/tests/wait.ts b/js/tests/wait.ts new file mode 100644 index 0000000..3a87f32 --- /dev/null +++ b/js/tests/wait.ts @@ -0,0 +1,24 @@ +import { Provider, types, utils } from "zksync-ethers"; + +/* +Waits until node is ready to receive traffic. It's used to wait for local environment setup. + */ +async function main() { + const maxAttempts = 30; + const provider = Provider.getDefaultProvider(types.Network.Localhost); + for (let i = 0; i < maxAttempts; i++) { + try { + await provider.getNetwork(); + return; + } catch (error) { + await utils.sleep(20_000); + } + } + throw new Error("Maximum retries exceeded."); +} + +main() + .then() + .catch((error) => { + console.log(`Error: ${error}`); + }); diff --git a/js/tsconfig.json b/js/tsconfig.json index f7d9a8d..1f450a6 100644 --- a/js/tsconfig.json +++ b/js/tsconfig.json @@ -1,27 +1,27 @@ { - "compilerOptions": { - "module": "CommonJS", - "target": "ES2020", - "moduleResolution": "Node16", + "compilerOptions": { + "module": "CommonJS", + "target": "ES2020", + "moduleResolution": "Node16", - "outDir": "./build", - "esModuleInterop": true, - "declaration": true, + "outDir": "./build", + "esModuleInterop": true, + "declaration": true, - "preserveSymlinks": true, - "preserveWatchOutput": true, + "preserveSymlinks": true, + "preserveWatchOutput": true, - "noImplicitOverride": true - }, - "files": [ - "./src/01_deposit.ts", - "./src/02_transfer.ts", - "./src/03_withdraw.ts", - "./src/04_finalize_withdraw.ts", - "./src/05_deposit_token.ts", - "./src/06_transfer_token.ts", - "./src/07_withdraw_token.ts", - "./src/08_get_confirmed_tokens.ts", - "./src/09_use_paymaster.ts" - ] + "noImplicitOverride": true + }, + "files": [ + "./src/01_deposit.ts", + "./src/02_transfer.ts", + "./src/03_withdraw.ts", + "./src/04_finalize_withdraw.ts", + "./src/05_deposit_token.ts", + "./src/06_transfer_token.ts", + "./src/07_withdraw_token.ts", + "./src/08_get_confirmed_tokens.ts", + "./src/09_use_paymaster.ts" + ] } diff --git a/js/yarn.lock b/js/yarn.lock index c4481f7..9ccf2a6 100644 --- a/js/yarn.lock +++ b/js/yarn.lock @@ -7,6 +7,11 @@ resolved "https://registry.yarnpkg.com/@adraffy/ens-normalize/-/ens-normalize-1.9.2.tgz#60111a5d9db45b2e5cbb6231b0bb8d97e8659316" integrity sha512-0h+FrQDqe2Wn+IIGFkTCd4aAwTJ+7834Ek1COohCyV26AXhwQ7WQaz+4F/nLOeVl/3BtWHOHLPsq46V8YB46Eg== +"@bcoe/v8-coverage@^0.2.3": + version "0.2.3" + resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" + integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== + "@cspotcode/source-map-support@^0.8.0": version "0.8.1" resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1" @@ -14,12 +19,17 @@ dependencies: "@jridgewell/trace-mapping" "0.3.9" -"@jridgewell/resolve-uri@^3.0.3": +"@istanbuljs/schema@^0.1.2", "@istanbuljs/schema@^0.1.3": + version "0.1.3" + resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" + integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== + +"@jridgewell/resolve-uri@^3.0.3", "@jridgewell/resolve-uri@^3.1.0": version "3.1.1" resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz#c08679063f279615a3326583ba3a90d1d82cc721" integrity sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA== -"@jridgewell/sourcemap-codec@^1.4.10": +"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14": version "1.4.15" resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== @@ -32,6 +42,14 @@ "@jridgewell/resolve-uri" "^3.0.3" "@jridgewell/sourcemap-codec" "^1.4.10" +"@jridgewell/trace-mapping@^0.3.12": + version "0.3.20" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz#72e45707cf240fa6b081d0366f8265b0cd10197f" + integrity sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q== + dependencies: + "@jridgewell/resolve-uri" "^3.1.0" + "@jridgewell/sourcemap-codec" "^1.4.14" + "@noble/hashes@1.1.2": version "1.1.2" resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.1.2.tgz#e9e035b9b166ca0af657a7848eb2718f0f22f183" @@ -62,6 +80,21 @@ resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.4.tgz#0b92dcc0cc1c81f6f306a381f28e31b1a56536e9" integrity sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA== +"@types/chai@^4.3.9": + version "4.3.11" + resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.3.11.tgz#e95050bf79a932cb7305dd130254ccdf9bde671c" + integrity sha512-qQR1dr2rGIHYlJulmr8Ioq3De0Le9E4MJ5AiaeAETJJpndT1uUNHsGFK3L/UIu+rbkQSdj8J/w2bCsBZc/Y5fQ== + +"@types/istanbul-lib-coverage@^2.0.1": + version "2.0.6" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz#7739c232a1fee9b4d3ce8985f314c0c6d33549d7" + integrity sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w== + +"@types/mocha@^10.0.1": + version "10.0.6" + resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-10.0.6.tgz#818551d39113081048bdddbef96701b4e8bb9d1b" + integrity sha512-dJvrYWxP/UcXm36Qn36fxhUKu8A/xMRXVT2cliFF1Z7UA9liG5Psj3ezNSZw+5puH2czDXRLcXQxf8JbJt0ejg== + "@types/node@18.15.13": version "18.15.13" resolved "https://registry.yarnpkg.com/@types/node/-/node-18.15.13.tgz#f64277c341150c979e42b00e4ac289290c9df469" @@ -87,21 +120,247 @@ aes-js@4.0.0-beta.5: resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-4.0.0-beta.5.tgz#8d2452c52adedebc3a3e28465d858c11ca315873" integrity sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q== +ansi-colors@4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" + integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== + +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-styles@^4.0.0, ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +anymatch@~3.1.2: + version "3.1.3" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" + integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + arg@^4.1.0: version "4.1.3" resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + +assertion-error@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" + integrity sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw== + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +binary-extensions@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" + integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +brace-expansion@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" + integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== + dependencies: + balanced-match "^1.0.0" + +braces@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + dependencies: + fill-range "^7.0.1" + +browser-stdout@1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" + integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== + +c8@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/c8/-/c8-8.0.1.tgz#bafd60be680e66c5530ee69f621e45b1364af9fd" + integrity sha512-EINpopxZNH1mETuI0DzRA4MZpAUH+IFiRhnmFD3vFr3vdrgxqi3VfE3KL0AIL+zDq8rC9bZqwM/VDmmoe04y7w== + dependencies: + "@bcoe/v8-coverage" "^0.2.3" + "@istanbuljs/schema" "^0.1.3" + find-up "^5.0.0" + foreground-child "^2.0.0" + istanbul-lib-coverage "^3.2.0" + istanbul-lib-report "^3.0.1" + istanbul-reports "^3.1.6" + rimraf "^3.0.2" + test-exclude "^6.0.0" + v8-to-istanbul "^9.0.0" + yargs "^17.7.2" + yargs-parser "^21.1.1" + +camelcase@^6.0.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" + integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== + +chai@^4.3.10: + version "4.3.10" + resolved "https://registry.yarnpkg.com/chai/-/chai-4.3.10.tgz#d784cec635e3b7e2ffb66446a63b4e33bd390384" + integrity sha512-0UXG04VuVbruMUYbJ6JctvH0YnC/4q3/AkT18q4NaITo91CUm0liMS9VqzT9vZhVQ/1eqPanMWjBM+Juhfb/9g== + dependencies: + assertion-error "^1.1.0" + check-error "^1.0.3" + deep-eql "^4.1.3" + get-func-name "^2.0.2" + loupe "^2.3.6" + pathval "^1.1.1" + type-detect "^4.0.8" + +chalk@^4.1.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +check-error@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.3.tgz#a6502e4312a7ee969f646e83bb3ddd56281bd694" + integrity sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg== + dependencies: + get-func-name "^2.0.2" + +chokidar@3.5.3: + version "3.5.3" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" + integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + +cliui@^7.0.2: + version "7.0.4" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" + integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.0" + wrap-ansi "^7.0.0" + +cliui@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa" + integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.1" + wrap-ansi "^7.0.0" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + +convert-source-map@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" + integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== + create-require@^1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== +cross-spawn@^7.0.0: + version "7.0.3" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" + integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +debug@4.3.4: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + +decamelize@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837" + integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ== + +deep-eql@^4.1.3: + version "4.1.3" + resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-4.1.3.tgz#7c7775513092f7df98d8df9996dd085eb668cc6d" + integrity sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw== + dependencies: + type-detect "^4.0.0" + +diff@5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-5.0.0.tgz#7ed6ad76d859d030787ec35855f5b1daf31d852b" + integrity sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w== + diff@^4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +escalade@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" + integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== + +escape-string-regexp@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + ethers@^6.7.1: version "6.7.1" resolved "https://registry.yarnpkg.com/ethers/-/ethers-6.7.1.tgz#9c65e8b5d8e9ad77b7e8cf1c46099892cfafad49" @@ -115,11 +374,452 @@ ethers@^6.7.1: tslib "2.4.0" ws "8.5.0" +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== + dependencies: + to-regex-range "^5.0.1" + +find-up@5.0.0, find-up@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== + dependencies: + locate-path "^6.0.0" + path-exists "^4.0.0" + +flat@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241" + integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== + +foreground-child@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-2.0.0.tgz#71b32800c9f15aa8f2f83f4a6bd9bff35d861a53" + integrity sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA== + dependencies: + cross-spawn "^7.0.0" + signal-exit "^3.0.2" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + +fsevents@~2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== + +get-caller-file@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + +get-func-name@^2.0.1, get-func-name@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.2.tgz#0d7cf20cd13fda808669ffa88f4ffc7a3943fc41" + integrity sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ== + +glob-parent@~5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob@7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" + integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@^7.1.3, glob@^7.1.4: + version "7.2.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.1.1" + once "^1.3.0" + path-is-absolute "^1.0.0" + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +he@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" + integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== + +html-escaper@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" + integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +is-binary-path@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== + dependencies: + binary-extensions "^2.0.0" + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-glob@^4.0.1, is-glob@~4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-plain-obj@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" + integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== + +is-unicode-supported@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" + integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + +istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: + version "3.2.2" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz#2d166c4b0644d43a39f04bf6c2edd1e585f31756" + integrity sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg== + +istanbul-lib-report@^3.0.0, istanbul-lib-report@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz#908305bac9a5bd175ac6a74489eafd0fc2445a7d" + integrity sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw== + dependencies: + istanbul-lib-coverage "^3.0.0" + make-dir "^4.0.0" + supports-color "^7.1.0" + +istanbul-reports@^3.1.6: + version "3.1.6" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.6.tgz#2544bcab4768154281a2f0870471902704ccaa1a" + integrity sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg== + dependencies: + html-escaper "^2.0.0" + istanbul-lib-report "^3.0.0" + +js-yaml@4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + dependencies: + argparse "^2.0.1" + +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== + dependencies: + p-locate "^5.0.0" + +log-symbols@4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503" + integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== + dependencies: + chalk "^4.1.0" + is-unicode-supported "^0.1.0" + +loupe@^2.3.6: + version "2.3.7" + resolved "https://registry.yarnpkg.com/loupe/-/loupe-2.3.7.tgz#6e69b7d4db7d3ab436328013d37d1c8c3540c697" + integrity sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA== + dependencies: + get-func-name "^2.0.1" + +lru-cache@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" + integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== + dependencies: + yallist "^4.0.0" + +make-dir@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-4.0.0.tgz#c3c2307a771277cd9638305f915c29ae741b614e" + integrity sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw== + dependencies: + semver "^7.5.3" + make-error@^1.1.1: version "1.3.6" resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== +minimatch@5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.0.1.tgz#fb9022f7528125187c92bd9e9b6366be1cf3415b" + integrity sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g== + dependencies: + brace-expansion "^2.0.1" + +minimatch@^3.0.4, minimatch@^3.1.1: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +mocha@^10.2.0: + version "10.2.0" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-10.2.0.tgz#1fd4a7c32ba5ac372e03a17eef435bd00e5c68b8" + integrity sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg== + dependencies: + ansi-colors "4.1.1" + browser-stdout "1.3.1" + chokidar "3.5.3" + debug "4.3.4" + diff "5.0.0" + escape-string-regexp "4.0.0" + find-up "5.0.0" + glob "7.2.0" + he "1.2.0" + js-yaml "4.1.0" + log-symbols "4.1.0" + minimatch "5.0.1" + ms "2.1.3" + nanoid "3.3.3" + serialize-javascript "6.0.0" + strip-json-comments "3.1.1" + supports-color "8.1.1" + workerpool "6.2.1" + yargs "16.2.0" + yargs-parser "20.2.4" + yargs-unparser "2.0.0" + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +ms@2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +nanoid@3.3.3: + version "3.3.3" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.3.tgz#fd8e8b7aa761fe807dba2d1b98fb7241bb724a25" + integrity sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w== + +normalize-path@^3.0.0, normalize-path@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + +p-limit@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + +p-locate@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" + integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== + dependencies: + p-limit "^3.0.2" + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== + +path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +pathval@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.1.tgz#8534e77a77ce7ac5a2512ea21e0fdb8fcf6c3d8d" + integrity sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ== + +picomatch@^2.0.4, picomatch@^2.2.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +prettier@3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.0.3.tgz#432a51f7ba422d1469096c0fdc28e235db8f9643" + integrity sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg== + +randombytes@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" + integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== + dependencies: + safe-buffer "^5.1.0" + +readdirp@~3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" + integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== + dependencies: + picomatch "^2.2.1" + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== + +rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + +safe-buffer@^5.1.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +semver@^7.5.3: + version "7.5.4" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" + integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== + dependencies: + lru-cache "^6.0.0" + +serialize-javascript@6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.0.tgz#efae5d88f45d7924141da8b5c3a7a7e663fefeb8" + integrity sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag== + dependencies: + randombytes "^2.1.0" + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +signal-exit@^3.0.2: + version "3.0.7" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" + integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== + +string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-json-comments@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +supports-color@8.1.1: + version "8.1.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +test-exclude@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" + integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w== + dependencies: + "@istanbuljs/schema" "^0.1.2" + glob "^7.1.4" + minimatch "^3.0.4" + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + ts-node@^10.9.1: version "10.9.1" resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.1.tgz#e73de9102958af9e1f0b168a6ff320e25adcff4b" @@ -144,6 +844,11 @@ tslib@2.4.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3" integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ== +type-detect@^4.0.0, type-detect@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" + integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== + typescript@^5.1.6: version "5.2.2" resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.2.2.tgz#5ebb5e5a5b75f085f22bc3f8460fba308310fa78" @@ -154,16 +859,117 @@ v8-compile-cache-lib@^3.0.1: resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== +v8-to-istanbul@^9.0.0: + version "9.2.0" + resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-9.2.0.tgz#2ed7644a245cddd83d4e087b9b33b3e62dfd10ad" + integrity sha512-/EH/sDgxU2eGxajKdwLCDmQ4FWq+kpi3uCmBGpw1xJtnAxEjlD8j8PEiGWpCIMIs3ciNAgH0d3TTJiUkYzyZjA== + dependencies: + "@jridgewell/trace-mapping" "^0.3.12" + "@types/istanbul-lib-coverage" "^2.0.1" + convert-source-map "^2.0.0" + +which@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +workerpool@6.2.1: + version "6.2.1" + resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.2.1.tgz#46fc150c17d826b86a008e5a4508656777e9c343" + integrity sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw== + +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + ws@8.5.0: version "8.5.0" resolved "https://registry.yarnpkg.com/ws/-/ws-8.5.0.tgz#bfb4be96600757fe5382de12c670dab984a1ed4f" integrity sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg== +y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== + +yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== + +yargs-parser@20.2.4: + version "20.2.4" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54" + integrity sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA== + +yargs-parser@^20.2.2: + version "20.2.9" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" + integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== + +yargs-parser@^21.1.1: + version "21.1.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" + integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== + +yargs-unparser@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-2.0.0.tgz#f131f9226911ae5d9ad38c432fe809366c2325eb" + integrity sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA== + dependencies: + camelcase "^6.0.0" + decamelize "^4.0.0" + flat "^5.0.2" + is-plain-obj "^2.1.0" + +yargs@16.2.0: + version "16.2.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" + integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== + dependencies: + cliui "^7.0.2" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.0" + y18n "^5.0.5" + yargs-parser "^20.2.2" + +yargs@^17.7.2: + version "17.7.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" + integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== + dependencies: + cliui "^8.0.1" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.3" + y18n "^5.0.5" + yargs-parser "^21.1.1" + yn@3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== + zksync-ethers@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/zksync-ethers/-/zksync-ethers-6.0.0.tgz#60ec1c38bb2a0b844433fa59a33633e258cb00d6"