From b6c282944246c9918728d8642ce86530865445ea Mon Sep 17 00:00:00 2001 From: Sabrina Ferguson Date: Mon, 18 Mar 2024 17:20:01 -0400 Subject: [PATCH] chore: remove docs to start clean --- content/10.getting-started/1.index.md | 4 +- content/20.build/README.md | 109 - content/20.build/api.md | 912 ------ .../account-abstraction.md | 580 ---- .../developer-reference/bridging-asset.md | 89 - .../contract-deployment.md | 152 - .../contract-development.md | 53 - .../differences-with-ethereum.md | 465 --- .../20.build/developer-reference/events.md | 74 - .../20.build/developer-reference/fee-model.md | 158 - .../developer-reference/l1-l2-interop.md | 61 - .../20.build/developer-reference/rollups.md | 70 - .../developer-reference/system-contracts.md | 192 -- .../20.build/developer-reference/zkSync.md | 136 - .../quick-start/add-zksync-to-metamask.md | 40 - .../20.build/quick-start/best-practices.md | 133 - content/20.build/quick-start/hello-world.md | 329 --- content/20.build/quick-start/interact.md | 33 - .../20.build/quick-start/useful-address.md | 67 - content/20.build/sdks/go/accounts-l1-l2.md | 56 - content/20.build/sdks/go/accounts.md | 1543 ---------- content/20.build/sdks/go/clients.md | 1038 ------- content/20.build/sdks/go/contracts.md | 30 - content/20.build/sdks/go/features.md | 129 - content/20.build/sdks/go/getting-started.md | 116 - content/20.build/sdks/go/paymaster-utils.md | 78 - content/20.build/sdks/go/types/accounts.md | 384 --- content/20.build/sdks/go/types/clients.md | 66 - content/20.build/sdks/go/types/eip712.md | 21 - content/20.build/sdks/go/types/intro.md | 18 - content/20.build/sdks/go/types/types.md | 411 --- content/20.build/sdks/go/utils.md | 308 -- content/20.build/sdks/java/accounts-l1-l2.md | 98 - content/20.build/sdks/java/accounts.md | 313 -- content/20.build/sdks/java/getting-started.md | 1085 ------- content/20.build/sdks/java/providers.md | 357 --- content/20.build/sdks/js/accounts-l1-l2.md | 50 - content/20.build/sdks/js/accounts.md | 2548 ---------------- content/20.build/sdks/js/contracts.md | 17 - content/20.build/sdks/js/features.md | 126 - content/20.build/sdks/js/front-end.md | 22 - content/20.build/sdks/js/getting-started.md | 84 - content/20.build/sdks/js/paymaster-utils.md | 91 - content/20.build/sdks/js/providers.md | 1416 --------- content/20.build/sdks/js/types.md | 365 --- content/20.build/sdks/js/utils.md | 834 ------ .../sdks/js/zksync-ethers/accounts-l1-l2.md | 52 - .../sdks/js/zksync-ethers/accounts.md | 2552 ----------------- .../sdks/js/zksync-ethers/contracts.md | 17 - .../sdks/js/zksync-ethers/features.md | 127 - .../sdks/js/zksync-ethers/front-end.md | 22 - .../sdks/js/zksync-ethers/getting-started.md | 96 - .../sdks/js/zksync-ethers/migration.md | 38 - .../sdks/js/zksync-ethers/paymaster-utils.md | 91 - .../sdks/js/zksync-ethers/providers.md | 1407 --------- .../20.build/sdks/js/zksync-ethers/types.md | 345 --- .../20.build/sdks/js/zksync-ethers/utils.md | 834 ------ .../20.build/sdks/python/accounts-l1-l2.md | 234 -- content/20.build/sdks/python/accounts.md | 428 --- content/20.build/sdks/python/contracts.md | 52 - .../20.build/sdks/python/getting-started.md | 163 -- .../20.build/sdks/python/paymaster-utils.md | 66 - content/20.build/sdks/python/providers.md | 384 --- content/20.build/sdks/python/types.md | 191 -- .../contract-deployment-and-interaction.md | 208 -- content/20.build/sdks/rust/getting-started.md | 314 -- content/20.build/sdks/swift/accounts-l1-l2.md | 41 - content/20.build/sdks/swift/accounts.md | 711 ----- .../20.build/sdks/swift/getting-started.md | 69 - .../20.build/sdks/swift/paymaster-utils.md | 50 - content/20.build/support/audit-bug-bounty.md | 103 - .../20.build/support/community-channels.md | 66 - .../20.build/support/contribution-track.md | 117 - content/20.build/support/faq.md | 281 -- content/20.build/support/withdrawal-delay.md | 93 - .../test-and-debug/continuous-integration.md | 163 -- .../test-and-debug/dockerized-l1-l2-nodes.md | 99 - .../20.build/test-and-debug/era-test-node.md | 459 --- content/20.build/test-and-debug/foundry.md | 98 - .../test-and-debug/getting-started.md | 77 - content/20.build/test-and-debug/hardhat.md | 319 --- .../test-and-debug/testing-examples/README.md | 1 - .../testing-examples/impersonate-account.md | 68 - .../testing-examples/time-change.md | 178 -- .../block-explorer/block-explorer-api.md | 36 - .../block-explorer/block-explorer-menu.md | 94 - .../tooling/block-explorer/block-explorers.md | 69 - .../block-explorer/contract-verification.md | 77 - .../tooling/block-explorer/getting-started.md | 78 - content/20.build/tooling/bridges.md | 35 - content/20.build/tooling/compiler-overview.md | 93 - content/20.build/tooling/cross-chain.md | 17 - content/20.build/tooling/data-indexers.md | 48 - .../tooling/foundry/getting-started.md | 347 --- content/20.build/tooling/foundry/overview.md | 60 - .../tooling/hardhat/compiling-libraries.md | 176 -- .../tooling/hardhat/getting-started.md | 367 --- .../hardhat/hardhat-zksync-chai-matchers.md | 165 -- .../tooling/hardhat/hardhat-zksync-deploy.md | 304 -- .../tooling/hardhat/hardhat-zksync-ethers.md | 191 -- .../tooling/hardhat/hardhat-zksync-node.md | 176 -- .../tooling/hardhat/hardhat-zksync-solc.md | 252 -- .../tooling/hardhat/hardhat-zksync-toolbox.md | 61 - .../hardhat/hardhat-zksync-upgradable.md | 793 ----- .../hardhat/hardhat-zksync-verify-vyper.md | 207 -- .../tooling/hardhat/hardhat-zksync-verify.md | 218 -- .../tooling/hardhat/hardhat-zksync-vyper.md | 116 - .../tooling/hardhat/migrating-to-zksync.md | 278 -- .../20.build/tooling/hardhat/other-plugins.md | 79 - content/20.build/tooling/ide.md | 30 - content/20.build/tooling/monitoring.md | 29 - content/20.build/tooling/network-faucets.md | 30 - content/20.build/tooling/nft-marketplaces.md | 43 - content/20.build/tooling/node-providers.md | 55 - content/20.build/tooling/oracles.md | 43 - content/20.build/tooling/wallets.md | 72 - .../tooling/zksync-cli/commands/bridge.md | 110 - .../commands/contract-interaction.md | 338 --- .../tooling/zksync-cli/commands/create.md | 64 - .../zksync-cli/commands/custom-chains.md | 46 - .../tooling/zksync-cli/commands/local-node.md | 76 - .../zksync-cli/commands/transaction-info.md | 122 - .../tooling/zksync-cli/commands/wallet.md | 90 - .../tooling/zksync-cli/getting-started.md | 47 - .../tooling/zksync-cli/troubleshooting.md | 73 - .../frontend-quickstart-paymaster.md | 560 ---- .../gated-nft-paymaster-tutorial.md | 792 ----- .../tutorials/how-to/deposit-erc-20-to-l2.md | 168 -- .../tutorials/how-to/deposit-eth-to-l2.md | 160 -- .../20.build/tutorials/how-to/estimate-gas.md | 363 --- .../tutorials/how-to/send-message-l2-l1.md | 365 --- .../how-to/send-transaction-l1-l2.md | 441 --- .../tutorials/how-to/transfer-token-l2.md | 198 -- .../tutorials/how-to/verify-contracts.md | 333 --- .../tutorials/how-to/withdraw-erc-20-to-l1.md | 158 - .../tutorials/how-to/withdraw-eth-to-l1.md | 156 - .../account-abstraction/custom-aa-tutorial.md | 1223 -------- .../account-abstraction/daily-spend-limit.md | 1135 -------- .../cross-chain-tutorial.md | 664 ----- .../paymasters/allowlist.md | 235 -- .../paymasters/custom-paymaster-tutorial.md | 577 ---- .../paymasters/erc20fixed.md | 384 --- .../paymasters/gasless.md | 254 -- .../paymasters/timebased.md | 302 -- .../20.build/tutorials/tooling-guides/api3.md | 600 ---- .../20.build/tutorials/tooling-guides/dia.md | 249 -- .../tutorials/tooling-guides/layerzero.md | 129 - .../tutorials/tooling-guides/redstone.md | 205 -- .../tutorials/tooling-guides/subquery.md | 257 -- .../tutorials/tooling-guides/the-graph.md | 648 ----- .../20.build/tutorials/tooling-guides/viem.md | 200 -- .../tutorials/tooling-guides/wagmi.md | 519 ---- .../tooling-guides/wallet-connect.md | 107 - .../tutorials/tooling-guides/web3js.md | 84 - content/30.infra/README.md | 52 - content/30.infra/api-overview.md | 120 - content/30.infra/component-breakdown.md | 84 - content/30.infra/configuration.md | 76 - content/30.infra/introduction.md | 165 -- content/30.infra/observability.md | 60 - content/30.infra/running-node.md | 82 - content/30.infra/troubleshooting.md | 66 - content/40.zk-stack/README.md | 52 - .../40.zk-stack/components/block-explorer.md | 20 - .../compiler/specification/code-separation.md | 83 - .../specification/evmla-translator.md | 763 ----- .../specification/exception-handling.md | 137 - .../instructions/evm/arithmetic.md | 388 --- .../specification/instructions/evm/bitwise.md | 229 -- .../specification/instructions/evm/block.md | 176 -- .../specification/instructions/evm/calls.md | 47 - .../specification/instructions/evm/create.md | 27 - .../instructions/evm/environment.md | 350 --- .../specification/instructions/evm/events.md | 37 - .../specification/instructions/evm/hashes.md | 59 - .../specification/instructions/evm/logical.md | 209 -- .../specification/instructions/evm/memory.md | 80 - .../instructions/evm/overview.md | 34 - .../specification/instructions/evm/return.md | 85 - .../specification/instructions/evm/stack.md | 60 - .../specification/instructions/evm/storage.md | 50 - .../specification/instructions/evmla.md | 92 - .../specification/instructions/overview.md | 52 - .../specification/instructions/yul.md | 108 - .../compiler/specification/overview.md | 46 - .../specification/system-contracts.md | 144 - .../components/compiler/toolchain/llvm.md | 33 - .../components/compiler/toolchain/overview.md | 87 - .../components/compiler/toolchain/solidity.md | 128 - .../components/compiler/toolchain/vyper.md | 52 - .../40.zk-stack/components/fee-withdrawer.md | 14 - content/40.zk-stack/components/overview.md | 17 - .../components/portal-wallet-bridge.md | 20 - .../boojum-function-check-if-satisfied.md | 104 - .../components/prover/boojum-gadgets.md | 198 -- .../prover/circuit-testing/README.md | 66 - .../prover/circuits/code-decommitter.md | 215 -- .../prover/circuits/demux-log-queue.md | 233 -- .../components/prover/circuits/ecrecover.md | 327 --- .../prover/circuits/keccak-round-function.md | 210 -- .../prover/circuits/l1-messages-hasher.md | 156 - .../components/prover/circuits/log-sorter.md | 358 --- .../components/prover/circuits/main-vm.md | 349 --- .../components/prover/circuits/overview.md | 128 - .../prover/circuits/ram-permutation.md | 202 -- .../prover/circuits/sha256-round-function.md | 376 --- .../prover/circuits/sorting/log-sorter.md | 358 --- .../prover/circuits/sorting/overview.md | 64 - .../circuits/sorting/sort-decommitments.md | 239 -- .../prover/circuits/sorting/storage-sorter.md | 289 -- .../prover/circuits/storage-application.md | 220 -- .../40.zk-stack/components/prover/overview.md | 69 - .../components/prover/run-the-prover.md | 28 - .../components/prover/zk-terminology.md | 110 - .../components/sequencer-server.md | 54 - .../40.zk-stack/components/shared-bridges.md | 245 -- .../smart-contracts/smart-contracts.md | 291 -- .../smart-contracts/system-contracts.md | 310 -- .../components/zkEVM/bootloader.md | 348 --- .../40.zk-stack/components/zkEVM/overview.md | 34 - .../components/zkEVM/precompiles.md | 183 -- .../zkEVM/vm-specification/formal-spec.md | 13 - .../zkEVM/vm-specification/vm-primer.md | 639 ----- .../concepts/account-abstraction.md | 46 - content/40.zk-stack/concepts/blocks.md | 219 -- .../concepts/data-availability/overview.md | 83 - .../recreate-l2-state-from-l1-state-diffs.md | 52 - content/40.zk-stack/concepts/fee-mechanism.md | 529 ---- content/40.zk-stack/concepts/finality.md | 42 - .../concepts/hyperchains-hyperscaling.md | 334 --- .../concepts/l1_l2_communication.md | 266 -- content/40.zk-stack/concepts/overview.md | 26 - .../40.zk-stack/concepts/system-upgrades.md | 44 - .../concepts/transaction-lifecycle.md | 189 -- content/40.zk-stack/concepts/validiums.md | 63 - .../running-a-hyperchain/dependencies.md | 294 -- .../running-a-hyperchain/enabling-prover.md | 36 - .../running-a-hyperchain/getting-started.md | 8 - .../running-a-hyperchain/locally.md | 256 -- .../running-a-hyperchain/production.md | 24 - .../running-a-hyperchain/using-hyperchain.md | 83 - 241 files changed, 2 insertions(+), 56338 deletions(-) delete mode 100644 content/20.build/README.md delete mode 100644 content/20.build/api.md delete mode 100644 content/20.build/developer-reference/account-abstraction.md delete mode 100644 content/20.build/developer-reference/bridging-asset.md delete mode 100644 content/20.build/developer-reference/contract-deployment.md delete mode 100644 content/20.build/developer-reference/contract-development.md delete mode 100644 content/20.build/developer-reference/differences-with-ethereum.md delete mode 100644 content/20.build/developer-reference/events.md delete mode 100644 content/20.build/developer-reference/fee-model.md delete mode 100644 content/20.build/developer-reference/l1-l2-interop.md delete mode 100644 content/20.build/developer-reference/rollups.md delete mode 100644 content/20.build/developer-reference/system-contracts.md delete mode 100644 content/20.build/developer-reference/zkSync.md delete mode 100644 content/20.build/quick-start/add-zksync-to-metamask.md delete mode 100644 content/20.build/quick-start/best-practices.md delete mode 100644 content/20.build/quick-start/hello-world.md delete mode 100644 content/20.build/quick-start/interact.md delete mode 100644 content/20.build/quick-start/useful-address.md delete mode 100644 content/20.build/sdks/go/accounts-l1-l2.md delete mode 100644 content/20.build/sdks/go/accounts.md delete mode 100644 content/20.build/sdks/go/clients.md delete mode 100644 content/20.build/sdks/go/contracts.md delete mode 100644 content/20.build/sdks/go/features.md delete mode 100644 content/20.build/sdks/go/getting-started.md delete mode 100644 content/20.build/sdks/go/paymaster-utils.md delete mode 100644 content/20.build/sdks/go/types/accounts.md delete mode 100644 content/20.build/sdks/go/types/clients.md delete mode 100644 content/20.build/sdks/go/types/eip712.md delete mode 100644 content/20.build/sdks/go/types/intro.md delete mode 100644 content/20.build/sdks/go/types/types.md delete mode 100644 content/20.build/sdks/go/utils.md delete mode 100644 content/20.build/sdks/java/accounts-l1-l2.md delete mode 100644 content/20.build/sdks/java/accounts.md delete mode 100644 content/20.build/sdks/java/getting-started.md delete mode 100644 content/20.build/sdks/java/providers.md delete mode 100644 content/20.build/sdks/js/accounts-l1-l2.md delete mode 100644 content/20.build/sdks/js/accounts.md delete mode 100644 content/20.build/sdks/js/contracts.md delete mode 100644 content/20.build/sdks/js/features.md delete mode 100644 content/20.build/sdks/js/front-end.md delete mode 100644 content/20.build/sdks/js/getting-started.md delete mode 100644 content/20.build/sdks/js/paymaster-utils.md delete mode 100644 content/20.build/sdks/js/providers.md delete mode 100644 content/20.build/sdks/js/types.md delete mode 100644 content/20.build/sdks/js/utils.md delete mode 100644 content/20.build/sdks/js/zksync-ethers/accounts-l1-l2.md delete mode 100644 content/20.build/sdks/js/zksync-ethers/accounts.md delete mode 100644 content/20.build/sdks/js/zksync-ethers/contracts.md delete mode 100644 content/20.build/sdks/js/zksync-ethers/features.md delete mode 100644 content/20.build/sdks/js/zksync-ethers/front-end.md delete mode 100644 content/20.build/sdks/js/zksync-ethers/getting-started.md delete mode 100644 content/20.build/sdks/js/zksync-ethers/migration.md delete mode 100644 content/20.build/sdks/js/zksync-ethers/paymaster-utils.md delete mode 100644 content/20.build/sdks/js/zksync-ethers/providers.md delete mode 100644 content/20.build/sdks/js/zksync-ethers/types.md delete mode 100644 content/20.build/sdks/js/zksync-ethers/utils.md delete mode 100644 content/20.build/sdks/python/accounts-l1-l2.md delete mode 100644 content/20.build/sdks/python/accounts.md delete mode 100644 content/20.build/sdks/python/contracts.md delete mode 100644 content/20.build/sdks/python/getting-started.md delete mode 100644 content/20.build/sdks/python/paymaster-utils.md delete mode 100644 content/20.build/sdks/python/providers.md delete mode 100644 content/20.build/sdks/python/types.md delete mode 100644 content/20.build/sdks/rust/contract-deployment-and-interaction.md delete mode 100644 content/20.build/sdks/rust/getting-started.md delete mode 100644 content/20.build/sdks/swift/accounts-l1-l2.md delete mode 100644 content/20.build/sdks/swift/accounts.md delete mode 100644 content/20.build/sdks/swift/getting-started.md delete mode 100644 content/20.build/sdks/swift/paymaster-utils.md delete mode 100644 content/20.build/support/audit-bug-bounty.md delete mode 100644 content/20.build/support/community-channels.md delete mode 100644 content/20.build/support/contribution-track.md delete mode 100644 content/20.build/support/faq.md delete mode 100644 content/20.build/support/withdrawal-delay.md delete mode 100644 content/20.build/test-and-debug/continuous-integration.md delete mode 100644 content/20.build/test-and-debug/dockerized-l1-l2-nodes.md delete mode 100644 content/20.build/test-and-debug/era-test-node.md delete mode 100644 content/20.build/test-and-debug/foundry.md delete mode 100644 content/20.build/test-and-debug/getting-started.md delete mode 100644 content/20.build/test-and-debug/hardhat.md delete mode 100644 content/20.build/test-and-debug/testing-examples/README.md delete mode 100644 content/20.build/test-and-debug/testing-examples/impersonate-account.md delete mode 100644 content/20.build/test-and-debug/testing-examples/time-change.md delete mode 100644 content/20.build/tooling/block-explorer/block-explorer-api.md delete mode 100644 content/20.build/tooling/block-explorer/block-explorer-menu.md delete mode 100644 content/20.build/tooling/block-explorer/block-explorers.md delete mode 100644 content/20.build/tooling/block-explorer/contract-verification.md delete mode 100644 content/20.build/tooling/block-explorer/getting-started.md delete mode 100644 content/20.build/tooling/bridges.md delete mode 100644 content/20.build/tooling/compiler-overview.md delete mode 100644 content/20.build/tooling/cross-chain.md delete mode 100644 content/20.build/tooling/data-indexers.md delete mode 100644 content/20.build/tooling/foundry/getting-started.md delete mode 100644 content/20.build/tooling/foundry/overview.md delete mode 100644 content/20.build/tooling/hardhat/compiling-libraries.md delete mode 100644 content/20.build/tooling/hardhat/getting-started.md delete mode 100644 content/20.build/tooling/hardhat/hardhat-zksync-chai-matchers.md delete mode 100644 content/20.build/tooling/hardhat/hardhat-zksync-deploy.md delete mode 100644 content/20.build/tooling/hardhat/hardhat-zksync-ethers.md delete mode 100644 content/20.build/tooling/hardhat/hardhat-zksync-node.md delete mode 100644 content/20.build/tooling/hardhat/hardhat-zksync-solc.md delete mode 100644 content/20.build/tooling/hardhat/hardhat-zksync-toolbox.md delete mode 100644 content/20.build/tooling/hardhat/hardhat-zksync-upgradable.md delete mode 100644 content/20.build/tooling/hardhat/hardhat-zksync-verify-vyper.md delete mode 100644 content/20.build/tooling/hardhat/hardhat-zksync-verify.md delete mode 100644 content/20.build/tooling/hardhat/hardhat-zksync-vyper.md delete mode 100644 content/20.build/tooling/hardhat/migrating-to-zksync.md delete mode 100644 content/20.build/tooling/hardhat/other-plugins.md delete mode 100644 content/20.build/tooling/ide.md delete mode 100644 content/20.build/tooling/monitoring.md delete mode 100644 content/20.build/tooling/network-faucets.md delete mode 100644 content/20.build/tooling/nft-marketplaces.md delete mode 100644 content/20.build/tooling/node-providers.md delete mode 100644 content/20.build/tooling/oracles.md delete mode 100644 content/20.build/tooling/wallets.md delete mode 100644 content/20.build/tooling/zksync-cli/commands/bridge.md delete mode 100644 content/20.build/tooling/zksync-cli/commands/contract-interaction.md delete mode 100644 content/20.build/tooling/zksync-cli/commands/create.md delete mode 100644 content/20.build/tooling/zksync-cli/commands/custom-chains.md delete mode 100644 content/20.build/tooling/zksync-cli/commands/local-node.md delete mode 100644 content/20.build/tooling/zksync-cli/commands/transaction-info.md delete mode 100644 content/20.build/tooling/zksync-cli/commands/wallet.md delete mode 100644 content/20.build/tooling/zksync-cli/getting-started.md delete mode 100644 content/20.build/tooling/zksync-cli/troubleshooting.md delete mode 100644 content/20.build/tutorials/dapp-development/frontend-quickstart-paymaster.md delete mode 100644 content/20.build/tutorials/dapp-development/gated-nft-paymaster-tutorial.md delete mode 100644 content/20.build/tutorials/how-to/deposit-erc-20-to-l2.md delete mode 100644 content/20.build/tutorials/how-to/deposit-eth-to-l2.md delete mode 100644 content/20.build/tutorials/how-to/estimate-gas.md delete mode 100644 content/20.build/tutorials/how-to/send-message-l2-l1.md delete mode 100644 content/20.build/tutorials/how-to/send-transaction-l1-l2.md delete mode 100644 content/20.build/tutorials/how-to/transfer-token-l2.md delete mode 100644 content/20.build/tutorials/how-to/verify-contracts.md delete mode 100644 content/20.build/tutorials/how-to/withdraw-erc-20-to-l1.md delete mode 100644 content/20.build/tutorials/how-to/withdraw-eth-to-l1.md delete mode 100644 content/20.build/tutorials/smart-contract-development/account-abstraction/custom-aa-tutorial.md delete mode 100644 content/20.build/tutorials/smart-contract-development/account-abstraction/daily-spend-limit.md delete mode 100644 content/20.build/tutorials/smart-contract-development/cross-chain-tutorial.md delete mode 100644 content/20.build/tutorials/smart-contract-development/paymasters/allowlist.md delete mode 100644 content/20.build/tutorials/smart-contract-development/paymasters/custom-paymaster-tutorial.md delete mode 100644 content/20.build/tutorials/smart-contract-development/paymasters/erc20fixed.md delete mode 100644 content/20.build/tutorials/smart-contract-development/paymasters/gasless.md delete mode 100644 content/20.build/tutorials/smart-contract-development/paymasters/timebased.md delete mode 100644 content/20.build/tutorials/tooling-guides/api3.md delete mode 100644 content/20.build/tutorials/tooling-guides/dia.md delete mode 100644 content/20.build/tutorials/tooling-guides/layerzero.md delete mode 100644 content/20.build/tutorials/tooling-guides/redstone.md delete mode 100644 content/20.build/tutorials/tooling-guides/subquery.md delete mode 100644 content/20.build/tutorials/tooling-guides/the-graph.md delete mode 100644 content/20.build/tutorials/tooling-guides/viem.md delete mode 100644 content/20.build/tutorials/tooling-guides/wagmi.md delete mode 100644 content/20.build/tutorials/tooling-guides/wallet-connect.md delete mode 100644 content/20.build/tutorials/tooling-guides/web3js.md delete mode 100644 content/30.infra/README.md delete mode 100644 content/30.infra/api-overview.md delete mode 100644 content/30.infra/component-breakdown.md delete mode 100644 content/30.infra/configuration.md delete mode 100644 content/30.infra/introduction.md delete mode 100644 content/30.infra/observability.md delete mode 100644 content/30.infra/running-node.md delete mode 100644 content/30.infra/troubleshooting.md delete mode 100644 content/40.zk-stack/README.md delete mode 100644 content/40.zk-stack/components/block-explorer.md delete mode 100644 content/40.zk-stack/components/compiler/specification/code-separation.md delete mode 100644 content/40.zk-stack/components/compiler/specification/evmla-translator.md delete mode 100644 content/40.zk-stack/components/compiler/specification/exception-handling.md delete mode 100644 content/40.zk-stack/components/compiler/specification/instructions/evm/arithmetic.md delete mode 100644 content/40.zk-stack/components/compiler/specification/instructions/evm/bitwise.md delete mode 100644 content/40.zk-stack/components/compiler/specification/instructions/evm/block.md delete mode 100644 content/40.zk-stack/components/compiler/specification/instructions/evm/calls.md delete mode 100644 content/40.zk-stack/components/compiler/specification/instructions/evm/create.md delete mode 100644 content/40.zk-stack/components/compiler/specification/instructions/evm/environment.md delete mode 100644 content/40.zk-stack/components/compiler/specification/instructions/evm/events.md delete mode 100644 content/40.zk-stack/components/compiler/specification/instructions/evm/hashes.md delete mode 100644 content/40.zk-stack/components/compiler/specification/instructions/evm/logical.md delete mode 100644 content/40.zk-stack/components/compiler/specification/instructions/evm/memory.md delete mode 100644 content/40.zk-stack/components/compiler/specification/instructions/evm/overview.md delete mode 100644 content/40.zk-stack/components/compiler/specification/instructions/evm/return.md delete mode 100644 content/40.zk-stack/components/compiler/specification/instructions/evm/stack.md delete mode 100644 content/40.zk-stack/components/compiler/specification/instructions/evm/storage.md delete mode 100644 content/40.zk-stack/components/compiler/specification/instructions/evmla.md delete mode 100644 content/40.zk-stack/components/compiler/specification/instructions/overview.md delete mode 100644 content/40.zk-stack/components/compiler/specification/instructions/yul.md delete mode 100644 content/40.zk-stack/components/compiler/specification/overview.md delete mode 100644 content/40.zk-stack/components/compiler/specification/system-contracts.md delete mode 100644 content/40.zk-stack/components/compiler/toolchain/llvm.md delete mode 100644 content/40.zk-stack/components/compiler/toolchain/overview.md delete mode 100644 content/40.zk-stack/components/compiler/toolchain/solidity.md delete mode 100644 content/40.zk-stack/components/compiler/toolchain/vyper.md delete mode 100644 content/40.zk-stack/components/fee-withdrawer.md delete mode 100644 content/40.zk-stack/components/overview.md delete mode 100644 content/40.zk-stack/components/portal-wallet-bridge.md delete mode 100644 content/40.zk-stack/components/prover/boojum-function-check-if-satisfied.md delete mode 100644 content/40.zk-stack/components/prover/boojum-gadgets.md delete mode 100644 content/40.zk-stack/components/prover/circuit-testing/README.md delete mode 100644 content/40.zk-stack/components/prover/circuits/code-decommitter.md delete mode 100644 content/40.zk-stack/components/prover/circuits/demux-log-queue.md delete mode 100644 content/40.zk-stack/components/prover/circuits/ecrecover.md delete mode 100644 content/40.zk-stack/components/prover/circuits/keccak-round-function.md delete mode 100644 content/40.zk-stack/components/prover/circuits/l1-messages-hasher.md delete mode 100644 content/40.zk-stack/components/prover/circuits/log-sorter.md delete mode 100644 content/40.zk-stack/components/prover/circuits/main-vm.md delete mode 100644 content/40.zk-stack/components/prover/circuits/overview.md delete mode 100644 content/40.zk-stack/components/prover/circuits/ram-permutation.md delete mode 100644 content/40.zk-stack/components/prover/circuits/sha256-round-function.md delete mode 100644 content/40.zk-stack/components/prover/circuits/sorting/log-sorter.md delete mode 100644 content/40.zk-stack/components/prover/circuits/sorting/overview.md delete mode 100644 content/40.zk-stack/components/prover/circuits/sorting/sort-decommitments.md delete mode 100644 content/40.zk-stack/components/prover/circuits/sorting/storage-sorter.md delete mode 100644 content/40.zk-stack/components/prover/circuits/storage-application.md delete mode 100644 content/40.zk-stack/components/prover/overview.md delete mode 100644 content/40.zk-stack/components/prover/run-the-prover.md delete mode 100644 content/40.zk-stack/components/prover/zk-terminology.md delete mode 100644 content/40.zk-stack/components/sequencer-server.md delete mode 100644 content/40.zk-stack/components/shared-bridges.md delete mode 100644 content/40.zk-stack/components/smart-contracts/smart-contracts.md delete mode 100644 content/40.zk-stack/components/smart-contracts/system-contracts.md delete mode 100644 content/40.zk-stack/components/zkEVM/bootloader.md delete mode 100644 content/40.zk-stack/components/zkEVM/overview.md delete mode 100644 content/40.zk-stack/components/zkEVM/precompiles.md delete mode 100644 content/40.zk-stack/components/zkEVM/vm-specification/formal-spec.md delete mode 100644 content/40.zk-stack/components/zkEVM/vm-specification/vm-primer.md delete mode 100644 content/40.zk-stack/concepts/account-abstraction.md delete mode 100644 content/40.zk-stack/concepts/blocks.md delete mode 100644 content/40.zk-stack/concepts/data-availability/overview.md delete mode 100644 content/40.zk-stack/concepts/data-availability/recreate-l2-state-from-l1-state-diffs.md delete mode 100644 content/40.zk-stack/concepts/fee-mechanism.md delete mode 100644 content/40.zk-stack/concepts/finality.md delete mode 100644 content/40.zk-stack/concepts/hyperchains-hyperscaling.md delete mode 100644 content/40.zk-stack/concepts/l1_l2_communication.md delete mode 100644 content/40.zk-stack/concepts/overview.md delete mode 100644 content/40.zk-stack/concepts/system-upgrades.md delete mode 100644 content/40.zk-stack/concepts/transaction-lifecycle.md delete mode 100644 content/40.zk-stack/concepts/validiums.md delete mode 100644 content/40.zk-stack/running-a-hyperchain/dependencies.md delete mode 100644 content/40.zk-stack/running-a-hyperchain/enabling-prover.md delete mode 100644 content/40.zk-stack/running-a-hyperchain/getting-started.md delete mode 100644 content/40.zk-stack/running-a-hyperchain/locally.md delete mode 100644 content/40.zk-stack/running-a-hyperchain/production.md delete mode 100644 content/40.zk-stack/running-a-hyperchain/using-hyperchain.md diff --git a/content/10.getting-started/1.index.md b/content/10.getting-started/1.index.md index c89c73b3..66f9e3b0 100644 --- a/content/10.getting-started/1.index.md +++ b/content/10.getting-started/1.index.md @@ -34,7 +34,7 @@ There are already many websites based on this template: You can start playing with this template in your browser using our online sandboxes: -## ::u-button +::u-button class: mr-4 icon: i-simple-icons-stackblitz label: Play on StackBlitz target: \_blank to: https://stackblitz.com/github/nuxt-ui-pro/docs/ @@ -43,7 +43,7 @@ https://stackblitz.com/github/nuxt-ui-pro/docs/ :: -## ::u-button +::u-button class: mt-2 sm:mt-0 icon: i-simple-icons-codesandbox label: Play on CodeSandbox target: \_blank to: https://codesandbox.io/s/github/nuxt-ui-pro/docs/ diff --git a/content/20.build/README.md b/content/20.build/README.md deleted file mode 100644 index e7827b23..00000000 --- a/content/20.build/README.md +++ /dev/null @@ -1,109 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Build | zkSync Docs ---- - -# Build - -Find user guides, code samples, SDKs & toolkits, tutorials, API & CLI references, and more. - -
- Getting Started -
-
-
- - Hello World Tutorial -
-

Hello World Quickstart

-

Deploy your first dApp to zkSync.

-
-
- - zkSync ERA documentation -
-

zkSync CLI

-

Local development, contract interaction, custom chains and more.

-
-
- - zkSync ERA Network Faucets -
-

Testnet Faucets

-

Access testnet funds using one of our 3rd party faucets.

-
-
- - zkSync ERA documentation -
-

Paymasters & AA

-

Get Started with Paymasters and Account Abstraction Essentials.

-
-
- - zkSync ERA documentation -
-

In Memory Node

-

Elevate Test Quality and Debug locally with the In Memory Node.

-
-
- - Web3 API -
-

Web3 JSON-RPC API

-

Explore the API endpoints for the zkSync Era node.

-
-
- - FAQs -
-

FAQs

-

Find some of the most common questions about zkSync Era.

-
-
-
-
diff --git a/content/20.build/api.md b/content/20.build/api.md deleted file mode 100644 index 76c113b4..00000000 --- a/content/20.build/api.md +++ /dev/null @@ -1,912 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Web3 JSON-RPC API | zkSync Docs ---- - -# Web3 JSON-RPC API - -zkSync Era supports the standard [Ethereum JSON-RPC API](https://ethereum.org/en/developers/docs/apis/json-rpc/) and -adds some L2-specific features. - -:::tip Tip - -- As long as code does not involve deploying new smart contracts, which can only be deployed using - [EIP712 transactions](../zk-stack/concepts/transaction-lifecycle.md#eip-712-0x71), _no changes to the codebase are - needed_. -- Read the documentation on [EIP-712 transactions](../zk-stack/concepts/transaction-lifecycle.md#eip-712-0x71) for more - information. ::: - -## RPC endpoint URLs - -:::warning Rate Limits - -We apply rate limiting to both HTTPS and Websocket APIs. The limits are generally permissive (currently 10s to 100s RPS -per client), but please [contact us](https://github.com/zkSync-Community-Hub/zkync-developers/discussions) if you face -any issues in that regard. ::: - -### Testnet - -- HTTPS: `https://sepolia.era.zksync.dev` -- Websocket: `wss://sepolia.era.zksync.dev/ws` - -### Mainnet - -- HTTPS: `https://mainnet.era.zksync.io` -- Websocket: `wss://mainnet.era.zksync.io/ws` - -## zkSync Era JSON-RPC methods - -The API may provide methods not detailed here which are used internally by the team. - -::: warning - -- Metamask does not support the `zks_` namespace at the time of writing. -- Instead, use the [`Provider`](../build/sdks/js/providers.md#provider) class with the testnet RPC. ::: - -### `debug_traceBlockByHash` - -Returns debug trace of all executed calls contained in a block given by its L2 hash. - -#### Inputs - -| Parameter | Type | Description | -| --------- | -------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | -| `hash` | `H256` | The 32 byte hash defining the L2 block. | -| `options` | `TracerConfig` | Optional arguments: see the [TraceConfig documentation](https://geth.ethereum.org/docs/interacting-with-geth/rpc/ns-debug#traceconfig) for details. | - -#### Example - -```shell -curl -X POST -H "Content-Type: application/json" \ ---data '{"jsonrpc":"2.0", "id":2, "method": "debug_traceBlockByHash", "params": ["0x4bd0bd4547d8f8a4fc86a024e54558e156c1acf43d82e24733c6dac2fe5c5fc7"] }' \ -"https://mainnet.era.zksync.io" -``` - -#### Output snippet - -```json -{ - "calls": [], - "error": null, - "from": "0x0000000000000000000000000000000000008001", - "gas": "0xe1e31a08", - "gasUsed": "0x27e", - "input": "0x6ef25c3a", - "output": "0x000000000000000000000000000000000000000000000000000000000ee6b280", - "revertReason": null, - "to": "0x000000000000000000000000000000000000800b", - "type": "Call", - "value": "0x0" -}, -``` - -### `debug_traceBlockByNumber` - -Returns debug trace of all executed calls contained in a block given by its L2 block number. - -#### Inputs - -| Parameter | Type | Description | -| --------- | -------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | -| `block` | `BlockNumber` | Block number. | -| `options` | `TracerConfig` | Optional arguments: see the [TraceConfig documentation](https://geth.ethereum.org/docs/interacting-with-geth/rpc/ns-debug#traceconfig) for details. | - -#### Example - -```shell -curl -X POST -H "Content-Type: application/json" \ ---data '{"jsonrpc":"2.0", "id":2, "method": "debug_traceBlockByNumber", "params": [ "0x24b258" ] }' \ -"https://mainnet.era.zksync.io" -``` - -#### Output snippet - -```json -{ - "calls": [], - "error": null, - "from": "0x0000000000000000000000000000000000008001", - "gas": "0xe1e31a08", - "gasUsed": "0x27e", - "input": "0x6ef25c3a", - "output": "0x000000000000000000000000000000000000000000000000000000000ee6b280", - "revertReason": null, - "to": "0x000000000000000000000000000000000000800b", - "type": "Call", - "value": "0x0" -}, -``` - -### `debug_traceCall` - -Returns debug trace containing information on a specific calls given by the call request. - -#### Inputs - -| Parameter | Type | Description | -| --------- | -------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | -| `request` | `CallRequest` | The transaction call request for debugging. | -| `block` | `BlockNumber` | Block number by hash or number (optional). | -| `options` | `TracerConfig` | Optional arguments: see the [TraceConfig documentation](https://geth.ethereum.org/docs/interacting-with-geth/rpc/ns-debug#traceconfig) for details. | - -#### Example - -```shell -curl -X POST -H "Content-Type: application/json" \ ---data '{"jsonrpc":"2.0", "id":2, "method": "debug_traceCall", "params": [ { "from": "0x1111111111111111111111111111111111111111", "to":"0x2222222222222222222222222222222222222222", "data": "0xffffffff" }, "0x24b258" ] }' \ -"https://mainnet.era.zksync.io" -``` - -#### Output snippet - -```json -{ - "calls": [], - "error": null, - "from": "0x0000000000000000000000000000000000008001", - "gas": "0x4b19b87", - "gasUsed": "0x291", - "input": "0x4de2e4680000000000000000000000001111111111111111111111111111111111111111", - "output": "0x0000000000000000000000000000000000000000000000000000000000000000", - "revertReason": null, - "to": "0x0000000000000000000000000000000000008002", - "type": "Call", - "value": "0x0" -}, -``` - -### `debug_traceTransaction` - -Uses the [EVM's `callTracer`](https://geth.ethereum.org/docs/developers/evm-tracing/built-in-tracers#call-tracer) to -return a debug trace of a specific transaction given by its transaction hash. - -#### Inputs - -| Parameter | Type | Description | -| --------- | -------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | -| `hash` | `H256` | The 32 byte hash defining the L2 block. | -| `options` | `TracerConfig` | Optional arguments: see the [TraceConfig documentation](https://geth.ethereum.org/docs/interacting-with-geth/rpc/ns-debug#traceconfig) for details. | - -#### Example - -```shell -curl -X POST -H "Content-Type: application/json" \ ---data '{"jsonrpc":"2.0", "id":2, "method": "debug_traceTransaction", "params": [ "0x4b228f90e796de5a18227072745b0f28e0c4a4661a339f70d3bdde591d3b7f3a" ] }' \ -"https://mainnet.era.zksync.io" -``` - -#### Output snippet - -```json -... -{ - "calls": [], - "error": null, - "from": "0x0000000000000000000000000000000000008001", - "gas": "0xdff51aa3", - "gasUsed": "0x27e", - "input": "0x6ef25c3a", - "output": "0x000000000000000000000000000000000000000000000000000000000ee6b280", - "revertReason": null, - "to": "0x000000000000000000000000000000000000800b", - "type": "Call", - "value": "0x0" -}, -... -``` - -### `zks_estimateFee` - -Returns the fee for the transaction. - -#### Inputs - -| Parameter | Type | Description | -| --------- | ------------- | -------------------------------------------------------------- | -| `request` | `CallRequest` | The zkSync transaction request for which the fee is estimated. | - -#### Example - -```shell -curl -X POST -H "Content-Type: application/json" \ ---data '{"jsonrpc":"2.0", "id":2, "method": "zks_estimateFee", "params": [ { "from": "0x1111111111111111111111111111111111111111", "to":"0x2222222222222222222222222222222222222222", "data": "0xffffffff" } ] }' \ -"https://mainnet.era.zksync.io" -``` - -#### Output - -```json -{ - "jsonrpc": "2.0", - "result": { - "gas_limit": "0x156c00", - "gas_per_pubdata_limit": "0x143b", - "max_fee_per_gas": "0xee6b280", - "max_priority_fee_per_gas": "0x0" - }, - "id": 2 -} -``` - -### `zks_estimateGasL1ToL2` - -Returns an estimate of the gas required for a L1 to L2 transaction. - -#### Inputs - -| Parameter | Type | Description | -| --------- | ------------- | ------------------------------------------------------------------ | -| `request` | `CallRequest` | The zkSync transaction request for which the gas fee is estimated. | - -#### curl example - -```shell -curl -X POST -H "Content-Type: application/json" \ ---data '{"jsonrpc":"2.0", "id":2, "method": "zks_estimateGasL1ToL2", "params": [ { "from": "0x1111111111111111111111111111111111111111", "to":"0x2222222222222222222222222222222222222222", "data": "0xffffffff" } ] }' \ -"https://mainnet.era.zksync.io" -``` - -#### Output - -```json -{ - "jsonrpc": "2.0", - "result": "0x25f64db", - "id": 2 -} -``` - -### `zks_getAllAccountBalances` - -Returns all balances for confirmed tokens given by an account address. - -#### Inputs - -| Parameter | Type | Description | -| --------- | --------- | -------------------- | -| `address` | `Address` | The account address. | - -#### curl example - -```shell -curl -X POST -H "Content-Type: application/json" \ ---data '{"jsonrpc": "2.0", "id": 1, "method": "zks_getAllAccountBalances", "params": [ "0x98E9D288743839e96A8005a6B51C770Bbf7788C0" ]}' \ -"https://mainnet.era.zksync.io" -``` - -#### Output - -```json -{ - "jsonrpc": "2.0", - "result": { - "0x0000000000000000000000000000000000000000": "0x2fbd72a1121b3100" - }, - "id": 2 -} -``` - -### `zks_getBlockDetails` - -Returns additional zkSync-specific information about the L2 block. - -- `committed`: The batch is closed and the state transition it creates exists on layer 1. -- `proven`: The batch proof has been created, submitted, and accepted on layer 1. -- `executed`: The batch state transition has been executed on L1; meaning the root state has been updated. - -#### Inputs - -| Parameter | Type | Description | -| --------- | -------- | ------------------------ | -| block | `uint32` | The number of the block. | - -#### curl example - -```shell -curl -X POST -H "Content-Type: application/json" \ ---data '{"jsonrpc": "2.0", "id": 1, "method": "zks_getBlockDetails", "params": [ 140599 ]}' \ -"https://mainnet.era.zksync.io" -``` - -#### Output - -```json -{ - "jsonrpc": "2.0", - "result": { - "baseSystemContractsHashes": { - "bootloader": "0x010007793a328ef16cc7086708f7f3292ff9b5eed9e7e539c184228f461bf4ef", - "default_aa": "0x0100067d861e2f5717a12c3e869cfb657793b86bbb0caa05cc1421f16c5217bc" - }, - "commitTxHash": "0xd045e3698f018cb233c3817eb53a41a4c5b28784ffe659da246aa33bda34350c", - "committedAt": "2023-03-26T07:21:21.046817Z", - "executeTxHash": "0xbb66aa75f437bb4255cf751badfc6b142e8d4d3a4e531c7b2e737a22870ff19e", - "executedAt": "2023-03-27T07:44:52.187764Z", - "l1BatchNumber": 1617, - "l1GasPrice": 20690385511, - "l1TxCount": 0, - "l2FairGasPrice": 250000000, - "l2TxCount": 20, - "number": 140599, - "operatorAddress": "0xfeee860e7aae671124e9a4e61139f3a5085dfeee", - "proveTxHash": "0x1591e9b16ff6eb029cc865614094b2e6dd872c8be40b15cc56164941ed723a1a", - "provenAt": "2023-03-26T19:48:35.200565Z", - "rootHash": "0xf1adac176fc939313eea4b72055db0622a10bbd9b7a83097286e84e471d2e7df", - "status": "verified", - "timestamp": 1679815038 - }, - "id": 1 -} -``` - -### `zks_getBridgeContracts` - -Returns L1/L2 addresses of default bridges. - -#### Inputs - -None. - -#### curl example - -```shell -curl -X POST -H "Content-Type: application/json" \ ---data '{"jsonrpc": "2.0", "id": 1, "method": "zks_getBridgeContracts", "params": [ ]}' \ -"https://mainnet.era.zksync.io" -``` - -#### Output - -```json -{ - "jsonrpc": "2.0", - "result": { - "l1Erc20DefaultBridge": "0x57891966931eb4bb6fb81430e6ce0a03aabde063", - "l2Erc20DefaultBridge": "0x11f943b2c77b743ab90f4a0ae7d5a4e7fca3e102" - }, - "id": 1 -} -``` - -### `zks_getBytecodeByHash` - -Returns bytecode of a transaction given by its hash. - -#### Inputs - -| Parameter | Type | Description | -| --------- | -------- | ------------------------ | -| `hash` | `H256 ` | Bytecode hash as string. | - -#### curl example - -```shell -curl -X POST -H "Content-Type: application/json" \ ---data '{"jsonrpc": "2.0", "id": 1, "method": "zks_getBytecodeByHash", "params": [ "0x0100067d861e2f5717a12c3e869cfb657793b86bbb0caa05cc1421f16c5217bc" ]}' \ -"https://mainnet.era.zksync.io" -``` - -#### Output - -```json -{ - "jsonrpc": "2.0", - "result": [ - 0, - 4, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 11, - ..., - ..., - ], - "id": 1 -} -``` - -### `zks_getL1BatchBlockRange` - -Returns the range of blocks contained within a batch given by batch number. - -The range is given by beginning/end block numbers in hexadecimal. - -#### Inputs - -| Parameter | Type | Description | -| --------- | --------------- | ------------------------- | -| `batch` | `L1BatchNumber` | The layer 1 batch number. | - -#### curl example - -```shell -curl -X POST -H "Content-Type: application/json" \ ---data '{"jsonrpc": "2.0", "id": 1, "method": "zks_getL1BatchBlockRange", "params": [ 12345 ]}' \ -"https://mainnet.era.zksync.io" -``` - -#### Output - -```json -{ - "jsonrpc": "2.0", - "result": ["0x116fec", "0x117015"], - "id": 1 -} -``` - -### `zks_getL1BatchDetails` - -Returns data pertaining to a given batch. - -#### Inputs - -| Parameter | Type | Description | -| --------- | --------------- | ------------------------- | -| `batch` | `L1BatchNumber` | The layer 1 batch number. | - -#### curl example - -```shell -curl -X POST -H "Content-Type: application/json" \ ---data '{"jsonrpc": "2.0", "id": 1, "method": "zks_getL1BatchDetails", "params": [ 12345 ]}' \ -"https://mainnet.era.zksync.io" -``` - -#### Output - -```json -{ - "jsonrpc": "2.0", - "result": { - "baseSystemContractsHashes": { - "bootloader": "0x010007793a328ef16cc7086708f7f3292ff9b5eed9e7e539c184228f461bf4ef", - "default_aa": "0x0100067d861e2f5717a12c3e869cfb657793b86bbb0caa05cc1421f16c5217bc" - }, - "commitTxHash": "0xe5e76d1e17cff2b7232d40ddf43c245e29c76e5354571aa8083d73e793efb64a", - "committedAt": "2023-04-09T18:05:40.548203Z", - "executeTxHash": "0x19c125a6104f731bcc1ce378f090c808e97c6d634fc32cb786694a94fc8219a1", - "executedAt": "2023-04-10T18:48:25.009708Z", - "l1GasPrice": 29424338466, - "l1TxCount": 9, - "l2FairGasPrice": 250000000, - "l2TxCount": 294, - "number": 12345, - "proveTxHash": "0xe980f58feed22a4dbc46fe0339bfcbc09f51c99b2f3bc4f9f60e710ea5f0a2da", - "provenAt": "2023-04-09T22:51:16.200810Z", - "rootHash": "0x994d2738f7ac89b45c8381a7816307b501c00b3127afc79e440dbf1b3e3b5a8c", - "status": "verified", - "timestamp": 1681063384 - }, - "id": 1 -} -``` - -### `zks_getL2ToL1LogProof` - -Given a transaction hash, and an index of the L2 to L1 log produced within the transaction, it returns the proof for the -corresponding L2 to L1 log. - -The index of the log that can be obtained from the transaction receipt (it includes a list of every log produced by the -transaction). - -#### Inputs - -| Parameter | Type | Description | -| ------------------ | --------- | ---------------------------------------------------------------- | -| tx_hash | `bytes32` | Hash of the L2 transaction the L2 to L1 log was produced within. | -| l2_to_l1_log_index | `number` | The index of the L2 to L1 log in the transaction (optional). | - -#### curl example - -```shell -curl -X POST -H "Content-Type: application/json" \ ---data '{"jsonrpc": "2.0", "id": 1, "method": "zks_getL2ToL1LogProof", "params": [ "0x2a1c6c74b184965c0cb015aae9ea134fd96215d2e4f4979cfec12563295f610e" ]}' \ -"https://mainnet.era.zksync.io" -``` - -#### Output - -If there was no such message, the returned value is `null`. Otherwise: - -```json -{ - "jsonrpc": "2.0", - "result": { - "id": 0, - "proof": [ - "0x8c48910df2ca7de509daf50b3182fcdf2dd6c422c6704054fd857d6c9516d6fc", - "0xc5028885760b8b596c4fa11497c783752cb3a3fb3b8e6b52d7e54b9f1c63521e", - "0xeb1f451eb8163723ee19940cf3a8f2a2afdf51100ce8ba25839bd94a057cda16", - "0x7aabfd367dea2b5306b8071c246b99566dae551a1dbd40da791e66c4f696b236", - "0xe4733f281f18ba3ea8775dd62d2fcd84011c8c938f16ea5790fd29a03bf8db89", - "0x1798a1fd9c8fbb818c98cff190daa7cc10b6e5ac9716b4a2649f7c2ebcef2272", - "0x66d7c5983afe44cf15ea8cf565b34c6c31ff0cb4dd744524f7842b942d08770d", - "0xb04e5ee349086985f74b73971ce9dfe76bbed95c84906c5dffd96504e1e5396c", - "0xac506ecb5465659b3a927143f6d724f91d8d9c4bdb2463aee111d9aa869874db" - ], - "root": "0x920c63cb0066a08da45f0a9bf934517141bd72d8e5a51421a94b517bf49a0d39" - }, - "id": 1 -} -``` - -The `id` is the position of the leaf in the Merkle tree of L2->L1 messages for the block. The `proof` is the Merkle -proof for the message, while the `root ` is the root of the Merkle tree of L2->L1 messages. Please note, that the Merkle -tree uses _sha256_ for the trees. - -The `id` and `proof` can be used right away for interacting with the zkSync Era smart contract. - -::: tip - -- The list of L2 to L1 logs produced by the transaction, which is included in the receipts, is a combination of logs - produced by the `L1Messenger` contract or other system contracts/bootloader. -- The bootloader produces a log for every L1-originated transaction that outputs if the transaction has succeeded. ::: - -### `zks_getL2ToL1MsgProof` - -Given a block, a sender, a message, and an optional message log index in the block containing the L1->L2 message, it -returns the proof for the message sent via the L1Messenger system contract. - -#### Inputs - -| Parameter | Type | Description | -| --------------- | --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| block | `uint32` | The number of the block where the message was emitted. | -| sender | `address` | The sender of the message (i.e. the account that called the L1Messenger system contract). | -| msg | `bytes32` | The keccak256 hash of the sent message. | -| l2_log_position | `uint256` | The index in the block of the event that was emitted by the [L1Messenger](../build/developer-reference/system-contracts.md#l1messenger) when submitting this message. If it is omitted, the proof for the first message returns. | - -#### curl example - -```shell -curl -X POST -H "Content-Type: application/json" \ ---data '{"jsonrpc": "2.0", "id": 1, "method": "zks_getL2ToL1MsgProof", "params": [ 5187, "0x87869cb87c4Fa78ca278dF358E890FF73B42a39E", "0x22de7debaa98758afdaee89f447ff43bab5da3de6acca7528b281cc2f1be2ee9" ]}' \ -"https://mainnet.era.zksync.io" -``` - -#### Output - -The same as in [zks_getL2ToL1LogProof](#zks-getl2tol1logproof). - -::: warning - -- `zks_getL2ToL1MsgProof` endpoint will be deprecated in favor of `zks_getL2ToL1LogProof`. ::: - -### `zks_getMainContract` - -Returns the address of the zkSync Era contract. - -#### Inputs - -None. - -#### curl example - -```shell -curl -X POST -H "Content-Type: application/json" \ ---data '{"jsonrpc": "2.0", "id": 1, "method": "zks_getMainContract", "params": [ ]}' \ -"https://mainnet.era.zksync.io" -``` - -#### Output - -```json -{ - "jsonrpc": "2.0", - "result": "0x32400084c286cf3e17e7b677ea9583e60a000324", - "id": 1 -} -``` - -### `zks_getProof` - -Returns Merkle proofs for one or more storage values at the specified account along with a Merkle proof of their -authenticity. This allows to verify that the values have not been tampered with. - -This RPC method is similar to `eth_getProof` in Ethereum, but there are notable differences caused by different Merkle -tree construction: - -- The point in time at which the requested values with proofs are returned is specified as an L1 batch number, rather - than a block number. -- The Merkle tree is constructed in a different way, and so proofs need to be verified differently. In Ethereum, the - Merkle tree of the system state is a two-level hexadecimal trie (the upper level corresponds to accounts, the lower – - to storage slots within the account). In Era, the Merkle tree is one level full binary tree with 256-bit keys (see its - specification below). -- Because of the flat tree, account-level values in Ethereum are stored using special account and storage key - combinations. For example, the code hash for account address A is stored at account - `0x0000000000000000000000000000000000008002` and storage key pad_address(A), where pad_address pads the address from - the start with 12 zero bytes. - -**zkSync Era Merkle tree specification:** - -- The Merkle tree is one-level full binary tree with 256-bit keys and 40-byte values. -- Tree keys are computed as `reversed(blake2s256([0_u8; 12] ++ account_address ++ storage_key))`, where: - - `account_address` is a 20-byte account address, - - `storage_key` is a 32-byte key in the account storage - - `++` is byte concatenation - - `reversed` is a function reversing the order of bytes in the provided bytes sequence. -- Tree values are `big_endian(leaf_index) ++ storage_value`, where: - - `leaf_index` is a 64-bit 1-based enumeration index of the entry. Indices are assigned in the order entries are - filled. - - `storage_value` is a 32-byte value of the slot. -- If a tree entry is vacant, it is considered to have `[0_u8; 40]` value (i.e., 40 zero bytes). -- Tree leaves are hashed using `blake2s256` hash function without a tag. E.g., a hash of a vacant leaf is - `blake2s256([0_u8; 40])`. -- Internal tree nodes are hashed using `blake2s256` hash function without a tag: - `blake2s256(left_child_hash ++ right_child_hash)`. - -#### Inputs - -| Parameter | Type | Description | -| ------------- | --------- | ----------------------------------------------------------------------------------------------- | -| address | `Address` | The account to fetch storage values and proofs for. | -| keys | `H256[]` | Vector of storage keys in the account. | -| l1BatchNumber | `number` | Number of the L1 batch specifying the point in time at which the requested values are returned. | - -#### curl example - -```shell -curl -X POST -H "Content-Type: application/json" --data '{"jsonrpc": "2.0", "id": 1, "method": "zks_getProof", "params": ["0x0000000000000000000000000000000000008003", ["0x8b65c0cf1012ea9f393197eb24619fd814379b298b238285649e14f936a5eb12"], 354895 ] }' "https://mainnet.era.zksync.io" -``` - -#### Output - -An object with the following fields: - -- `address`: account address -- `storageProof`: proof for each of the requested keys in the order at which they were requested. - -Each `storageProof` is an object with the following fields: - -| Field | Type | Description | -| ------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `key` | `H256` | the requested storage key | -| `value` | `H256` | the storage value at address + key at `l1BatchNumber` | -| `index` | `u64` | 1-based integer enumeration index of the tree entry (see the tree spec above) | -| `proof` | `H256[]` | sequence of zero or more 32-byte hashes that form a Merkle path for key in the Merkle tree. Hashes are listed using the root-to-leaf ordering. The root hash is excluded; it is published on L1 as a part of L1 batch commit data. If there are less than 256 hashes in proof (which is overwhelmingly likely), then hashes are omitted from the end of the Merkle path. All omitted hashes are hashes of the entirely empty subtrees of the corresponding height. For example, if `proof` has 255 hashes, then the single omitted hash is `empty_value_hash = blake2s256([0_u8; 40])`. If `proof` has 254 hashes, then the 2 omitted hashes are `blake2s256(empty_value_hash ++ empty_value_hash)`, `empty_value_hash`, etc. | - -For each `StorageProof`, it is possible to restore the Merkle tree root hash and compare it to the reference value -published on L1. If the hashes match, the value authenticity is proven. - -Example output: - -```json -{ - "jsonrpc": "2.0", - "result": { - "address": "0x0000000000000000000000000000000000008003", - "storageProof": [ - { - "key": "0x8b65c0cf1012ea9f393197eb24619fd814379b298b238285649e14f936a5eb12", - "proof": [ - "0xe3e8e49a998b3abf8926f62a5a832d829aadc1b7e059f1ea59ffbab8e11edfb7", - "0x9bebfa036e85a6ffb6bf447a9c7d41af176642c6aaf5cfbc97128f4f10d8a25a", - "0xcca89548554c0402d1ad9d40f58357dd63f9a8797312764a7a2117fdf3c3cf27", - "0xb300d43e85e6985e813e1d6f9231e14e3d0b150a177ca4b84b14f56a40d7460e", - "0x85d3157d7a7437390e78db2b43ab66f46543ba54bae5a6d4165fc6c0a731369c", - "0xa76e30d2ea9e9fc1842273540126743c1eed6ebab3468cc0e73ceb48b60bbbc5", - "0xe870299d2381b56dc3a01dfd12c71662aedffa74686d56b35199352761b7d7e5", - "0x95ddfc7d513311b3ac273699246ea095495f4155253de3e7d34e0a3643c5fbd8", - "0x31110aa2a06a06bbc692255235eb69188e9a29d20548057f76f6a3068e1a0506", - "0x9cfb69d119d1e7a4dc671e99d4ecc8f0cc5a7ed5e2225106949d6ac7d17ba8a2", - "0x92fe999cb989e97693398f4a6bb7c3db3cb35e256e2a0a3c1bbb6772e2dc8df8", - "0xaa6feb7cb008ee03c6a3aa05920f4d2258a21aede994c5f190c4828cff12c672", - "0x1d4e754ebcfe090aa99541027a44622c48faa5aa0ce44e74764296a307f11a9a", - "0x1618d709ec45a19f4c4decc234965d9d56e5630bfb03de0b8efab3b0d3fdd5c3", - "0x9eca9d5f3d18e7a7006e1a7dae94756b95b1e498b638a9b16e08a123aafab1fb", - "0xb270c37699110bb9c32218d5da501b945ecef12cf200f32d606a8b250aa5b13a", - "0x027f56999d7c97c5ed711f38972ae251bfff9ef450a12024e8680dadfe8d1952", - "0x67ebd9c0e1dd1e1b8a2039d5a761f99aa16845ba6ced8243dad2cfbf32fd1e35", - "0x6b349489a60360783e70d701549e8ef90ddab85352e3810c6a70c5c3493c7b58", - "0xf3f33bc89d6cf6a79aff4fa51cb8d98b0437c0ee49c2c4fcb8745ee4e6478274", - "0x0269c9296ebf77ac4603fb5040455f88ccacb7f186e56029f209c383d8d4128c", - "0xa557bd43406ed8e6fedf52a8d5fadd97c4be39ec43862e95b8761cd3f58b89ee", - "0xc461d0f39807b910e8fa76107e99f99f346a3f3e7faa40343ee2ddf53c4e6b4d", - "0xf7fd5de13defb75017e587a4c2e58c33f7118f066367868e8a7e5b1ee2800260", - "0x42c0e6cfbd0f0bc0505538ec04c120a21477c109b0a576247d7d45919d400ede", - "0x9cb345b482f45358dd0a57afce927d7b85756f6d49c2ae0dc7f7908fb27d3cc2", - "0x0a39e3389d2437d160f3d95cdf30f61c1afd52a2f82cafd2ac32a6b6ea823e9b", - "0x9ebd7b37a21fb0c74d0040a941038887caf4e4c7dfaa182b82915cacc6191025", - "0x4550ab30af8c76557a74d051eb43a964889d383d6da343c6a4f4799595d86f9c" - ], - "value": "0x0000000000000000000000000000000000000000000000000000000000000060", - "index": 27900957 - } - ] - }, - "id": 1 -} -``` - -### `zks_getRawBlockTransactions` - -Returns data of transactions in a block. - -#### Inputs - -| Parameter | Type | Description | -| --------- | -------- | ------------- | -| `block` | `uint32` | Block number. | - -#### curl example - -```shell -curl -X POST -H "Content-Type: application/json" \ ---data '{"jsonrpc": "2.0", "id": 1, "method": "zks_getRawBlockTransactions", "params": [ 5817 ]}' \ -"https://mainnet.era.zksync.io" -``` - -#### Output - -```json -{ - "jsonrpc": "2.0", - "result": [ - { - "common_data": { - "L1": { - "canonicalTxHash": "0x22de7debaa98758afdaee89f447ff43bab5da3de6acca7528b281cc2f1be2ee9", - "deadlineBlock": 0, - "ethBlock": 16751339, - "ethHash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "fullFee": "0x0", - "gasLimit": "0x989680", - "gasPerPubdataLimit": "0x320", - "layer2TipFee": "0x0", - "maxFeePerGas": "0x0", - "opProcessingType": "Common", - "priorityQueueType": "Deque", - "refundRecipient": "0x87869cb87c4fa78ca278df358e890ff73b42a39e", - "sender": "0x87869cb87c4fa78ca278df358e890ff73b42a39e", - "serialId": 67, - "toMint": "0x0" - } - }, - "execute": { - "calldata": "0x471c46c800000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000100000000000000000000000031edd5a882583cbf3a712e98e100ef34ad6934b400000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001", - "contractAddress": "0xfc5b07a5dd1b80cf271d35642f75cc0500ff1e2c", - "factoryDeps": [], - "value": "0x0" - }, - "received_timestamp_ms": 1677887544169 - } - ], - "id": 1 -} -``` - -### `zks_getTestnetPaymaster` - -Returns the address of the [testnet paymaster](../build/developer-reference/account-abstraction.md#testnet-paymaster): -the paymaster that is available on testnets and enables paying fees in ERC-20 compatible tokens. - -#### Inputs - -None. - -#### curl example - -```shell -curl -X POST -H "Content-Type: application/json" \ ---data '{"jsonrpc": "2.0", "id": 1, "method": "zks_getTestnetPaymaster", "params": [ ]}' \ -"https://sepolia.era.zksync.dev" -``` - -#### Output - -```json -{ - "jsonrpc": "2.0", - "result": "0x8f0ea1312da29f17eabeb2f484fd3c112cccdd63", - "id": 1 -} -``` - -### `zks_getTransactionDetails` - -Returns data from a specific transaction given by the transaction hash. - -#### Inputs - -| Parameter | Type | Description | -| --------- | ------ | --------------------------- | -| `hash` | `H256` | Transaction hash as string. | - -#### curl example - -```shell -curl -X POST -H "Content-Type: application/json" \ ---data '{"jsonrpc": "2.0", "id": 1, "method": "zks_getTransactionDetails", "params": [ "0x22de7debaa98758afdaee89f447ff43bab5da3de6acca7528b281cc2f1be2ee9" ]}' \ -"https://mainnet.era.zksync.io" -``` - -#### Output - -```json -{ - "jsonrpc": "2.0", - "result": { - "ethCommitTxHash": "0x3da5b6eda357189c9243c41c5a33b1b2ed0169be172705d74681a25217702772", - "ethExecuteTxHash": "0xdaff5fd7ff91333b161de54534b4bb6a78e5325329959a0863bf0aae2b0fdcc6", - "ethProveTxHash": "0x2f482d3ea163f5be0c2aca7819d0beb80415be1a310e845a2d726fbc4ac54c80", - "fee": "0x0", - "gasPerPubdata": "0x320", - "initiatorAddress": "0x87869cb87c4fa78ca278df358e890ff73b42a39e", - "isL1Originated": true, - "receivedAt": "2023-03-03T23:52:24.169Z", - "status": "verified" - }, - "id": 1 -} -``` - -### `zks_L1BatchNumber` - -Returns the latest L1 batch number. - -#### Inputs - -None. - -#### curl example - -```shell -curl -X POST -H "Content-Type: application/json" \ ---data '{"jsonrpc": "2.0", "id": 1, "method": "zks_L1BatchNumber", "params": [ ]}' \ -"https://mainnet.era.zksync.io" -``` - -#### Output - -```json -{ - "jsonrpc": "2.0", - "result": "0x544c", - "id": 1 -} -``` - -### `zks_L1ChainId` - -Returns the chain id of the underlying L1. - -#### Inputs - -None. - -#### curl example - -```shell -curl -X POST -H "Content-Type: application/json" \ ---data '{"jsonrpc": "2.0", "id": 1, "method": "zks_L1ChainId", "params": [ ]}' \ -"https://mainnet.era.zksync.io" -``` - -#### Output - -```json -{ - "jsonrpc": "2.0", - "result": "0x1", - "id": 1 -} -``` - -## PubSub API - -zkSync is fully compatible with [Geth's pubsub API](https://geth.ethereum.org/docs/interacting-with-geth/rpc/pubsub), -except for the `syncing` subscription. This is because nodes on the zkSync network are technically always synchronized. - -The WebSocket URL is `wss://sepolia.era.zksync.dev/ws`. - -::: tip - -- Use the websocket endpoint to handle smart contract events, as detailed - [in this section of the docs](../build/developer-reference/events.md). ::: diff --git a/content/20.build/developer-reference/account-abstraction.md b/content/20.build/developer-reference/account-abstraction.md deleted file mode 100644 index 926dd023..00000000 --- a/content/20.build/developer-reference/account-abstraction.md +++ /dev/null @@ -1,580 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Account Abstraction | zkSync Docs ---- - -# Account Abstraction - -::: warning - -- Please note that with the system update released in Feb 2023, the `ergs` concept is only used by the VM while the API - layer operates with `gas`. -- For more information, read the [changelog]. ::: - -## Introduction - -On Ethereum there are two types of accounts: -[externally owned accounts (EOAs)](https://ethereum.org/en/developers/docs/accounts/#externally-owned-accounts-and-key-pairs) -and [contracts accounts](https://ethereum.org/en/developers/docs/accounts/#contract-accounts). The former type is the -only one that can initiate transactions, while the latter is the only one that can implement arbitrary logic. For some -use-cases, like smart-contract wallets or privacy protocols, this difference can create a lot of friction. As a result, -such applications require L1 relayers, e.g. an EOA to help facilitate transactions from a smart-contract wallet. - -Accounts in zkSync Era can initiate transactions, like an EOA, but can also have arbitrary logic implemented in them, -like a smart contract. This feature, called "account abstraction" (AA), aims to resolve the issues described above. - -::: warning - -- zkSync Era is the first EVM-compatible chain to implement native account abstraction. We are evaluating how well the - implementation works with EVM projects on testnet and mainnet. No incompatibilities have been found so far. -- Due to the early stage nature of the feature, you may see some breaking changes to the account abstraction - API/interfaces. However, given that accounts are versioned in zkSync Era, older accounts will still work even after - breaking changes are released. ::: - -Native Account Abstraction on zkSync Era fundamentally changes how accounts operate by introducing the concept of Smart -Accounts and Paymasters. Smart Accounts are fully programmable, allowing for various customizations such as signature -schemes, native multi-sig capabilities, spending limits, and application-specific restrictions. - -::: info The native account abstraction of zkSync and Ethereum's EIP 4337 aim to enhance accounts' flexibility and user -experience, but they differ in key aspects; learn more [here](./differences-with-ethereum.md#native-aa-vs-eip-4337). ::: - -Paymasters, conversely, can sponsor transactions for users, enabling users to pay transaction fees in ERC20 tokens. This -innovative approach to account management significantly enhances user experience, security, and flexibility, paving the -way for broader adoption of blockchain technology. - -## Prerequisites - -To better understand this page, we recommend you take some time to first read a guide on -[accounts](https://ethereum.org/en/developers/docs/accounts/). - -## Design - -The account abstraction protocol on zkSync is very similar to [EIP4337](https://eips.ethereum.org/EIPS/eip-4337), though -our protocol is still different for the sake of efficiency and better UX. - -### Keeping nonces unique - -::: warning - -- The current model does not allow custom wallets to send multiple transactions at the same time and maintain - deterministic ordering. -- For EOAs, nonces are expected to grow sequentially; while for custom accounts the order of transactions cannot be - guaranteed. -- In the future, we plan to switch to a model where accounts can choose between sequential or arbitrary nonce-ordering. - ::: - -One of the important invariants of every blockchain is that each transaction has a unique hash. Holding this property -with an arbitrary account abstraction is not trivial, though accounts can, in general, accept multiple identical -transactions. Even though these transactions would be technically valid by the rules of the blockchain, violating hash -uniqueness would be very hard for indexers and other tools to process. - -There needs to be a solution on the protocol level that is both cheap for users and robust in case of a malicious -operator. One of the easiest ways to ensure that transaction hashes do not repeat is to have a pair (sender, nonce) -always unique. - -The following protocol is used: - -- Before each transaction starts, the system queries the - [NonceHolder](../../zk-stack/components/smart-contracts/system-contracts.md#nonceholder) to check whether the provided - nonce has already been used or not. -- If the nonce has not been used yet, the transaction validation is run. The provided nonce is expected to be marked as - "used" during this time. -- After the validation, the system checks whether this nonce is now marked as used. - -Users will be allowed to use any 256-bit number as nonce and they can put any non-zero value under the corresponding key -in the system contract. This is already supported by the protocol, but not on the server side. - -More documentation on various interactions with the `NonceHolder` system contract as well as tutorials will be available -once support on the server side is released. For now, it is recommended to only use the `incrementMinNonceIfEquals` -method, which practically enforces the sequential ordering of nonces. - -### Standardizing transaction hashes - -In the future, it is planned to support efficient proofs of transaction inclusion on zkSync. This would require us to -calculate the transaction's hash in the [bootloader](../../zk-stack/components/zkEVM/bootloader.md). Since these -calculations won't be free to the user, it is only fair to include the transaction's hash in the interface of the AA -methods (in case the accounts may need this value for some reason). That's why all the methods of the `IAccount` and -`IPaymaster` interfaces, which are described below, contain the hash of the transaction as well as the recommended -signed digest (the digest that is signed by EOAs for this transaction). - -### IAccount interface - -Each account is recommended to implement the -[IAccount](https://github.com/matter-labs/era-contracts/blob/main/system-contracts/contracts/interfaces/IAccount.sol) -interface. It contains the following five methods: - -- `validateTransaction` is mandatory and will be used by the system to determine if the AA logic agrees to proceed with - the transaction. In case the transaction is not accepted (e.g. the signature is wrong) the method should revert. In - case the call to this method succeeds, the implemented account logic is considered to accept the transaction, and the - system will proceed with the transaction flow. -- `executeTransaction` is mandatory and will be called by the system after the fee is charged from the user. This - function should perform the execution of the transaction. -- `payForTransaction` is optional and will be called by the system if the transaction has no paymaster, i.e. the account - is willing to pay for the transaction. This method should be used to pay for the fees by the account. Note, that if - your account will never pay any fees and will always rely on the [paymaster](#paymasters) feature, you don't have to - implement this method. This method must send at least `tx.gasprice * tx.gasLimit` ETH to the - [bootloader](./system-contracts.md#bootloader) address. -- `prepareForPaymaster` is optional and will be called by the system if the transaction has a paymaster, i.e. there is a - different address that pays the transaction fees for the user. This method should be used to prepare for the - interaction with the paymaster. One of the notable [examples](#approval-based-paymaster-flow) where it can be helpful - is to approve the ERC-20 tokens for the paymaster. -- `executeTransactionFromOutside`, technically, is not mandatory, but it is _highly encouraged_, since there needs to be - some way, in case of priority mode (e.g. if the operator is unresponsive), to be able to start transactions from your - account from ``outside'' (basically this is the fallback to the standard Ethereum approach, where an EOA starts - transaction from your smart contract). - -### IPaymaster interface - -Like in EIP4337, our account abstraction protocol supports paymasters: accounts that can compensate for other accounts' -transactions execution. You can read more about them [here](#paymasters). - -Each paymaster should implement the -[IPaymaster](https://github.com/matter-labs/era-contracts/blob/main/system-contracts/contracts/interfaces/IPaymaster.sol) -interface. It contains the following two methods: - -- `validateAndPayForPaymasterTransaction` is mandatory and will be used by the system to determine if the paymaster - approves paying for this transaction. If the paymaster is willing to pay for the transaction, this method must send at - least `tx.gasprice * tx.gasLimit` to the operator. It should return the `context` that will be one of the call - parameters to the `postTransaction` method. -- `postTransaction` is optional and is called after the transaction executes. Note that unlike EIP4337, there _is no - guarantee that this method will be called_. In particular, this method won't be called if the transaction fails with - `out of gas` error. It takes four parameters: the context returned by `validateAndPayForPaymasterTransaction`, the - transaction itself, a flag that indicates whether the transaction execution succeeded, and the maximum amount of gas - the paymaster might be refunded with. - -### Reserved fields of the `Transaction` struct with special meaning - -Note that each of the methods above accept the -[Transaction](https://github.com/matter-labs/era-contracts/blob/main/system-contracts/contracts/libraries/TransactionHelper.sol) -struct. While some of its fields are self-explanatory, there are also 6 `reserved` fields, the meaning of each is -defined by the transaction's type. We decided to not give these fields names, since they might be unneeded in some -future transaction types. For now, the convention is: - -- `reserved[0]` is the nonce. -- `reserved[1]` is `msg.value` that should be passed with the transaction. - -### The transaction flow - -Each transaction goes through the following flow: - -#### The validation step - -During the validation step, the account should decide whether it accepts the transaction and if so, pay the fees for it. -If any part of the validation fails, the account is not charged a fee, and such transaction can not be included in a -block. - -**Step 1.** The system checks that the nonce of the transaction has not been used before. You can read more about -preserving the nonce uniqueness [here](#keeping-nonces-unique). - -**Step 2.** The system calls the `validateTransaction` method of the account. If it does not revert, proceed to the next -step. - -**Step 3.** The system checks that the nonce of the transaction has been marked as used. - -**Step 4 (no paymaster).** The system calls the `payForTransaction` method of the account. If it does not revert, -proceed to the next step. - -**Step 4 (paymaster).** The system calls the `prepareForPaymaster` method of the sender. If this call does not revert, -then the `validateAndPayForPaymasterTransaction` method of the paymaster is called. If it does not revert too, proceed -to the next step. - -**Step 5.** The system verifies that the bootloader has received at least `tx.gasPrice * tx.gasLimit` ETH to the -bootloader. If it is the case, the verification is considered complete and we can proceed to the next step. - -#### The execution step - -The execution step is considered responsible for the actual execution of the transaction and sending the refunds for any -unused gas back to the user. If there is any revert on this step, the transaction is still considered valid and will be -included in the block. - -**Step 6.** The system calls the `executeTransaction` method of the account. - -**Step 7. (only in case the transaction has a paymaster)** The `postTransaction` method of the paymaster is called. This -step should typically be used for refunding the sender the unused gas in case the paymaster was used to facilitate -paying fees in ERC-20 tokens. - -### Fees - -In EIP4337 you can see three types of gas limits: `verificationGas`, `executionGas`, `preVerificationGas`, that describe -the gas limit for the different steps of the transaction inclusion in a block. zkSync Era has only a single field, -`gasLimit`, that covers the fee for all three. When submitting a transaction, make sure that `gasLimit` is enough to -cover verification, paying the fee (the ERC20 transfer mentioned above), and the actual execution itself. - -By default, calling `estimateGas` adds a constant to cover charging the fee and the signature verification for EOA -accounts. - -## Using the `SystemContractsCaller` library - -For the sake of security, both `NonceHolder` and the `ContractDeployer` system contracts can only be called with a -special `isSystem` flag. You can read more about it -[here](./system-contracts.md#protected-access-to-some-of-the-system-contracts). To make a call with this flag, the -`systemCall`/`systemCallWithPropagatedRevert`/`systemCallWithReturndata` methods of the -[SystemContractsCaller](https://github.com/matter-labs/era-contracts/blob/main/system-contracts/contracts/libraries/SystemContractsCaller.sol) -library should be used. - -Using this library is practically a must when developing custom accounts since this is the only way to call non-view -methods of the `NonceHolder` system contract. Also, you will have to use this library if you want to allow users to -deploy contracts of their own. You can use the -[implementation](https://github.com/matter-labs/era-contracts/blob/main/system-contracts/contracts/DefaultAccount.sol) -of the EOA account as a reference. - -## Extending EIP4337 - -To provide DoS protection for the operator, EIP4337 imposes several -[restrictions](https://eips.ethereum.org/EIPS/eip-4337#simulation) on the validation step of the account. Most of them, -especially those regarding the forbidden opcodes, are still relevant. However, several restrictions have been lifted for -better UX. - -### Extending the allowed opcodes - -- It is allowed to `call`/`delegateCall`/`staticcall` contracts that were already deployed. Unlike Ethereum, we have no - way to edit the code that was deployed or delete the contract via selfdestruct, so we can be sure that the code during - the execution of the contract will be the same. - -### Extending the set of slots that belong to a user - -In the original EIP, the `validateTransaction` step of the AA allows the account to read only the storage slots of its -own. However, there are slots that _semantically_ belong to that user but are actually located on another contract’s -addresses. A notable example is `ERC20` balance. - -This limitation provides DDoS safety by ensuring that the slots used for validation by various accounts _do not -overlap_, so there is no need for them to _actually_ belong to the account’s storage. - -To enable reading the user's ERC20 balance or allowance on the validation step, the following types of slots will be -allowed for an account with address `A` on the validation step: - -1. Slots that belong to address `A`. -2. Slots `A` on any other address. -3. Slots of type `keccak256(A || X)` on any other address. (to cover `mapping(address => value)`, which is usually used - for balance in ERC20 tokens). - -### What could be allowed in the future? - -In the future, we might even allow time-bound transactions, e.g. allow checking that `block.timestamp <= value` if it -returned `false`, etc. This would require deploying a separate library of such trusted methods, but it would greatly -increase the capabilities of accounts. - -## Building custom accounts - -As already mentioned above, each account should implement the [IAccount](#iaccount-interface) interface. - -An example of the implementation of the AA interface is the -[implementation](https://github.com/matter-labs/era-contracts/blob/main/system-contracts/contracts/DefaultAccount.sol) -of the EOA account. Note that this account, just like standard EOA accounts on Ethereum, successfully returns empty -value whenever it is called by an external address, while this may not be the behaviour that you would like for your -account. - -### EIP1271 - -If you are building a smart wallet, we also _highly encourage_ you to implement the -[EIP1271](https://eips.ethereum.org/EIPS/eip-1271) signature-validation scheme. This is the standard that is endorsed by -the zkSync team. It is used in the signature-verification library described below in this section. - -### The deployment process - -The process of deploying account logic is very similar to the one of deploying a smart contract. In order to protect -smart contracts that do not want to be treated as an account, a different method of the deployer system contract should -be used to do it. Instead of using `create`/`create2`, you should use the `createAccount`/`create2Account` methods of -the deployer system contract. - -Here is an example of how to deploy account logic using the `zksync-ethers` SDK (v5): - -```ts -import { ContractFactory } from 'zksync-ethers'; - -const contractFactory = new ContractFactory(abi, bytecode, initiator, 'createAccount'); -const aa = await contractFactory.deploy(...args); -await aa.deployed(); -``` - -### Limitations of the verification step - -::: warning - -- The verification rules are not yet fully enforced. -- Even if your custom account works at the moment, it could stop working in the future if it does not follow the rules - below. ::: - -In order to protect the system from a DoS threat, the verification step must have the following limitations: - -- The account logic can only touch slots that belong to the account. Note, that the - [definition](#extending-the-set-of-slots-that-belong-to-a-user) is far beyond just the slots that are at the users' - address. -- The account logic can not use context variables (e.g. `block.number`). -- It is also required that your account increases the nonce by 1. This restriction is only needed to preserve - transaction hash collision resistance. In the future, this requirement will be lifted to allow more generic use-cases - (e.g. privacy protocols). - -Transactions that violate the rules above will not be accepted by the API, though these requirements can not be enforced -on the circuit/VM level and do not apply to L1->L2 transactions. - -To let you try out the feature faster, we decided to release account abstraction publicly before fully implementing the -limitations' checks for the verification step of the account. Currently, your transactions may pass through the API -despite violating the requirements above, but soon this will be changed. - -### Nonce holder contract - -For optimization purposes, both -[tx nonce and the deployment nonce](./contract-deployment.md#differences-in-create-behaviour) are put in one storage -slot inside the [NonceHolder](./system-contracts.md#nonceholder) system contracts. In order to increment the nonce of -your account, it is highly recommended to call the -[incrementMinNonceIfEquals](https://github.com/matter-labs/era-contracts/blob/6250292a98179cd442516f130540d6f862c06a16/system-contracts/contracts/NonceHolder.sol#L110) -function and pass the value of the nonce provided in the transaction. - -This is one of the whitelisted calls, where the account logic is allowed to call outside smart contracts. - -### Sending transactions from an account - -For now, only EIP712 transactions are supported. To submit a transaction from a specific account, you should provide the -`from` field of the transaction as the address of the sender and the `customSignature` field of the `customData` with -the signature for the account. - -```ts -import { utils } from 'zksync-ethers'; - -// here the `tx` is a `TransactionRequest` object from `zksync-ethers` SDK. -// and the zksyncProvider is the `Provider` object from `zksync-ethers` SDK connected to zkSync network. -tx.from = aaAddress; -tx.customData = { - ...tx.customData, - customSignature: aaSignature, -}; -const serializedTx = utils.serialize({ ...tx }); - -const sentTx = await zksyncProvider.sendTransaction(serializedTx); -``` - -## Paymasters - -Imagine being able to pay fees for users of your protocol! Paymasters are accounts that can compensate for other -accounts' transactions. The other important use-case of paymasters is to facilitate paying fees in ERC20 tokens. While -ETH is the formal fee token in zkSync, paymasters can provide the ability to exchange ERC20 tokens to ETH on the fly. - -If users want to interact with a paymaster, they should provide the non-zero `paymaster` address in their EIP712 -transaction. The input data to the paymaster is provided in the `paymasterInput` field of the paymaster. - -### Paymaster verification rules - -::: warning - -- The verification rules are not yet fully enforced. -- Even if your paymaster works at the moment, it could stop working in the future if it does not follow the rules below. - ::: - -Since multiple users should be allowed to access the same paymaster, malicious paymasters _can_ do a DoS attack on our -system. To work around this, a system similar to the -[EIP4337 reputation scoring](https://eips.ethereum.org/EIPS/eip-4337#reputation-scoring-and-throttlingbanning-for-paymasters) -will be used. - -Unlike in the original EIP, paymasters are allowed to touch any storage slots. Also, the paymaster won't be throttled if -either of the following is true: - -- More than `X` minutes have passed since the verification has passed on the API nodes (the exact value of `X` will be - defined later). -- The order of slots being read is the same as during the run on the API node and the first slot whose value has changed - is one of the user's slots. This is needed to protect the paymaster from malicious users (e.g. the user might have - erased the allowance for the ERC20 token). - -### Built-in paymaster flows - -While some paymasters can trivially operate without any interaction from users (e.g. a protocol that always pays fees -for their users), some require active participation from the transaction's sender. A notable example is a paymaster that -swaps users' ERC20 tokens to ETH as it requires the user to set the necessary allowance to the paymaster. - -The account abstraction protocol by itself is generic and allows both accounts and paymasters to implement arbitrary -interactions. However, the code of default accounts (EOAs) is constant, but we still want them to be able to participate -in the ecosystem of custom accounts and paymasters. That's why we have standardized the `paymasterInput` field of the -transaction to cover the most common uses-cases of the paymaster feature. - -Your accounts are free to implement or not implement the support for these flows. However, this is highly encouraged to -keep the interface the same for both EOAs and custom accounts. - -#### General paymaster flow - -It should be used if no prior actions are required from the user for the paymaster to operate. - -The `paymasterInput` field must be encoded as a call to a function with the following interface: - -```solidity -function general(bytes calldata data); -``` - -EOA accounts will do nothing and the paymaster can interpret this `data` in any way. - -#### Approval-based paymaster flow - -It should be used if the user is required to set certain allowance to a token for the paymaster to operate. The -`paymasterInput` field must be encoded as a call to a function with the following signature: - -```solidity -function approvalBased( - address _token, - uint256 _minAllowance, - bytes calldata _innerInput -) -``` - -The EOA will ensure that the allowance of the `_token` towards the paymaster is set to at least `_minAllowance`. The -`_innerInput` param is an additional payload that can be sent to the paymaster to implement any logic (e.g. an -additional signature or key that can be validated by the paymaster). - -If you are developing a paymaster, you _should not_ trust the transaction sender to behave honestly (e.g. provide the -required allowance with the `approvalBased` flow). These flows serve mostly as instructions to EOAs and the requirements -should always be double-checked by the paymaster. - -#### Working with paymaster flows using `zksync-ethers` SDK - -The `zksync-ethers` SDK provides [methods](../../build/sdks/js/paymaster-utils.md) for encoding correctly formatted -paymaster params for all of the built-in paymaster flows. - -### Testnet paymaster - -To ensure users experience paymasters on testnet, as well as keep supporting paying fees in ERC20 tokens, the Matter -Labs team provides the testnet paymaster, that enables paying fees in ERC20 token at a 1:1 exchange rate with ETH (i.e. -one unit of this token is equal to 1 wei of ETH). - -The paymaster supports only the [approval based](#approval-based-paymaster-flow) paymaster flow and requires that the -`token` param is equal to the token being swapped and `minAllowance` to equal to least `tx.maxFeePerGas * tx.gasLimit`. -In addition, the testnet paymaster does not make use of the `_innerInput` parameter, so nothing should be provided -(empty `bytes`). - -An example of how to use testnet paymaster can be seen in the -[frontend quickstart](../tutorials/dapp-development/frontend-quickstart-paymaster.md#pay-fees-with-erc20-tokens) -tutorial. - -### Estimating gas when interacting with a paymaster - -While the paymaster pays the fees for the user, it also consumes additional gas compared to a normal transaction, which -includes: - -1. Computation inside the paymaster's `validateAndPayForPaymasterTransaction` as well as `postTransaction`. -2. Paymaster sending funds to the bootloader. -3. Assigning and spending the allowance for the ERC20 tokens by the user. (optional, in case the user pays the paymaster - in an ERC20 token) - -While the (1) is usually quite negligible (it, of course, depends on the implementation of each individual paymaster), -(2) is roughly similar to what the user would pay in a transaction if it was to be spent by the user on its own, the (3) -is unique for the paymaster operations, i.e. it is effectively an additional slot that is affected. Especially if the -user grants allowance for the first time, since it would require 32 bytes to publish the storage key identifier, which -may amount to roughly 400k gas under 50 gwei L1 gas price. Note, that even though the usual flow is "grant `X` allowance -to the paymaster + paymaster spends all allowance", which means that the slot is zeroed out at the end of the execution, -the cost for write is pre-charged during execution. In other words, we firstly charge for pubdata required for updating -the allowance and if the slot has been zeroed out by the end of the transaction, the user will be refunded, but only at -the end of the transaction. - -All of the above means that the estimation of the transaction must be as close to the final execution as possible. -Especially, with regard to pubdata-intensive operations, like writing to storage. - -On the front-end side you should provide the corresponding `paymasterInput` to ensure that the paymaster is used during -estimation. The corresponding snippet from the -[Custom paymaster tutorial](../tutorials/smart-contract-development/paymasters/custom-paymaster-tutorial.md) shows how -to do it: - -```ts -const gasLimit = await erc20.estimateGas.mint(wallet.address, 5, { - customData: { - gasPerPubdata: utils.DEFAULT_GAS_PER_PUBDATA_LIMIT, - paymasterParams: paymasterParams, - }, -}); -``` - -Here, the `paymasterParams` contain both the address of the paymaster as well as its input. - -Often `paymasterInput` contains some parameters that are hard to know at the time of the estimation. For instance: the -actual amount of tokens that the user needs to provide. Also, often paymasters may store the pricing data on the server -side and so a signature that allows a certain conversion rate may be needed. - -If some signature that depends on the content of the transaction is required, it is better to return `magic = 0` from -the `validateAndPayForPaymasterTransaction`, while consuming roughly the same amount of gas as verification of a valid -signature would require. This way it will ensure that while the transaction wouldn't pass on mainnet (since `magic = 0`) -it will still be able to estimate the correct number of gas needed for this function to work. Note, that gas estimation -is basically a binary search that searches for the lower number of gas that makes the transaction not fail, so if for -some reason the validation is reverted, the gas estimation will try to provide a higher gas value. If it always fails, -the gas estimation will fail also. The correctness of the `magic` value is checked during transaction submission only -and is not checked during estimation. - -Sometimes, unfortunately it will create "chicken and egg" problem. In order to know how much tokens should user grant to -the paymaster, the paymaster needs to know the `gasLimit`, but in order to know the `gasLimit` we need to know the state -diff created by the changes to the allowance. We already add some % to the estimated gas, so a small difference from the -final amount is usually accceptable, but at a relatively close estimate should be provided in the `paymasterParams`. - -There are two ways to provide the allowance for estimate: - -- If you have a rough estimation on how many funds the user will end up paying, you can use it. If the difference is on - the order of a few pubdata bytes, it won't cause the tx to fail as our estimation already takes it into account. This - approach is prone to some issues: for instance if user has a balance of 100 USDC and creates a tx that transfers 95 - USDC from the users' balance, while during estimation you will assume that the user spends 10 USDC for the fee, the tx - will fail (since it wont have enough funds for the actual transaction). -- Alternatively you could estimate the cost of an individual transaction where the user would just set the allowance to - the paymaster and then add this cost on top of the original estimated one. This may introduce a noticeable overhead to - the original estimation, since such estimated tx would also include changing the nonce/general validation logic. - -## Signature validation - -Your project can start preparing for native AA support. We highly encourage you to do so, since it will allow you to -onboard hundreds of thousands of users (many new Wallets are smart accounts by default, providing way smoother -experience for users). We expect that in the future even more users will switch to smart wallets. - -One of the most notable differences between various types of accounts to be built is different signature schemes. We -expect accounts to support the [EIP-1271](https://eips.ethereum.org/EIPS/eip-1271) standard. - -The -[`@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/5ed5a86d1d22f387ce69ab4e0ace405de8bc888d/contracts/utils/cryptography/SignatureChecker.sol#L22) -library provides a way to verify signatures for different account implementations. We strongly encourage you to use this -library whenever you need to check that a signature of an account is correct. - -### Adding the library to your project - -``` -yarn add @openzeppelin/contracts -``` - -### Example of using the library - -```solidity -pragma solidity ^0.8.0; - -import { SignatureChecker } from "@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol"; - -contract TestSignatureChecker { - using SignatureChecker for address; - - function isValidSignature( - address _address, - bytes32 _hash, - bytes memory _signature - ) public pure returns (bool) { - return _address.isValidSignatureNow(_hash, _signature); - } -} -``` - -## Verifying AA signatures within our SDK - -It is also **not recommended** to use `ethers.js` library to verify user signatures. - -Our SDK provides two methods with its `utils` to verify the signature of an account: - -```ts -export async function isMessageSignatureCorrect( - address: string, - message: ethers.Bytes | string, - signature: SignatureLike -): Promise; - -export async function isTypedDataSignatureCorrect( - address: string, - domain: TypedDataDomain, - types: Record>, - value: Record, - signature: SignatureLike -): Promise; -``` - -Currently these methods only support verifying ECDSA signatures, but very soon they will support EIP1271 signature -verification as well. - -Both of these methods return `true` or `false` depending on whether the message signature is correct. diff --git a/content/20.build/developer-reference/bridging-asset.md b/content/20.build/developer-reference/bridging-asset.md deleted file mode 100644 index 37707eb3..00000000 --- a/content/20.build/developer-reference/bridging-asset.md +++ /dev/null @@ -1,89 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Bridging Assets | zkSync Docs ---- - -# Bridging Assets - -Users can deposit and withdraw assets from zkSync Era using any of the -[multiple bridges](https://zksync.io/explore#bridges). - -Under the hood, bridging is implemented by having two contracts (one deployed to L1, and the second deployed to L2) -communicating with each other using [L1 <-> L2 interoperability](./l1-l2-interop.md). - -Developers are free to build their own [custom bridge for any token](#custom-bridges-on-l1-and-l2) however, we provide -default bridges (one for ETH and one for ERC20 tokens), which can be used for basic bridging. - -::: warning - -Addresses of tokens on L2 will always differ from the same token L1 address. Also note, that tokens bridged via the -default bridge only support standard ERC20 functionality, i.e. rebase tokens and other custom behavior are not -supported. - -::: - -## Default bridges - -You can get the default bridge addresses using the [`zks_getBridgeContracts`](../api.md#zks-getbridgecontracts) endpoint -or [`getDefaultBridgeAddresses`](../sdks/js/providers.md#getdefaultbridgeaddresses) method of `Provider`. Similar -methods are available in the other SDKs. - -### Deposits (to L2) - -Users must call the `deposit` method on the L1 bridge contract, which triggers the following actions: - -- The user's L1 tokens will be sent to the L1 bridge and become locked there. -- The L1 bridge initiates a transaction to the L2 bridge using L1 -> L2 communication. -- Within the L2 transaction, tokens will be minted and sent to the specified address on L2. - - If the token does not exist on zkSync yet, a new contract is deployed for it. Given the L2 token address is - deterministic (based on the original L1 address, name and symbol), it doesn't matter who is the first person - bridging it, the new L2 address will be the same. -- For every executed L1 -> L2 transaction, there will be an L2 -> L1 log message confirming its execution. -- Lastly, the `finalizeDeposit`method is called and it finalizes the deposit and mints funds on L2. - -You can find example scripts to deposit ETH and ERC20 tokens using the default bridges in the how-to section of the -docs. - -### Withdrawals (to L1) - -:::tip - -- To provide additional security during the Alpha phase, **withdrawals in zkSync Era take 24 hours**. -- For more information, read the [withdrawal delay guide](../support/withdrawal-delay.md). ::: - -Users must call the `withdraw` method on the L2 bridge contract, which will trigger the following actions: - -- L2 tokens will be burned. -- An L2 -> L1 message with the information about the withdrawal will be sent. -- After that, the withdrawal action will be available to be finalized by anyone in the L1 bridge (by proving the - inclusion of the L2 -> L1 message, which is done when calling the `finalizeWithdrawal` method on the L1 bridge - contract). -- After the method is called, the funds are unlocked from the L1 bridge and sent to the withdrawal recipient. - -::: warning On the testnet environment, we automatically finalize all withdrawals, i.e., for every withdrawal, we will -take care of it by making an L1 transaction that proves the inclusion for each message. ::: - -## Custom bridges on L1 and L2 - -To build a custom bridge, create a regular Solidity contract which extends one of the interfaces mentioned below for the -layer. The interfaces provide access to the zkSync Era SDK deposit and withdraw implementations. - -- L1: - [IL1Bridge.sol](https://github.com/matter-labs/era-contracts/blob/main/l1-contracts/contracts/bridge/interfaces/IL1Bridge.sol) - - For more information, check out our example - [L1 custom bridge implementation](https://github.com/matter-labs/era-contracts/blob/main/l1-contracts/contracts/bridge/L1ERC20Bridge.sol). - -- L2: - [IL2Bridge.sol](https://github.com/matter-labs/era-contracts/blob/main/l1-contracts/contracts/bridge/interfaces/IL2Bridge.sol) - - For more information, check out our example - [L2 custom bridge implementation](https://github.com/matter-labs/era-contracts/blob/main/l2-contracts/contracts/bridge/L2ERC20Bridge.sol). - -## Adding Tokens to the Bridge UI - -No action is required to add tokens to the bridge UI. All tokens are automatically recognized based on user balances. If -you desire for your token to display an icon or price, refer to the -[Token Listing Guide](../support/faq.md#token-listing). diff --git a/content/20.build/developer-reference/contract-deployment.md b/content/20.build/developer-reference/contract-deployment.md deleted file mode 100644 index 1544e763..00000000 --- a/content/20.build/developer-reference/contract-deployment.md +++ /dev/null @@ -1,152 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Contract Deployment | zkSync Docs ---- - -# Contract Deployment - -In order to maintain the same level of security as the L1, the zkSync operator is required to publish the code for each -contract it deploys on the Ethereum chain. However, if multiple contracts are deployed using the same code, the operator -only needs to publish it on Ethereum once. While the initial deployment of contracts can be relatively expensive, -utilizing contract factories that deploy contracts with the same code multiple times can lead to huge savings compared -to the L1. - -These specific requirements ensure that the process of deploying smart contracts on zkEVM complies to a crucial rule: -_the operator must be aware of the contract's code before deployment_. Consequently, deploying contracts can only be -accomplished through EIP712 transactions, with the `factory_deps` field containing the bytecode provided. - -[Learn more about EIP712 transactions here](../../zk-stack/concepts/transaction-lifecycle.md#eip-712-0x71). - -## Ethereum / zkSync differences in contract deployment - -**How deploying contracts works on Ethereum.** - -To deploy a contract on Ethereum, a user sends a transaction to the zero address (`0x000...000`) with the `data` field -of the transaction equal to the contract bytecode concatenated with the constructor parameters. - -**How deploying contracts works on zkSync.** - -To deploy a contract on zkSync Era, a user calls the `create` function of the -[ContractDeployer system contract](./system-contracts.md#contractdeployer) providing the hash of the contract to be -published, as well as the constructor arguments. The contract bytecode itself is supplied in the `factory_deps` field of -the transaction (as it's an [EIP712 transaction](../../zk-stack/concepts/transaction-lifecycle.md#eip-712-0x71)). If the -contract is a factory (i.e. it can deploy other contracts), these contracts' bytecodes should be included in the -`factory_deps` as well. - -We recommend using the [hardhat-zksync-deploy](../tooling/hardhat/getting-started.md) plugin, to simplify the deployment -process. It provides classes and methods to take care of all the deployment requirements, like generating the -[bytecode hash of the contract](#contract-size-limit-and-format-of-bytecode-hash). - -Here's a [step-by-step guide on how to use it](../tooling/hardhat/getting-started.md). - -### Note on `factory_deps` - -You might wonder how validators obtain the preimage of the bytecode hashes necessary to execute the code. This is where -the concept of factory dependencies, or factory_deps for short, comes into play. Factory dependencies refer to a list of -bytecode hashes whose corresponding preimages were previously revealed on the L1 (where data is always available). - -Under the hood, zkSync does not store bytecodes of contracts, but -[specially formatted hashes of the bytecodes](#contract-size-limit-and-format-of-bytecode-hash). You can see that the -[ContractDeployer](./system-contracts.md#contractdeployer) system contract accepts the bytecode hash of the deployed -contract and not its bytecode. However, for contract deployment to succeed, the operator needs to know the bytecode. The -`factory_deps` field of the transaction is used for this reason: it contains the bytecodes that should be known to the -operator for this transaction to succeed. Once the transaction succeeds, these bytecodes are published on L1 and are -considered "known" to the operator forever. - -Some examples of usage are: - -- The obvious one is when you deploy a contract, you need to provide its code in the `factory_deps` field. -- On zkSync, factories (i.e. contracts that can deploy other contracts) do not store bytecodes of their dependencies, - i.e. contracts that they can deploy. They only store their hashes. That's why you need to include _all_ the bytecodes - of the dependencies in the `factory_deps` field. - -Both of these examples are already seamlessly done under the hood by our -[hardhat-zksync-deploy](../tooling/hardhat/getting-started.md). - -Note that the factory deps do not necessarily have to be used by the transaction in any way. These are just markers that -these bytecodes should be published on L1 with this transaction. If your contract contains a lot of various factory -dependencies and they do not fit inside a single L1 block, you can split the list of factory dependencies between -multiple transactions. - -For example, let's say that you want to deploy contract `A` which can also deploy contracts `B` and `C`. This means that -you will have three factory dependencies for your deployment transaction: `A`,`B` and `C`. If the pubdata required to -publish all of them is too large to fit into one block, you can send a dummy transaction with only factory dependencies -`A` and `B` (assuming their combined length is small enough) and do the actual deploy with a second transaction while -providing the bytecode of contract `C` as a factory dependency for it. Note that if some contract _on its own_ is larger -than the allowed limit per block, this contract has to be split into smaller ones. - -### Contract size limit and format of bytecode hash - -Each zkEVM bytecode must adhere to the following format: - -- Its length must be divisible by 32. -- Its length in words (32-byte chunks) should be odd. In other words, `bytecodeLength % 64 == 32`. -- It can not be longer than `2^16` 32-byte words, i.e. `2^21` bytes. - -The 32-byte hash of the bytecode of a zkSync contract is calculated in the following way: - -- The first 2 bytes denote the version of bytecode hash format and are currently equal to `[1,0]`. -- The second 2 bytes denote the length of the bytecode in 32-byte words. -- The rest of the 28-byte (i.e. 28 low big-endian bytes) are equal to the last 28 bytes of the `sha256` hash of the - contract's bytecode. - -## Smart contract security - -Smart contract security is critical. A single vulnerability in a smart contract can lead to loss of funds. Make sure -your contracts are secure against common threats. - -A common Solidity smart contract attack is reentrancy. This threat exploits vulnerabilities in contract code that allow -an attacker to repeatedly call a function that withdraws funds. - -Auditing smart contracts for security holes prevents theft and other malicious activities. An audit involves a thorough -review of the contract's code and its underlying logic to identify any vulnerabilities or weaknesses that could be -exploited by attackers. Auditors look for things like buffer overflows, integer overflows, and other types of security -issues that can lead to the loss of assets or other unwanted outcomes. This review process should include both manual -and automated testing to ensure that all vulnerabilities are identified. - -The process of auditing a smart contract should be carried out by experts who have the necessary knowledge and -experience to identify potential security risks. Investing in a thorough audit can help prevent security breaches and -protect investors and users from losses, reputation damage, and legal issues. Therefore, it's essential to prioritize -smart contract security and take proactive measures to ensure that they are thoroughly audited for security holes before -deploying your smart contract on zkSync Era network. - -For detailed information on smart contract vulnerabilities and security best practices, refer to the following -resources: - -- [Consensys smart contract best practices](https://consensys.github.io/smart-contract-best-practices/). -- [Solidity docs security considerations](https://docs.soliditylang.org/en/latest/security-considerations.html). -- [Security considerations and best practices on zkSync](../quick-start/best-practices.md) - -### Differences in `create()` behaviour - -To facilitate [support for account abstraction](../developer-reference/account-abstraction.md), zkSync splits the nonce -of each account into two parts: the deployment nonce and the transaction nonce. The deployment nonce represents the -number of contracts the account has deployed using the `create()` opcode, while the transaction nonce is used for -protecting against replay attacks for transactions. - -This distinction implies that, while the nonce on zkSync behaves similarly to Ethereum for smart contracts, calculating -the address of a deployed contract for externally owned accounts (EOAs) is not as straightforward. - -On Ethereum, it can be safely determined using the formula `hash(RLP[address, nonce])`. However, on zkSync, it is -advisable to wait until the contract is deployed and catch the `ContractDeployed` event emitted by the -[ContractDeployer](./system-contracts#contractdeployer), which provides the address of the newly deployed contract. The -SDK handles all of these processes in the background to simplify the workflow. - -To have a deterministic address, you should use the `create2` method from -[ContractDeployer](./system-contracts.md#contractdeployer). It is available for EOAs as well. - -## Deploying contracts from L1 - -Deploying contracts on zkSync Era is also possible via L1-L2 communication. - -The -[interface](https://github.com/matter-labs/era-contracts/blob/main/l1-contracts/contracts/zksync/interfaces/IZkSync.sol) -for submitting L1->L2 transactions accepts the list of all the factory dependencies required for this particular -transaction. The logic for working with them is the same as for the default L2 deployments. The only difference is that -since the user has already published the full preimage for the bytecodes on L1, there is no need to publish these -bytecodes again on L1. - -To learn more about L1-L2 communication on zkSync Era, visit -[this section of the docs](../developer-reference/l1-l2-interop.md). diff --git a/content/20.build/developer-reference/contract-development.md b/content/20.build/developer-reference/contract-development.md deleted file mode 100644 index 9706e070..00000000 --- a/content/20.build/developer-reference/contract-development.md +++ /dev/null @@ -1,53 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Smart Contract Development | zkSync Docs ---- - -# Smart Contract Development - -zkSync Era allows developers to build projects using the same programming languages and tools used to build on Ethereum. - -::: tip Differences with Ethereum - -Although most smart contracts work out of the box, we **strongly recommend developers to read about the -[differences between Ethereum and zkSync Era](./differences-with-ethereum.md)**, and test their projects using the -[local setup](../test-and-debug/getting-started.md) and in testnet. - -::: - -## Solidity support - -Currently, Solidity versions as old as `0.4.12` are supported, although **we strongly recommend using the latest -supported revision of 0.8**, as older versions contain known bugs and -[have limitations with our compiler](../../zk-stack/components/compiler/toolchain/solidity.md#limitations). - -Please read [this section of the docs](../../zk-stack/components/compiler/toolchain/solidity.md#using-libraries) if your -project uses libraries. - -::: info Security and best practices Follow the -[security considerations and best practices](../quick-start/best-practices.md) to build smart contracts on zkSync Era. -::: - -## Vyper support - -Currently only Vyper 0.3.3 and 0.3.9 versions are supported. Versions 0.3.4 to 0.3.8 (both included) are not supported. - -## Compilers - -Although you can write smart contracts in both Solidity and Vyper, compiling these contracts to our zkEVM bytecode -requires special compilers: - -- [zksolc](https://github.com/matter-labs/zksolc-bin): Solidity compiler. -- [zkvyper](https://github.com/matter-labs/zkvyper-bin): Vyper compiler. - -**It's strongly recommended to use the latest version of the compiler available.** - -You can find more information about our compilers in the -[Compiler toolchain section](../../zk-stack/components/compiler/toolchain/overview.md). - -**Learn more about how to install and configure the compiler Hardhat plugins in the links below:** - -- [hardhat-zksync-solc documentation](../tooling/hardhat/hardhat-zksync-solc.md) -- [hardhat-zksync-vyper documentation](../tooling/hardhat/hardhat-zksync-vyper.md) diff --git a/content/20.build/developer-reference/differences-with-ethereum.md b/content/20.build/developer-reference/differences-with-ethereum.md deleted file mode 100644 index d28f914f..00000000 --- a/content/20.build/developer-reference/differences-with-ethereum.md +++ /dev/null @@ -1,465 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Differences with Ethereum | zkSync Docs ---- - -# Differences from Ethereum - -zkSync Era handles nearly all smart contracts based on the Ethereum Virtual Machine (EVM) and upholds high security -standards, minimizing the need for repeated security audits. Nevertheless, it's essential to recognize the following -differences. - -:::tip Best practices It's highly recommended to review the best practices and key considerations for creating smart -contracts on zkSync Era section [here](../quick-start/best-practices.md). ::: - -## EVM instructions - -### `CREATE`, `CREATE2` - -On zkSync Era, contract deployment is performed using the hash of the bytecode, and the `factoryDeps` field of EIP712 -transactions contains the bytecode. The actual deployment occurs by providing the contract's hash to the -`ContractDeployer` system contract. - -To guarantee that `create`/`create2` functions operate correctly, the compiler must be aware of the bytecode of the -deployed contract in advance. The compiler interprets the calldata arguments as incomplete input for `ContractDeployer`, -as the remaining part is filled in by the compiler internally. The Yul `datasize` and `dataoffset` instructions have -been adjusted to return the constant size and bytecode hash rather than the bytecode itself. - -The code below should work as expected: - -```solidity -MyContract a = new MyContract(); -MyContract a = new MyContract{salt: ...}(); -``` - -In addition, the subsequent code should also work, but it must be explicitly tested to ensure its intended -functionality: - -```solidity -bytes memory bytecode = type(MyContract).creationCode; -assembly { - addr := create2(0, add(bytecode, 32), mload(bytecode), salt) -} -``` - -The following code will not function correctly because the compiler is not aware of the bytecode beforehand: - -```solidity -function myFactory(bytes memory bytecode) public { - assembly { - addr := create(0, add(bytecode, 0x20), mload(bytecode)) - } -} -``` - -Unfortunately, it's impossible to differentiate between the above cases during compile-time. As a result, we strongly -recommend including tests for any factory that deploys child contracts using `type(T).creationCode`. - -Since the deploy and runtime code is merged together on zkSync Era, we do not support `type(T).runtimeCode` and it -always produces a compile-time error. - -#### Address derivation - -For zkEVM bytecode, zkSync Era uses a distinct address derivation method compared to Ethereum. The precise formulas can -be found in our SDK, as demonstrated below: - -```typescript -export function create2Address(sender: Address, bytecodeHash: BytesLike, salt: BytesLike, input: BytesLike) { - const prefix = ethers.utils.keccak256(ethers.utils.toUtf8Bytes('zksyncCreate2')); - const inputHash = ethers.utils.keccak256(input); - const addressBytes = ethers.utils - .keccak256(ethers.utils.concat([prefix, ethers.utils.zeroPad(sender, 32), salt, bytecodeHash, inputHash])) - .slice(26); - return ethers.utils.getAddress(addressBytes); -} - -export function createAddress(sender: Address, senderNonce: BigNumberish) { - const prefix = ethers.utils.keccak256(ethers.utils.toUtf8Bytes('zksyncCreate')); - const addressBytes = ethers.utils - .keccak256( - ethers.utils.concat([ - prefix, - ethers.utils.zeroPad(sender, 32), - ethers.utils.zeroPad(ethers.utils.hexlify(senderNonce), 32), - ]) - ) - .slice(26); - - return ethers.utils.getAddress(addressBytes); -} -``` - -Since the bytecode differs from Ethereum as zkSync uses a modified version of the EVM, the address derived from the -bytecode hash will also differ. This means that the same bytecode deployed on Ethereum and zkSync will have different -addresses and the Ethereum address will still be available and unused on zkSync. If and when the zkEVM reaches parity -with the EVM, the address derivation will be updated to match Ethereum and the same bytecode will have the same address -on both chains, deployed bytecodes to different addresses on zkSync could then be deployed to the same the -Ethereum-matching addresses on zkSync. - -### `CALL`, `STATICCALL`, `DELEGATECALL` - -For calls, you specify a memory slice to write the return data to, e.g. `out` and `outsize` arguments for -`call(g, a, v, in, insize, out, outsize)`. In EVM, if `outsize != 0`, the allocated memory will grow to `out + outsize` -(rounded up to the words) regardless of the `returndatasize`. On zkSync Era, `returndatacopy`, similar to -`calldatacopy`, is implemented as a cycle iterating over return data with a few additional checks and triggering a panic -if `out + outsize > returndatasize` to simulate the same behavior as in EVM. - -Thus, unlike EVM where memory growth occurs before the call itself, on zkSync Era, the necessary copying of return data -happens only after the call has ended, leading to a difference in `msize()` and sometimes zkSync Era not panicking where -EVM would panic due to the difference in memory growth. - -```solidity -success := call(gas(), target, 0, in, insize, out, outsize) // grows to 'min(returndatasize(), out + outsize)' -``` - -```solidity -success := call(gas(), target, 0, in, insize, out, 0) // memory untouched -returndatacopy(out, 0, returndatasize()) // grows to 'out + returndatasize()' -``` - -Additionally, there is no native support for passing Ether on zkSync Era, so it is handled by a special system contract -called `MsgValueSimulator`. The simulator receives the callee address and Ether amount, performs all necessary balance -changes, and then calls the callee. - -### `MSTORE`, `MLOAD` - -Unlike EVM, where the memory growth is in words, on zkEVM the memory growth is counted in bytes. For example, if you -write `mstore(100, 0)` the `msize` on zkEVM will be `132`, but on the EVM it will be `160`. Note, that also unlike EVM -which has quadratic growth for memory payments, on zkEVM the fees are charged linearly at a rate of `1` erg per byte. - -The other thing is that our compiler can sometimes optimize unused memory reads/writes. This can lead to different -`msize` compared to Ethereum since fewer bytes have been allocated, leading to cases where EVM panics, but zkEVM will -not due to the difference in memory growth. - -### `CALLDATALOAD`, `CALLDATACOPY` - -If the `offset` for `calldataload(offset)` is greater than `2^32-33` then execution will panic. - -Internally on zkEVM, `calldatacopy(to, offset, len)` there is just a loop with the `calldataload` and `mstore` on each -iteration. That means that the code will panic if `2^32-32 + offset % 32 < offset + len`. - -### `RETURN`, `STOP` - -Constructors return the array of immutable values. If you use `RETURN` or `STOP` in an assembly block in the constructor -on zkSync Era, it will leave the immutable variables uninitialized. - -```solidity -contract Example { - uint immutable x; - - constructor() { - x = 45; - - assembly { - // The statements below are overridden by the zkEVM compiler to return - // the array of immutables. - - // The statement below leaves the variable x uninitialized. - // return(0, 32) - - // The statement below leaves the variable x uninitialized. - // stop() - } - } - - function getData() external pure returns (string memory) { - assembly { - return(0, 32) // works as expected - } - } -} - -``` - -### `TIMESTAMP`, `NUMBER` - -For more information about blocks on zkSync Era, including the differences between `block.timestamp` and `block.number`, -check out the [blocks on zkSync Documentation](../../zk-stack/concepts/blocks.md). - -::: note Changes From the Previous Protocol Version Modifications were performed on how certain block properties were -implemented on zkSync Era. For details on the changes performed visit the -[announcement on GitHub](https://github.com/zkSync-Community-Hub/zkync-developers/discussions/87). ::: - -### `COINBASE` - -Returns the address of the `Bootloader` contract, which is `0x8001` on zkSync Era. - -### `DIFFICULTY`, `PREVRANDAO` - -Returns a constant value of `2500000000000000` on zkSync Era. - -### `BASEFEE` - -This is not a constant on zkSync Era and is instead defined by the fee model. Most of the time it is 0.25 gwei, but -under very high L1 gas prices it may rise. - -### `SELFDESTRUCT` - -Considered harmful and deprecated in [EIP-6049](https://eips.ethereum.org/EIPS/eip-6049). - -Always produces a compile-time error with the zkEVM compiler. - -### `CALLCODE` - -Deprecated in [EIP-2488](https://eips.ethereum.org/EIPS/eip-2488) in favor of `DELEGATECALL`. - -Always produces a compile-time error with the zkEVM compiler. - -### `PC` - -Inaccessible in Yul and Solidity `>=0.7.0`, but accessible in Solidity `0.6`. - -Always produces a compile-time error with the zkEVM compiler. - -### `CODESIZE` - -| Deploy code | Runtime code | -| --------------------------------- | ------------- | -| Size of the constructor arguments | Contract size | - -Yul uses a special instruction `datasize` to distinguish the contract code and constructor arguments, so we substitute -`datasize` with 0 and `codesize` with `calldatasize` in zkSync Era deployment code. This way when Yul calculates the -calldata size as `sub(codesize, datasize)`, the result is the size of the constructor arguments. - -```solidity -contract Example { - uint256 public deployTimeCodeSize; - uint256 public runTimeCodeSize; - - constructor() { - assembly { - deployTimeCodeSize := codesize() // return the size of the constructor arguments - } - } - - function getRunTimeCodeSize() external { - assembly { - runTimeCodeSize := codesize() // works as expected - } - } -} -``` - -### `CODECOPY` - -| Deploy code | Runtime code (old EVM codegen) | Runtime code (new Yul codegen) | -| -------------------------------- | ------------------------------ | ------------------------------ | -| Copies the constructor arguments | Zeroes memory out | Compile-time error | - -```solidity -contract Example { - constructor() { - assembly { - codecopy(0, 0, 32) // behaves as CALLDATACOPY - } - } - - function getRunTimeCodeSegment() external { - assembly { - // Behaves as 'memzero' if the compiler is run with the old (EVM assembly) codegen, - // since it is how solc performs this operation there. On the new (Yul) codegen - // `CALLDATACOPY(dest, calldatasize(), 32)` would be generated by solc instead, and - // `CODECOPY` is safe to prohibit in runtime code. - // Produces a compile-time error on the new codegen, as it is not required anywhere else, - // so it is safe to assume that the user wants to read the contract bytecode which is not - // available on zkEVM. - codecopy(0, 0, 32) - } - } -} -``` - -### `EXTCODECOPY` - -Contract bytecode cannot be accessed on zkEVM architecture. Only its size is accessible with both `CODESIZE` and -`EXTCODESIZE`. - -`EXTCODECOPY` always produces a compile-time error with the zkEVM compiler. - -### `DATASIZE`, `DATAOFFSET`, `DATACOPY` - -Contract deployment is handled by two parts of the zkEVM protocol: the compiler front end and the system contract called -`ContractDeployer`. - -On the compiler front-end the code of the deployed contract is substituted with its hash. The hash is returned by the -`dataoffset` Yul instruction or the `PUSH [$]` EVM legacy assembly instruction. The hash is then passed to the -`datacopy` Yul instruction or the `CODECOPY` EVM legacy instruction, which writes the hash to the correct position of -the calldata of the call to `ContractDeployer`. - -The deployer calldata consists of several elements: - -| Element | Offset | Size | -| --------------------------- | ------ | ---- | -| Deployer method signature | 0 | 4 | -| Salt | 4 | 32 | -| Contract hash | 36 | 32 | -| Constructor calldata offset | 68 | 32 | -| Constructor calldata length | 100 | 32 | -| Constructor calldata | 132 | N | - -The data can be logically split into header (first 132 bytes) and constructor calldata (the rest). - -The header replaces the contract code in the EVM pipeline, whereas the constructor calldata remains unchanged. For this -reason, `datasize` and `PUSH [$]` return the header size (132), and the space for constructor arguments is allocated by -**solc** on top of it. - -Finally, the `CREATE` or `CREATE2` instructions pass 132+N bytes to the `ContractDeployer` contract, which makes all the -necessary changes to the state and returns the contract address or zero if there has been an error. - -If some Ether is passed, the call to the `ContractDeployer` also goes through the `MsgValueSimulator` just like ordinary -calls. - -We do not recommend using `CREATE` for anything other than creating contracts with the `new` operator. However, a lot of -contracts create contracts in assembly blocks instead, so authors must ensure that the behavior is compatible with the -logic described above. - -Yul example: - -```solidity -let _1 := 128 // the deployer calldata offset -let _2 := datasize("Callable_50") // returns the header size (132) -let _3 := add(_1, _2) // the constructor arguments begin offset -let _4 := add(_3, args_size) // the constructor arguments end offset -datacopy(_1, dataoffset("Callable_50"), _2) // dataoffset returns the contract hash, which is written according to the offset in the 1st argument -let address_or_zero := create(0, _1, sub(_4, _1)) // the header and constructor arguments are passed to the ContractDeployer system contract -``` - -EVM legacy assembly example: - -```solidity -010 PUSH #[$] tests/solidity/complex/create/create/callable.sol:Callable // returns the header size (132), equivalent to Yul's datasize -011 DUP1 -012 PUSH [$] tests/solidity/complex/create/create/callable.sol:Callable // returns the contract hash, equivalent to Yul's dataoffset -013 DUP4 -014 CODECOPY // CODECOPY statically detects the special arguments above and behaves like the Yul's datacopy -... -146 CREATE // accepts the same data as in the Yul example above -``` - -### `SETIMMUTABLE`, `LOADIMMUTABLE` - -zkEVM does not provide any access to the contract bytecode, so the behavior of immutable values is simulated with the -system contracts. - -1. The deploy code, also known as constructor, assembles the array of immutables in the auxiliary heap. Each array - element consists of an index and a value. Indexes are allocated sequentially by `zksolc` for each string literal - identifier allocated by `solc`. -2. The constructor returns the array as the return data to the contract deployer. -3. The array is passed to a special system contract called `ImmutableSimulator`, where it is stored in a mapping with - the contract address as the key. -4. In order to access immutables from the runtime code, contracts call the `ImmutableSimulator` to fetch a value using - the address and value index. In the deploy code, immutable values are read from the auxiliary heap, where they are - still available. - -The element of the array of immutable values: - -```solidity -struct Immutable { - uint256 index; - uint256 value; -} -``` - -Yul example: - -```solidity -mstore(128, 1) // write the 1st value to the heap -mstore(160, 2) // write the 2nd value to the heap - -let _2 := mload(64) -let _3 := datasize("X_21_deployed") // returns 0 in the deploy code -codecopy(_2, dataoffset("X_21_deployed"), _3) // no effect, because the length is 0 - -// the 1st argument is ignored -setimmutable(_2, "3", mload(128)) // write the 1st value to the auxiliary heap array at index 0 -setimmutable(_2, "5", mload(160)) // write the 2nd value to the auxiliary heap array at index 32 - -return(_2, _3) // returns the auxiliary heap array instead -``` - -EVM legacy assembly example: - -```solidity -053 PUSH #[$] // returns 0 in the deploy code -054 PUSH [$] -055 PUSH 0 -056 CODECOPY // no effect, because the length is 0 -057 ASSIGNIMMUTABLE 5 // write the 1st value to the auxiliary heap array at index 0 -058 ASSIGNIMMUTABLE 3 // write the 2nd value to the auxiliary heap array at index 32 -059 PUSH #[$] -060 PUSH 0 -061 RETURN // returns the auxiliary heap array instead -``` - -## Nonces - -In Ethereum, each account is associated with a unique identifier known as a nonce. For externally owned accounts (EOAs), -the nonce fulfills three key functions: it prevents replay attacks on the network, ensures transactions are executed in -the intended sequence, and acts as a unique identifier in the formula for deriving addresses. The nonce is incremented -after each transaction is executed. - -In the context of smart contracts, the nonce has a singular purpose: it determines the address of a contract deployed -from another contract. When a new contract is created using the `create` or `create2` functions, the nonce is increased -to signify the deployment of a new contract. Unlike EOAs, which can only increment their nonce by one per transaction, -smart contracts have the ability to increase their nonce multiple times within a single transaction. - -Conversely, zkSync features native account abstraction, allowing accounts to leverage the nonce for both replay attack -protection and address derivation of created contracts. Given that accounts in zkSync can be smart contracts, they may -deploy several contracts in a single transaction. - -In order to maintain the expected and convenient use of a nonce in both transaction validation and contract deployment -contexts, zkSync introduces two different nonces: transaction nonce and deployment nonce. The transaction nonce is used -for the transaction validation, while the deployment nonce is incremented in the event of contract deployment. This way, -accounts may send many transactions by following only one nonce value and the contract may deploy many other contracts -without conflicting with the transaction nonce. - -There are also other minor differences between zkSync and Ethereum nonce management: - -- Newly created contracts begin with a **deployment nonce** value of zero. This contrasts with Ethereum, where, - following the specifications of [EIP-161](https://eips.ethereum.org/EIPS/eip-161), the nonce for newly created - contracts starts at one. -- On zkSync, the deployment nonce is incremented only if the deployment succeeds. On Ethereum nonce on deployment is - updated even in case creation failed. - -## Libraries - -We rely on the **solc** optimizer for library inlining, so a library may only be used without deployment if it has been -inlined by the optimizer. - -The addresses of deployed libraries must be set in the project configuration. These addresses then replace their -placeholders in IRs: `linkersymbol` in Yul and `PUSHLIB` in EVM legacy assembly. - -All linking happens at compile-time. Deploy-time linking is not supported. - -## Precompiles - -Some EVM cryptographic precompiles (notably pairings and RSA) aren't currently available. However, pairing is -prioritized to allow deployment of both Hyperchains and protocols like Aztec/Dark Forest without modifications. - -Ethereum cryptographic primitives like `ecrecover`, `keccak256`, `sha256`, `ecadd` and `ecmul` are supported as -precompiles. No actions are required from your side as all the calls to the precompiles are done by the compilers under -the hood. - -It's important to be aware that the gas costs and behaviors of these precompiles when invoked via delegatecall may -differ from those on Ethereum. - -## Native AA vs EIP 4337 - -The native account abstraction of zkSync and Ethereum's EIP 4337 aim to enhance accounts' flexibility and user -experience, but they differ in critical aspects listed below: - -1. **Implementation Level**: zkSync's account abstraction is integrated at the protocol level; however, EIP 4337 avoids - the implementation at the protocol level. -2. **Account Types**: on zkSync Era, smart contract accounts and paymasters are first-class citizens. Under the hood, - all accounts (even EOAs) behave like smart contract accounts; **all accounts support paymasters**. -3. **Transaction Processing**: EIP 4337 introduces a separate transaction flow for smart contract accounts, which relies - on a separate mempool for user operations, and Bundlers - nodes that bundle user operations and sends them to be - processed by the EntryPoint contract, resulting in two separate transaction flows. In contrast, on zkSync Era there - is a unified mempool for transactions from both Externally Owned Accounts (EOAs) and smart contract accounts. On - zkSync Era, the Operator takes on the role of bundling transactions, irrespective of the account type, and sends them - to the Bootloader (similar to the EntryPoint contract), which results in a single mempool and transaction flow. -4. **Paymasters support**: zkSync Era allows both EOAs and smart contract accounts to benefit from paymasters thanks to - its single transaction flow. On the other hand, EIP 4337 does not support paymasters for EOAs because paymasters are - only implemented in the new transaction flow for smart contract accounts. diff --git a/content/20.build/developer-reference/events.md b/content/20.build/developer-reference/events.md deleted file mode 100644 index c07ce0a7..00000000 --- a/content/20.build/developer-reference/events.md +++ /dev/null @@ -1,74 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Handling Events | zkSync Docs ---- - -# Handling Events - -Events are a mechanism to publish information to listeners outside the blockchain, given that smart contracts themselves -can't read them. - -Blockchains are public by design, and therefore make all information available to the public, and any actions can be -discovered by carefully looking into the transactions. Events are a shortcut for making specific information easily -available for external systems; they let dApps keep track of, and respond to what's happening to a smart contract. They -can also be searched for because they are indexable. Therefore, you should emit an event anytime something occurs in -your smart contract that some system outside the blockchain should be aware of so that the outside system may listen for -such occurrences. Events are included in the transaction logs of the same block containing the original transaction. - -At zkSync, events behave the same way as in Ethereum. - -## Events filtering - -Filtering is used to query indexed data and provide lower-cost data storage when the data is not required to be accessed -on-chain. When filtering, you should load events by block ranges (0-1999, 2000-3999, ...) and index the result on your -end. Otherwise you will get an error that says "block range should be less than or equal to 2000". - -These can be used in conjunction with the -[Provider Events API](https://docs.ethers.io/v5/api/providers/provider/#Provider--event-methods) and with the -[Contract Events API](https://docs.ethers.io/v5/api/contract/contract/#Contract--events). - -## Getting the events - -Here is an example to listen for smart contract events: - -```js -import * as ethers from 'ethers'; -const contractABI = require('./ABI_JSON'); - -const listenEvents = async () => { - const contractAddress = ''; - const provider = new ethers.providers.WebSocketProvider(`wss://sepolia.era.zksync.dev/ws`); - - const contract = new ethers.Contract(contractAddress, contractABI, provider); - - // starts listening to Transfer events on contract - contract.on('Transfer', (event) => { - // optional filter parameters - let options = { - filter: { INDEXED_PARAMETER: VALUE }, // e.g { from: '0x48c6c0923b514db081782271355e5745c49wd60' } - fromBlock: START_BLOCK_NUMBER, // e.g 15943000 - toBlock: END_BLOCK_NUMBER, // e.g 15943100 - data: event, - }; - console.log(JSON.stringify(options, null, 4)); - }); -}; - -listenEvents(); -``` - -- Provider: Your websocket provider through which you will retrieve the events data. Note that you need to use the - websocket endpoint. -- Contract address: The contract address whose events you want to track. -- ABI: The ABI (Application Binary Interface) of the contract in JSON format. -- Event name: The name of the event as defined in the smart contract. In this example we used the "Transfer" event from - an ERC20 contract. -- Indexed parameter : The indexed parameter of the event. -- Block number: The block number range for the events retrieval, it involves the `START_BLOCK_NUMBER` and the - `END_BLOCK_NUMBER`. - -**Note**: zkSync has a 10K log limit per response. This means that if you receive a response with 10k events, it will -most likely contain additional events so it'd be a good idea to adjust the filters to retrieve the events in multiple -batches. diff --git a/content/20.build/developer-reference/fee-model.md b/content/20.build/developer-reference/fee-model.md deleted file mode 100644 index ce1ef096..00000000 --- a/content/20.build/developer-reference/fee-model.md +++ /dev/null @@ -1,158 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Fee Model | zkSync Docs ---- - -# Fee Model - -zkSync Era's fee model is similar to Ethereum’s where `gas` is charged for computational cost, cost of publishing data -on-chain and storage effects. However, zkSync Era includes additional costs for publishing to L1 and for proof -generation. - -::: info More in ZK Stack docs - -You can find more details about the Fee model Contracts -[the concepts section of the ZK Stack documentation](../../zk-stack/concepts/fee-mechanism.md). - -::: - -Because the L1 gas price for publishing data (on L1) is so volatile, the amount of required L2 `gas` is variable. -Therefore, for each block, the zkSync Era sequencer defines the following dynamic parameters: - -- `gasPrice`: the price, in gwei, of a unit of gas. -- `gasPerPubdata`: the amount of `gas` for publishing one byte of data on Ethereum. - -In zkSync Era, unlike in Ethereum where each opcode has a fixed gas price, storage write charges remain dynamic due to -the fluctuation of gas price on L1. Other opcode prices are constant, similar to Ethereum. See the -[zkSync opcode documentation](https://github.com/matter-labs/era-zkevm_opcode_defs/blob/9307543b9ca51bd80d4f5c85d6eb80efd8b19bb2/src/lib.rs#L227) -for an idea of how we calculate them. - -Like Ethereum, the most costly operation is a storage update. Execution of arithmetic operations is relatively cheap, as -it involves computation alone and no storage changes. - -## State diffs vs transaction inputs - -A considerable advantage we have over optimistic and most ZK rollups is that, instead of publishing all transaction data -to L1, zkSync Era only publishes state diffs, thus publishing significantly less data to L1. - -:::info State diff example - -If an oracle updates a price in a contract using the same storage slot 10 times in the same rollup batch, only the final -update is published on Ethereum and is therefore only charged once, making 9 of the 10 updates free. ::: - -Another advantage is the cost-effective contract redeployment. An example is a DEX with a `PairFactory` contract for -different `Pair` pools. The contract bytecode of `Pair` is only published when the first instance is deployed. After -that, subsequent deployments only involve updating one storage slot which sets the contract code hash on the newly -deployed `Pair` address. - -## Design recommendations - -- **Update storage slots as little as possible:** Check to see if your code can avoid unnecessary storage updates. -- **Reuse as many storage slots as possible:** Only the final state diff is published on Ethereum. -- **Reuse the contract code where possible:** - - On Ethereum, avoiding constructor parameters and putting them into constants reduces some of the gas costs upon - contract deployment. - - On zkSync Era the opposite is true: as contract bytecode is only published once, updating the constructor parameters - alone leads to substantial fee savings. - -## Gas estimation for transactions - -Ethereum has a constant of `21000` gas that covers the intrinsic costs of processing a transaction, i.e. checking the -signature and updating the nonce for the account. - -On zkSync Era this varies because we support custom and paymaster accounts. These accounts require a (usually) higher -amount of gas than EOAs. zkSync Era provides functions for estimating the cost of a transaction regardless of the type -of account. - -The transaction fee estimate depends on the entire transaction flow, including validation and execution. The -`eth_estimateGas` function uses binary search to find the smallest gas value under which the transaction succeeds. - -For more information, find out [how to estimate gas for various transaction types](../tutorials/how-to/estimate-gas.md). - -For any Rust developers interested in the zkSync Era implementation for gas estimation, see the -[Rust code in our repo](https://github.com/matter-labs/zksync-era/blob/48fe6e27110c1fe1a438c5375fb256890e8017b1/sdk/zksync-rs/src/operations/execute_contract.rs#L129). - -### Transaction length - -zkSync Era publishes state diffs on-chain. The cost of the transaction, however, may still depend on transaction length -because the sequencer stores long transactions in-memory. - -Long transactions incur additional costs during interactions with an account. zkSync Era works with different types of -accounts and, therefore, the protocol cannot make assumptions about signature length. Furthermore, given that a -signature (and thus its length) is unavailable at the time of fee estimation, we cannot precisely estimate the cost of -such a transaction. To mitigate this, we multiply the recommended cost of the transaction by a small percentage. - -### `DefaultAccount` - -By default, the zkSync Era sequencer provides a transaction structure with the available information during the fee -estimation. - -Because the signature is unavailable prior to the transaction taking place, an invalid 65-byte ECDSA signature is used -instead. The `DefaultAccount` (used by EOAs), during gas fee estimation, executes many operations, including signature -verification, and returns only `bytes4(0)` instead of [magic](../sdks/js/utils.md#magic-value). - -In the case of a custom account with multiple signers, the account may wish to simulate signature validation for all the -provided signers. - -See the -[DefaultAccount code](https://github.com/matter-labs/era-contracts/blob/main/system-contracts/contracts/DefaultAccount.sol) -for more information. - -### Account abstraction considerations - -The `validateTransaction` function for account abstraction, and the `validateAndPayForPaymasterTransaction` function for -paymasters, always attempt to run using the same amount of computation, including storage access, regardless of whether -the transaction is successful or not. - -See the documentation on [account abstraction](../developer-reference/account-abstraction.md) for more detailed -information. - -#### `validateTransaction` - -- `validateTransaction` is considered successful when it does not revert (i.e. it returns `success = true`) and also - returns the magic string. -- For invalid signatures, the function does not revert. It instead returns invalid magic so the function is - unsuccessful. - -#### `eth_estimateGas` - -Because the entire transaction validation and execution flow is simulated in order to get the transaction’s fee, the -user needs to have sufficient funds in their account, otherwise the simulation may exit. This means that, to ensure the -execution progresses, the zkSync Era sequencer adds the necessary balance, temporarily, to the user’s account; -specifically the sequencer increases the account balance by tx.maxFeePerGas \* tx.gasLimit. - -This ensures the `DefaultAccount`’s `payForTransaction` function runs successfully. - -This is different to the Geth implementation which uses `tx.gasprice = 0` to make sure that the user can pay the fee -even though the `tx.origin` in the simulation may not have any balance at all. - -:::warning Due to this, custom accounts may unexpectedly contain more balance than they have on-chain during the -validation step, which may affect their behavior. ::: - -## Refunds - -A gas estimate may be higher than the actual cost of the transaction. This means users usually only spend a portion of -the estimated transaction cost. - -The refund, therefore, returns the unpaid transaction fee portion to the user. - -:::tip - -- Only one transaction is recorded on the block, even if a portion of the original estimate is refunded. -- Users can compare their token balance against the transaction cost on the block explorer to verify they did not - overspend. -- Users may see no notification in their wallet depending on which wallet they use. ::: - -Refunds are calculated by defining a fair value for the amount the user spent on the transaction and subtracting it from -the actual spend. - -## Out-of-gas errors - -Unlike on Geth, it is impossible to track out-of-gas errors on zkSync Era. - -The main reason is that the “actual” execution happens inside the `DefaultAccount` system contract and, due to the -[63/64 rule](https://eips.ethereum.org/EIPS/eip-150), when a high amount of gas is provided, the call to the `execute` -function of the `DefaultAccount` will NOT fail, even if it is out of gas, although the subcall to the `transaction.to` -contract will fail with an out of gas error. diff --git a/content/20.build/developer-reference/l1-l2-interop.md b/content/20.build/developer-reference/l1-l2-interop.md deleted file mode 100644 index e8910e24..00000000 --- a/content/20.build/developer-reference/l1-l2-interop.md +++ /dev/null @@ -1,61 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: L1 / L2 Interoperability | zkSync Docs ---- - -# L1 / L2 interoperability - -## Common use cases - -Many use cases require multi-layer interoperability, such as: - -- The network's censorship resistance. -- Custom bridges. -- Multi-layer governing smart contracts. -- Multi-layer transfers. - -## L1 to L2 communication - -L1 to L2 communication is governed by the -[`IZkSync.sol`](https://github.com/matter-labs/era-contracts/blob/main/l1-contracts/contracts/zksync/interfaces/IZkSync.sol) -inherited interfaces. - -:::tip - -- If you prefer to learn-by-doing, the - [cross chain governance tutorial](../tutorials/smart-contract-development/cross-chain-tutorial.md) is a practical - example of layer interoperability. ::: - -### Gas estimation - -The SDK processes gas estimation for transactions implicitly. However, it is also possible to implement the gas -estimation processes explicitly. - -:::tip L1 to L2 gas estimation for transactions - -- Basic costs are measured in the amount of gas, and so the final cost depends on the gas price that the transaction - assigns. -- The transaction process requires the current L1 gas price, transaction base cost, and transaction gas limit which - defines the maximum amount of gas a transaction can consume. ::: - -- Find out [how to estimate gas](../tutorials/how-to/estimate-gas.md) for different scenarios. -- Find out [how to send a transaction from L1 to L2](../../build/tutorials/how-to/send-transaction-l1-l2.md) with zkSync - Era. - -## L2 to L1 - -L2 to L1 communication is based on transferring the data as a message, and not on L1 transaction execution. - -- Find out [how to send a message from L2 to L1](../tutorials/how-to/send-message-l2-l1.md) with zkSync Era. - -## Priority queue - -1. All transaction types are supported by the priority queue. - -2. The priority queue must be fully permissionless to prevent malicious activity. For example, malicious users might - send multiple transactions which push up the block gas limit to unworkable levels. To mitigate against this, - submitting transactions to the priority queue is no longer free and users must pay a fee to the operator. To obtain - the cost for sending an L2 to L1 message, please refer to - [step 5 of how to send an L1 to L2 transaction](../../build/tutorials/how-to/send-transaction-l1-l2.md#step-by-step). diff --git a/content/20.build/developer-reference/rollups.md b/content/20.build/developer-reference/rollups.md deleted file mode 100644 index 24c97e0c..00000000 --- a/content/20.build/developer-reference/rollups.md +++ /dev/null @@ -1,70 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Intro to Rollups | zkSync Docs ---- - -# Intro to Rollups - -## Introduction - -To better understand rollups we need to dive briefly into Ethereum and Layer 2 solutions. - -The Ethereum network is frequently congested, which results in slow transactions and increased gas prices. While this -has remained so for a long time, an improved solution is needed: one that will not put limits on the throughput, but -instead, achieve a high transaction rate without having to trade off security. That is where Layer 2 solutions shine. - -Layer 2 solutions are designed as an extension to Ethereum, and offer various solutions poised to be the critical -scalability component to the inherent network congestion on Ethereum. Covering all Layer 2 solutions is beyond the scope -of this doc. We will go through a brief explainer on rollups in this section. - -## What are rollups? - -Rollups are a recent development intended to increase the scalability of Ethereum by performing calculations off-chain, -rolling many transactions up into a single batch, and sending it to the main Ethereum chain in a single action. Instead -of submitting each transaction separately, rollup operators submit a summary of the required changes to represent all -transactions in a batch. - -To be able to work on a rollup, funds need to be locked on a smart contract on the Layer 1 blockchain. This allows -transactions to be processed without the overhead of all the data associated with performing a transaction on the main -chain. **Rollups significantly decrease associated transaction processing times and gas fees.** - -## Optimistic vs ZK rollups - -Currently, there are 2 types of rollups used to scale Ethereum. - -1. ZK Rollups (Zero-Knowledge Rollups) - eg: zkSync, Loopring, Starknet, Scroll etc -2. Optimistic Rollups - eg: Optimism, Arbitrum etc - -The main difference between ZK and Optimistic rollups is in the way this batch of transactions becomes final. - -### What are ZK rollups? - -In ZK rollups ('ZK' standing for zero-knowledge) the batch of transactions is verified for correctness on the Ethereum -network. After the verification passes, the batch of transactions is considered final like any other Ethereum -transaction. This is achieved through the power of cryptographic validity proofs (commonly called -zero-knowledge proofs). With any batch of off-chain transactions, the ZK rollup operator generates a proof of validity -for this batch. Once the proof is generated, it is submitted to Ethereum to make the roll-up batch final. In zkSync, -this is done via a **SNARK**, succinct non-interactive argument of knowledge. - -### What are Optimistic rollups? - -Optimistic rollups, on the other hand, have no mechanism to prove the validity of the off-chain transactions. Instead, -they are considered “optimistic” because they assume off-chain transactions are valid unless proven otherwise. Hence, -they rely on fraud proof systems, a challenge to the submitted state to Ethereum. If such a challenge is -submitted, the Optimistic rollup operator needs to show that the state and transactions in questions are actually valid. -This is a cumbersome process, and requires watchers to make sure that the Optimistic rollup operator is honest at all -times. - -## L1 and L2: what's the difference? - -The term **Layer 1** (or **L1**) is used to refer to the underlying primary chain, such as the Ethereum network or -Bitcoin. Layer 1 blockchains determine protocol rules and transaction finality, and perform the base-level functions of -applications built upon them. - -The term **Layer 2** (or **L2**) is used to describe an overlaying application or network that operates on top of the -Layer 1 chain. These are most often built to provide further scalability solutions by taking on a portion of -transaction-based tasks to lighten the impact on the layer 1 chain, quickening transaction times and lowering gas fees. - -**zkSync Era is an L2, where L1 is the main Ethereum blockchain.** diff --git a/content/20.build/developer-reference/system-contracts.md b/content/20.build/developer-reference/system-contracts.md deleted file mode 100644 index a93be96e..00000000 --- a/content/20.build/developer-reference/system-contracts.md +++ /dev/null @@ -1,192 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: System Contracts | zkSync Docs ---- - -# System Contracts - -To keep the zero-knowledge circuits as simple as possible and enable simple extensions, a large chunk of the logic of -zkSync was moved to the so-called "system contracts" – a set of contracts that have special privileges and serve special -purposes, e.g. deployment of contracts, making sure that the user pays only once for publishing contracts' calldata, -etc. - -You can find the code of the system contracts in -[the following repository in GitHub](https://github.com/matter-labs/era-contracts). - -## L1 Smart Contracts - -::: info More in ZK Stack docs - -You can find more details about the L1 Smart Contracts in -[the components section of the ZK Stack documentation](../../zk-stack/components/smart-contracts/smart-contracts.md). - -::: - -### Diamond - -Technically, this L1 smart contract acts as a connector between Ethereum (L1) and zkSync (L2). This contract checks the -validity proof and data availability, handles L2 <-> L1 communication, finalizes L2 state transition, and more. - -There are also important contracts deployed on the L2 that can also execute logic that we refer to as -[System Contracts](#l2-system-contracts). Using L2 <-> L1 communication can affect both the L1 and the L2. - -### DiamondProxy - -This contract uses the [EIP-2535](https://eips.ethereum.org/EIPS/eip-2535) diamond proxy pattern. It is an in-house -implementation that is inspired by the [mudgen reference implementation](https://github.com/mudgen/Diamond). It has no -external functions, only the fallback that delegates a call to one of the facets (target/implementation contract). - -So even an upgrade system is a separate facet that can be replaced. - -One of the differences from the reference implementation is the ability to freeze access to the facet. - -Each of the facets has an associated parameter that indicates if it is possible to freeze access to the facet. - -Privileged actors can freeze the **diamond** (not a specific facet!) and all facets with the marker `isFreezable` should -be inaccessible until the governor unfreezes the diamond. - -::: tip System contract addresses You can find the L1 system contract addresses in the -[useful addresses page](../quick-start/useful-address.md). ::: - -### DiamondInit - -It is a one-function contract that implements the logic of initializing a diamond proxy. It is called only once on the -diamond constructor and is not saved in the diamond as a facet. - -Implementation detail - function returns a magic value just like it is designed in -[EIP-1271](https://eips.ethereum.org/EIPS/eip-1271), but the magic value is 32 bytes in size. - -### GettersFacet - -Separate facet, whose only function is providing `view` and `pure` methods. It also implements -[diamond loupe](https://eips.ethereum.org/EIPS/eip-2535#diamond-loupe) which makes managing facets easier. - -### MailboxFacet - -The facet that handles L2 <-> L1 communication, an overview for which can be found in the -[L1 / L2 Interoperability guide](./l1-l2-interop.md). - -The Mailbox only cares about transferring information from L2 to L1 and the other way but does not hold or transfer any -assets (ETH, ERC20 tokens, or NFTs). - -L1 -> L2 communication is implemented as requesting an L2 transaction on L1 and executing it on L2. This means a user -can call the function on the L1 contract to save the data about the transaction in some queue. Later on, a validator can -process such transactions on L2 and mark them as processed on the L1 priority queue. - -Currently, it is used only for sending information from L1 to L2 or implementing a multi-layer protocol, but it is -planned to use a priority queue for the censor-resistance mechanism. Relevant functions for L1 -> L2 communication: -`requestL2Transaction`/`l2TransactionBaseCost`/`serializeL2Transaction`. - -**NOTE**: For each executed transaction L1 -> L2, the system program necessarily sends an L2 -> L1 log. - -The semantics of such L2 -> L1 log are always: - -- sender = BOOTLOADER_ADDRESS. -- key = hash(L1ToL2Transaction). -- value = status of the processing transaction (1 - success & 0 for fail). -- isService = true (just a conventional value). -- l2ShardId = 0 (means that L1 -> L2 transaction was processed in a rollup shard, other shards are not available yet - anyway). -- txNumberInBlock = number of transactions in the block. - -L2 -> L1 communication, in contrast to L1 -> L2 communication, is based only on transferring the information, and not on -the transaction execution on L1. - -From the L2 side, there is a special zkEVM opcode that saves `l2ToL1Log` in the L2 block. A validator will send all -`l2ToL1Logs` when sending an L2 block to the L1 (see `ExecutorFacet`). Later on, users will be able to both read their -`l2ToL1logs` on L1 and _prove_ that they sent it. - -From the L1 side, for each L2 block, a Merkle root with such logs in leaves is calculated. Thus, a user can provide -Merkle proof for each `l2ToL1Logs`. - -_NOTE_: The `l2ToL1Log` structure consists of fixed-size fields! Because of this, it is inconvenient to send a lot of -data from L2 and to prove that they were sent on L1 using only `l2ToL1log`. To send a variable-length message we use -this trick: - -- One of the system contracts accepts an arbitrary-length message and sends a fixed-length message with parameters - `senderAddress == this`, `marker == true`, `key == msg.sender`, `value == keccak256(message)`. -- The contract on L1 accepts all sent messages and if the message came from this system contract it requires that the - preimage of `value` be provided. - -### ExecutorFacet - -A contract that accepts L2 blocks, enforces data availability and checks the validity of zk-proofs. - -The state transition is divided into three stages: - -- `commitBlocks` - check L2 block timestamp, process the L2 logs, save data for a block, and prepare data for zk-proof. -- `proveBlocks` - validate zk-proof. -- `executeBlocks` - finalize the state, marking L1 -> L2 communication processing, and saving Merkle tree with L2 logs. - -When a block is committed, we process L2 -> L1 logs. Here are the invariants that are expected there: - -- The only one L2 -> L1 log from the `L2_SYSTEM_CONTEXT_ADDRESS`, with the `key == l2BlockTimestamp` and - `value == l2BlockHash`. -- Several (or none) logs from the `L2_KNOWN_CODE_STORAGE_ADDRESS` with the `key == bytecodeHash`, where bytecode is - marked as a known factory dependency. -- Several (or none) logs from the `L2_BOOTLOADER_ADDRESS` with the `key == canonicalTxHash` where `canonicalTxHash` is a - hash of processed L1 -> L2 transaction. -- Several (of none) logs from the `L2_TO_L1_MESSENGER` with the `key == hashedMessage` where `hashedMessage` is a hash - of an arbitrary-length message that is sent from L2. -- Several (or none) logs from other addresses with arbitrary parameters. - -## L2 System Contracts - -::: info More in ZK Stack docs - -You can find more details about the System Contracts in -[the components section of the ZK Stack documentation](../../zk-stack/components/smart-contracts/system-contracts.md). - -::: - -The addresses and the interfaces of the L2 system contracts can be found -[here](https://github.com/matter-labs/era-contracts/blob/main/system-contracts/contracts/Constants.sol). - -This section will describe the semantic meaning of some of the most popular system contracts. - -### ContractDeployer - -[Interface](https://github.com/matter-labs/era-contracts/blob/main/system-contracts/contracts/interfaces/IContractDeployer.sol) - -This contract is used to deploy new smart contracts. Its job is to make sure that the bytecode for each deployed -contract is known. This contract also defines the derivation address. Whenever a contract is deployed, it emits the -`ContractDeployed` event. - -### L1Messenger - -[Interface](https://github.com/matter-labs/era-contracts/blob/main/system-contracts/contracts/interfaces/IL1Messenger.sol) - -This contract is used to send messages from zkSync to Ethereum. For each message sent, the `L1MessageSent` event is -emitted. - -### NonceHolder - -[Interface](https://github.com/matter-labs/era-contracts/blob/main/system-contracts/contracts/interfaces/INonceHolder.sol) - -This contract stores account nonces. The account nonces are stored in a single place for efficiency -([the tx nonce and the deployment nonce](./contract-deployment.md#differences-in-create-behaviour) are stored in a -single place) and also for the ease of the operator. - -### Bootloader - -For greater extensibility and to lower overhead, some parts of the protocol (e.g. account abstraction rules) have moved -to an ephemeral contract called a _bootloader_. We call it ephemeral since it is never deployed and cannot be called. It -does, however, have a formal -[address](https://github.com/matter-labs/era-contracts/blob/6250292a98179cd442516f130540d6f862c06a16/system-contracts/contracts/Constants.sol#L35) -that is used by `msg.sender` when calling other contracts. - -#### Protected access to some of the system contracts - -Some of the system contracts have an impact on the account that may not be expected on Ethereum. For instance, on -Ethereum the only way an EOA could increase its nonce is by sending a transaction. Also, sending a transaction could -only increase nonce by 1 at a time. On zkSync nonces are implemented via the [NonceHolder](#nonceholder) system contract -and, if naively implemented, the users could be allowed to increment their nonces by calling this contract. That's why -the calls to most of the non-view methods of the nonce holder were restricted to be called only with a special -`isSystem` flag, so that interactions with important system contracts could be consciously managed by the developer of -the account. - -The same applies to the [ContractDeployer](#contractdeployer) system contract. This means that, for instance, you would -need to explicitly allow your users to deploy contracts, as it is done in the DefaultAccount's -[implementation](https://github.com/matter-labs/era-contracts/blob/6250292a98179cd442516f130540d6f862c06a16/system-contracts/contracts/DefaultAccount.sol#L125). diff --git a/content/20.build/developer-reference/zkSync.md b/content/20.build/developer-reference/zkSync.md deleted file mode 100644 index 79072b51..00000000 --- a/content/20.build/developer-reference/zkSync.md +++ /dev/null @@ -1,136 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: zkSync Era Overview | zkSync Docs ---- - -# zkSync Era Overview - -## Prerequisites - -If you are unfamiliar with rollups, you should cover the [rollups basics](./rollups.md) and read about ZK rollups and -Optimistic rollups, before learning about zkSync. - -## Introduction - -**zkSync Era** is a [ZK rollup](./rollups.md#what-are-zk-rollups), a trustless protocol that uses cryptographic validity -proofs to provide scalable and low-cost transactions on Ethereum. In zkSync Era, computation is performed off-chain and -most data is stored off-chain as well. As all transactions are proven on the Ethereum mainchain, users enjoy the same -security level as in Ethereum. - -zkSync Era is made to look and feel like Ethereum, but with lower fees. Just like on Ethereum, smart contracts are -written in Solidity/Vyper and can be called using the same clients as the other EVM-compatible chains. - -You don't need to register a separate private key before usage; zkSync supports existing Ethereum wallets out of the -box. At this time, zkSync is solely run and operated by the zkSync team's servers and is therefore centralized. However, -this will be transitioned to a decentralized system shortly. - -:::tip Gas fees Layer 2 gas fees depend on the current Ethereum gas fees for publishing and verification. ::: - -## zkSync Era overview - -The general rollup workflow is as follows: - -- Users can receive, deposit, and transfer assets to each other. -- Users can withdraw assets under their control to an L1 address. - -Rollup operation requires the assistance of an operator, who rolls transactions together, computes a zero-knowledge -proof of the correct state transition, and affects the state transition by interacting with the rollup contract. To -understand the design, we need to look into how zkSync rollup transactions work. - -zkSync operations are divided into rollup transactions (initiated inside rollup by a rollup account) and priority -operations (initiated on the mainchain by an Ethereum account). - -The zkSync rollup operation lifecycles are as follows: - -- A user creates a transaction or a priority operation. -- After processing this request, the operator creates a rollup operation and adds it to the block. -- Once the block is complete, the operator submits it to the zkSync smart contract as a block commitment. Part of the - logic of some rollup operations is checked by the smart contract. -- The proof for the block is submitted to the zkSync smart contract as block verification. If the verification succeeds, - the new state is considered final. - -Furthermore, on zkSync, each L2 block will progress through the following four stages until it is final. - -- `Pending`: The transaction was received by the operator, but it has not been processed yet. -- `Processed`: The transaction is processed by the operator and is confirmed to be included in the next block. -- `Committed`: This indicates that the transaction data of this block has been posted on Ethereum. It does not prove - that it has been executed in a valid way, but it ensures the availability of the block data. -- `Finalized`: This indicates that the SNARK validity proof for the transaction has been submitted and verified by the - smart contract. After this step, the transaction is considered to be final. - -The typical time for a transaction to go from `Processed` to `Finalized` is a couple of hours at the current stage. - -Please note that for developer convenience, we usually treat the `Processed` and `Committed` states as a single stage -called `Committed` since they have no difference from the UX/DevEx standpoints. - -### The State of zkSync - -The current version of zkSync Era solves the needs of most applications on Ethereum, and with more features planned for -release soon, zkSync Era will provide developers with a design space to experiment with applications not possible on -Ethereum today. With this release, we are supporting the following features: - -- Native support of ECDSA signatures: Unlike the first version of zkSync and other ZK rollups, no special operation is - required to register the user’s private key. Any account can be managed in L2 with the same private key that is used - for L1. -- Solidity 0.8.x support: Deploy your existing codebase with little to no changes required. -- With small exceptions, our Web3 API is fully compatible with Ethereum. This allows seamless integration with existing - indexers, explorers, etc. -- Support for Ethereum cryptographic primitives: zkSync natively supports `keccak256`, `sha256`, and `ecrecover` via - precompiles. -- Hardhat plugin: Enables easy testing and development of smart contracts on zkSync. -- L1 → L2 smart contract messaging: Allows developers to pass data from Ethereum to smart contracts on zkSync, providing - the required information to run various smart contracts. -- Native account abstraction: zkSync Era implements - [account abstraction natively](../developer-reference/account-abstraction.md), which brings multiple UX improvements - for all accounts. - -Some features that will be released in future upgrades: - -- zkPorter: One of the largest and most important features, zkPorter will allow users to choose between a zkRollup - account featuring the highest security and a 20x fee reduction compared to Ethereum, or a zkPorter account featuring - stable transaction fees of just a few cents in a different security model (much higher than that of a sidechain). Both - zkPorter and zkRollup accounts will be able to interact seamlessly together under the hood. - -## Highlights of zkSync Era - -- Mainnet-like security with zero reliance on 3rd parties. -- Permissionless EVM-compatible smart contracts. -- Standard Web3 API. -- Preserving key EVM features, such as smart contract composability. -- Introducing new features, such as account abstraction. - -## zkSync in comparison - -zkSync -[stands out remarkably](https://blog.matter-labs.io/evaluating-ethereum-l2-scaling-solutions-a-comparison-framework-b6b2f410f955) -in security and usability among existing L2 scaling solutions. Thanks to the combination of cutting-edge cryptography -and on-chain data availability, ZK rollups (the core network of zkSync) are the only L2 scaling solution that doesn't -require any operational activity to keep the funds safe. For example, users can go offline and still be able to withdraw -their assets safely when they come back, even if the ZK rollup validators are no longer around. For a comprehensive -distinction between zkSync Era and Ethereum, read this [guide](../developer-reference/differences-with-ethereum.md). - -## zkSync Era user experience - -- Transactions have instant confirmations and fast finality on L1. -- Transaction fees are extremely low. -- Transaction fees can be conveniently paid with ERC20 tokens (e.g. USDC) thanks to - [native account abstraction and paymasters](../../build/developer-reference/account-abstraction.md). -- Support for existing Ethereum-based wallets like Metamask, TrustWallet or Zerion. - -## zkSync Era developer experience - -- Smart contracts can be written in Solidity or Vyper. -- Most contracts work out of the box so migrating projects is seamless. -- Web3 API compatibility enables support of most developer tools. -- Use existing frameworks like [Hardhat](../tooling/hardhat/getting-started.md) and - [Foundry (alpha)](https://github.com/matter-labs/foundry-zksync). -- Compile smart contracts with custom compilers: - [zksolc and zkvyper](../../zk-stack/components/compiler/toolchain/overview.md). -- Different [tools for testing locally](../test-and-debug/getting-started.md). - -## How to get started? - -- Begin by building a dApp in the [quickstart section](../quick-start/hello-world.md). -- See how to [connect your wallet and interact with zkSync Era](../quick-start/add-zksync-to-metamask.md). diff --git a/content/20.build/quick-start/add-zksync-to-metamask.md b/content/20.build/quick-start/add-zksync-to-metamask.md deleted file mode 100644 index ebe26d88..00000000 --- a/content/20.build/quick-start/add-zksync-to-metamask.md +++ /dev/null @@ -1,40 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Add zkSync to MetaMask | zkSync Docs ---- - -# Add zkSync to MetaMask - -To add zkSync as a custom network in MetaMask, follow these steps: - -1. Click on the MetaMask -2. Click on the Network on the left hand side -3. Click “Add Network" -4. Scroll down the "Networks" menu and click on "Add a Network Manually". - -Fill in the following details for the zkSync network: - -## Mainnet network info - -- Network Name: `zkSync Era Mainnet` -- RPC URL: `https://mainnet.era.zksync.io` -- Chain ID: `324` -- Currency Symbol: `ETH` -- Block Explorer URL: `https://explorer.zksync.io/` -- WebSocket URL: `wss://mainnet.era.zksync.io/ws` - -## Sepolia testnet network info - -- Network Name: `zkSync Era Sepolia Testnet` -- RPC URL: `https://sepolia.era.zksync.dev` -- Chain ID: `300` -- Currency Symbol: `ETH` -- Block Explorer URL: `https://sepolia.explorer.zksync.io/` -- WebSocket URL: `wss://sepolia.era.zksync.dev/ws` - -Click on "Save" to add the zkSync network to MetaMask. - -Now you should see the zkSync network listed in the Networks section of MetaMask. You can switch to the zkSync network -to interact with zkSync applications and contracts. diff --git a/content/20.build/quick-start/best-practices.md b/content/20.build/quick-start/best-practices.md deleted file mode 100644 index a43916de..00000000 --- a/content/20.build/quick-start/best-practices.md +++ /dev/null @@ -1,133 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Security and Best Practices | zkSync Docs ---- - -# Security and best practices - -Before diving into development on zkSync Era, it's crucial to consider the following recommendations. These best -practices will help you optimize your code, ensure security, and align with the unique characteristics of zkSync Era. - -## Use `call` over `.send` or `.transfer` - -Avoid using `payable(addr).send(x)`/`payable(addr).transfer(x)` because the 2300 gas stipend may not be enough for such -calls, especially if it involves state changes that require a large amount of L2 gas for data. Instead, we recommend -using `call`. - -Instead of: - -```solidity -payable(addr).send(x) // or -payable(addr).transfer(x) -``` - -Use: - -```solidity -(bool s, ) = addr.call{value: x}(""); -require(s); -``` - -This converts the `send`/`transfer` functionality to `call` and -[avoids potential security risks outlined here.](https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/). - -::: warning Be aware of reentrancy While `.call` offers more flexibility compared to `.send` or `.transfer`, developers -should be aware that `.call` does not provide the same level of reentrancy protection as `.transfer`/`.send`. It's -crucial to adhere to best practices like the checks-effects-interactions pattern and/or use reentrancy guard protection -to secure your contracts against reentrancy attacks. It can help ensure the robustness and security of your smart -contracts on the zkEVM, even under unexpected conditions. ::: - -## Use the proxy pattern at the early stage of the protocol - -zkSync Era is based on the zk-friendly VM. Thus, we offer -[a dedicated compiler](../../zk-stack/components/compiler/toolchain/overview.md) responsible for transforming -conventional Solidity and Vyper code into zkEVM bytecode. - -While we have extensive test coverage to ensure EVM compatibility, issues may still appear. We will implement the -patches for these in a timely manner. - -To integrate a compiler bug fix, you need to recompile and upgrade your smart contract. We recommend using the Proxy -pattern for a few months after your first deployment on zkSync Era, even if you plan to migrate to an immutable contract -in the future. - -:::tip zkSync Upgradeable plugin - -- The [hardhat-zksync-upgradeable plugin](../tooling/hardhat/hardhat-zksync-upgradable.md) is now available to help you - create proxies. ::: - -## Do not rely on EVM gas logic - -zkSync Era has a distinctive gas logic compared to Ethereum. There are two main drivers: - -- We have a state-diff-based data availability, which means that the price for the execution depends on the L1 gas - price. -- zkEVM has a different set of computational trade-offs compared to the standard computational model. In practice, this - means that the price for opcodes is different to Ethereum. Also, zkEVM contains a different set of opcodes under the - hood and so the “gas” metric of the same set of operations may be different on zkSync Era and on Ethereum. - -:::warning Our fee model is being constantly improved and so it is highly recommended **NOT** to hardcode any constants -since the fee model changes in the future might be breaking for this constant. ::: - -## `gasPerPubdataByte` should be taken into account in development - -Due to the state diff-based fee model of zkSync Era, every transaction includes a constant called `gasPerPubdataByte`. - -Presently, the operator has control over this value. However, in EIP712 transactions, users also sign an upper bound on -this value, but the operator is free to choose any value up to that upper bound. Note, that even if the value is chosen -by the protocol, it still fluctuates based on the L1 gas price. Therefore, relying solely on gas is inadequate. - -A notable example is a Gnosis Safe’s `execTransaction` method: - -```solidity -// We require some gas to emit the events (at least 2500) after the execution and some to perform code until the execution (500) -// We also include the 1/64 in the check that is not send along with a call to counteract potential shortcomings because of EIP-150 -require(gasleft() >= ((safeTxGas * 64) / 63).max(safeTxGas + 2500) + 500, "GS010"); -// Use scope here to limit variable lifetime and prevent `stack too deep` errors -{ - uint256 gasUsed = gasleft(); - // If the gasPrice is 0 we assume that nearly all available gas can be used (it is always more than safeTxGas) - // We only subtract 2500 (compared to the 3000 before) to ensure that the amount passed is still higher than safeTxGas - success = execute(to, value, data, operation, gasPrice == 0 ? (gasleft() - 2500) : safeTxGas); - gasUsed = gasUsed.sub(gasleft()); - - // ... -} -``` - -While the contract does enforce the correct `gasleft()`, it does not enforce the correct `gasPerPubdata`, since there -was no such parameter on Ethereum. This means that a malicious user could call this wallet when the `gasPerPubdata` is -high and make the transaction fail, hence making it spend artificially more gas than required. - -This is the case for all relayer-like logic ported directly from Ethereum and so if you see your code relying on logic -like “the user should provide at X gas”, then the `gasPerPubdata` should be also taken into account on zkSync Era. - -For now, zkSync Era operators use honest values for ETH L1 price and `gasPerPubdata`, so it should not be an issue if -enough margin is added to the estimated gas. In order to prepare for the future decentralization of zkSync Era, it is -imperative that you update your contract. - -## Use native account abstraction over `ecrecover` for validation - -Use zkSync Era's native account abstraction support for signature validation instead of this function. - -We recommend not relying on the fact that an account has an ECDSA private key, since the account may be governed by -multisig and use another signature scheme. - -Read more about [zkSync Era Account Abstraction support](../../build/developer-reference/account-abstraction.md). - -## Use local testing environment - -For optimal development and testing of your contracts, it is highly recommended to perform local testing before -deploying them to the mainnet. Local testing allows you to test your contracts in a controlled environment, providing -benefits such as reduced network latency and cost. - -We provide [two different testing environments](../../build/test-and-debug/getting-started.md) designed for local -testing purposes. These tools allow you to simulate the zkSync network locally, enabling you to validate your contracts -effectively. - -By incorporating local testing into your development workflow, you can effectively verify the behavior and functionality -of your contracts in a controlled environment, ensuring a smooth deployment process to the mainnet. - -For detailed instructions on configuring the local testing environment and performing tests using Mocha and Chai, refer -to the dedicated [Testing](../../build/test-and-debug/getting-started.md) page. diff --git a/content/20.build/quick-start/hello-world.md b/content/20.build/quick-start/hello-world.md deleted file mode 100644 index 8fdb39c2..00000000 --- a/content/20.build/quick-start/hello-world.md +++ /dev/null @@ -1,329 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Hello world | zkSync Docs ---- - -# Quickstart: hello world! hello zkSync - -
-

⏱️ Time to complete: <5 minutes

-
- -![zksync hello world tutorial](../../assets/images/quickstart-tutorial-cli.gif) - -This guide shows you how to deploy and interact with a smart contract on zkSync in less than 5 minutes. It will help you -get familiar with the zkSync development toolbox. - -This is what we're going to do: - -- Fund your wallet with zkSync testnet ETH. -- Use [zksync-cli](../tooling/zksync-cli/getting-started.md) to scaffold a new project. -- Build a smart contract that stores a greeting message and deploy it to zkSync Era testnet. -- Run a script to retrieve and update the greeting message using [zksync-ethers](../sdks/js/getting-started.md). - -## Prerequisites - -- Make sure your machine satisfies the - [system requirements](https://github.com/matter-labs/era-compiler-solidity/tree/main#system-requirements). -- Download and install [Node.js](https://nodejs.org/en/download). -- Use the `yarn` or `npm` package manager. We recommend using `yarn`. To install `yarn`, follow the - [Yarn installation guide](https://yarnpkg.com/getting-started/install). -- Learn how to - [get your private key from your Metamask wallet](https://support.metamask.io/hc/en-us/articles/360015289632-How-to-export-an-account-s-private-key) - as we'll use it to deploy a contract. - -## Fund your wallet - -You can get testnet ETH directly into zkSync testnet using the -[following faucet provided by LearnWeb3](https://learnweb3.io/faucets/zksync_sepolia/). - -Another option is to [get SepoliaETH from any of the following faucets](../tooling/network-faucets.md) and bridge it to -zkSync Sepolia testnet using the [zkSync bridge](https://portal.zksync.io/bridge/?network=sepolia). - -You can check the balance of your account in the [zkSync Sepolia explorer](https://sepolia.explorer.zksync.io/). - -## Create the project - -::: info Project available in Atlas IDE This entire tutorial can be run in under a minute using Atlas. Atlas is a smart -contract IDE that lets you write, deploy, and interact with contracts from your browser. - -[Open this project in Atlas](https://app.atlaszk.com/projects?template=https://github.com/matter-labs/zksync-hardhat-template&open=Greeter.sol&chainId=300). -::: - -Run the following command in your terminal to create a new project using zkSync CLI. - -```sh -npx zksync-cli create hello-zksync -``` - -It will give you options for different types of projects but for this tutorial choose the the following: - -```bash -? What type of project do you want to create? Contracts -? Ethereum framework: Ethers v6 -? Template: Hardhat + Solidity -? Private key of the wallet responsible for deploying contracts (optional) *************************************************** -? Package manager: yarn -``` - -::: info - -The private key of your wallet will be included in the `.env` file of the project and won't be pushed to GitHub. - -::: - -The project structure is pretty straight forward: - -- `hardhat.config.ts` contains the general configuration for Hardhat and the zkSync plugins, which are already imported - and setup. -- `/contracts` contains smart contracts. `zksync-cli` provides common examples like an ERC20, an NFT, and the Greeter - contract that we'll use later on. -- `/deploy` contains the deployment scripts. - -For this tutorial we'll focus on the `/contracts/Greeter.sol` contract: - -```solidity -//SPDX-License-Identifier: Unlicense -pragma solidity ^0.8.0; - -contract Greeter { - string private greeting; - - constructor(string memory _greeting) { - greeting = _greeting; - } - - function greet() public view returns (string memory) { - return greeting; - } - - function setGreeting(string memory _greeting) public { - greeting = _greeting; - } -} -``` - -As you can see, it a simple Solidity contract with two methods to read a message, `greet()`, and modify it, -`setGreeting()`. - -::: tip Takeaway - -zkSync is EVM compatible. You can write smart contracts with Solidity or Vyper and use existing popular libraries like -OpenZeppelin. - -::: - -## Compile the contract - -Smart contracts deployed to zkSync must be compiled using our custom compilers: - -- `zksolc` for Solidity contracts. -- `zkvyper` for Vyper contracts. - -As this is a Solidity project, it already has the `hardhat-zksync-solc` plugin installed and configured so there's -nothing you need to setup. To compile the contracts in the project, run the following command: - -::: code-tabs - -@tab:active yarn - -```bash -yarn compile -``` - -@tab npm - -```bash -npm run compile -``` - -::: - -You'll get the following output: - -```sh -Compiling contracts for zkSync Era with zksolc v1.3.21 and solc v0.8.17 -Compiling 46 Solidity files -Successfully compiled 46 Solidity files -✨ Done in 21.55s. -``` - -The compiled artifacts will be located in the `/artifacts-zk` folder. These artifacts are similar to the ones generated -by the Solidity compiler. For example, the ABI of the Greeter contract will be located in -`/artifacts-zk/contracts/Greeter.sol/Greeter.json`. - -::: tip Takeaway - -Smart contracts deployed to zkSync must be compiled using `zksolc` or `zkvyper` as they generate a custom bytecode -compatible with zkSync's ZKEVM. - -::: - -The configuration for the `zksolc` compiler is located in the `zksolc` section of the `hardhat.config.ts` file. You can -find more info about the compiler settings in the -[hardhat-zksync-solc plugin](../tooling/hardhat/hardhat-zksync-solc.md) and the -[compiler section](../../zk-stack/components/compiler/specification/overview.md) of the ZK Stack documentation. - -## Deploy and verify - -The project also contains a script to deploy and verify the contract in `/deploy/deploy.ts`. Under the hood, this script -uses `hardhat-zksync-deploy` and `hardhat-zksync-verify` for deployment and contract verification. - -```ts -import { deployContract } from './utils'; - -// An example of a basic deploy script -// It will deploy a Greeter contract to selected network -// as well as verify it on Block Explorer if possible for the network -export default async function () { - const contractArtifactName = 'Greeter'; - const constructorArguments = ['Hi there!']; - await deployContract(contractArtifactName, constructorArguments); -} -``` - -To execute it, just run: - -::: code-tabs - -@tab:active yarn - -```bash -yarn deploy -``` - -@tab npm - -```bash -npm run deploy -``` - -::: - -You'll get the following output: - -```sh -Starting deployment process of "Greeter"... -Estimated deployment cost: 0.0000648863 ETH - -"Greeter" was successfully deployed: - - Contract address: 0x0BaF96A7f137B05d0D35b76d59B16c86C1791D8D - - Contract source: contracts/Greeter.sol:Greeter - - Encoded constructor arguments: 0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000094869207468657265210000000000000000000000000000000000000000000000 - -Requesting contract verification... -Your verification ID is: 1781 -``` - -🥳 Congratulations! You just deployed a smart contract to zkSync Sepolia testnet. You can find it in the -[zkSync Sepolia explorer](https://sepolia.explorer.zksync.io/) by searching the contract address. - -In addition, the deployment script verified the contract automatically so you can see the source code in the contract -tab of the block explorer. - -## Interact with the contract - -The project also comes with a script to interact with the contract in `/deploy/interact.ts`. Add the address of the -Greeter contract you just deployed in the `CONTRACT_ADDRESS` variable inside the `/deploy/interact.ts` file: - -```ts -import * as hre from 'hardhat'; -import { getWallet } from './utils'; -import { ethers } from 'ethers'; - -// Address of the contract to interact with -const CONTRACT_ADDRESS = ''; -if (!CONTRACT_ADDRESS) throw '⛔️ Provide address of the contract to interact with!'; - -// An example of a script to interact with the contract -export default async function () { - console.log(`Running script to interact with contract ${CONTRACT_ADDRESS}`); - - // Load compiled contract info - const contractArtifact = await hre.artifacts.readArtifact('Greeter'); - - // Initialize contract instance for interaction - const contract = new ethers.Contract( - CONTRACT_ADDRESS, - contractArtifact.abi, - getWallet() // Interact with the contract on behalf of this wallet - ); - - // Run contract read function - const response = await contract.greet(); - console.log(`Current message is: ${response}`); - - // Run contract write function - const transaction = await contract.setGreeting('Hello people!'); - console.log(`Transaction hash of setting new message: ${transaction.hash}`); - - // Wait until transaction is processed - await transaction.wait(); - - // Read message after transaction - console.log(`The message now is: ${await contract.greet()}`); -} -``` - -As you can see, we're simply using `ethers` to interact with our contract. zkSync is EVM compatible so you can use -existing tools and libraries like `Hardhat`, `ethers`, `web3.js`, and users can use their existing wallets like -Metamask, Rabby or Zerion. - -::: tip Takeaway - -Existing libraries like `ethers` and `web3.js` can be used to interact with smart contracts deployed on zkSync. - -::: - -To execute the `/deploy/interact.ts` script, run: - -::: code-tabs - -@tab:active yarn - -```bash -yarn interact -``` - -@tab npm - -```bash -npm run interact -``` - -::: - -You'll get the following output: - -```sh -Running script to interact with contract 0x0BaF96A7f137B05d0D35b76d59B16c86C1791D8D -Current message is: Hi there! -Transaction hash of setting new message: 0x7a534857cfcd6df7e3eaf40a79a2c88f2e36bb60ce6f2399345e5431362b04eb -The message now is: Hello people! -✨ Done in 4.13s. -``` - -Congratulations! You've retrieved and updated the message on the `Greeter` contract. You can see the transaction -[in the block explorer](https://sepolia.explorer.zksync.io/) by searching the transaction hash. - -## Takeaways - -- zkSync is EVM compatible and you can write smart contracts in Solidity or Vyper, use Hardhat, libraries like Ethers - and Web3.js, or wallets like Metamask and Rabby. -- zkSync CLI provides a quick way to scaffold different types of projects thanks to its multiple templates. -- Contracts deployed to zkSync are compiled using `zksolc` or `zkvyper` as they generate a special bytecode for zkSync's - ZKEVM. - -## Next steps - -This was your first step towards becoming a zkSync developer. Here is what you can do next: - -- Create a frontend for this contract following the - [Frontend quickstart](../tutorials/dapp-development/frontend-quickstart-paymaster.md). -- Join our [developer community in GitHub](https://github.com/zkSync-Community-Hub/zksync-developers/discussions), where - you can ask questions and help other developers. -- Read the [Security and best practices](./best-practices.md) to keep you apps secure. -- Learn about the [differences between Ethereum and zkSync](../developer-reference/differences-with-ethereum.md). -- If you have a project, check out our [migration guide](../tooling/hardhat/migrating-to-zksync.md). diff --git a/content/20.build/quick-start/interact.md b/content/20.build/quick-start/interact.md deleted file mode 100644 index 5d78d818..00000000 --- a/content/20.build/quick-start/interact.md +++ /dev/null @@ -1,33 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Interact with zkSync Era | zkSync Docs ---- - -# Interact with zkSync Era - -## What do I need to start building? - -All the existing SDKs for Ethereum will work out of the box and your users will have the same experience as on Ethereum. -If you want to enable advanced zkSync features, like account abstraction, the zkSync SDK should be used. - -The only other place where using zkSync SDK is required is during -[contract deployment](../developer-reference/contract-deployment.md). This can be easily done through our -[Hardhat plugin](../tooling/hardhat/hardhat-zksync-deploy.md). - -### Setting up your wallet - -To configure zkSync Era (and testnets) in your wallet [follow this guide](../quick-start/add-zksync-to-metamask.md). - -### Quickstart on zkSync - -Before diving into the technical details, we highly recommend checking out our -[Security considerations](./best-practices.md) and -[Differences with Ethereum](../../build/developer-reference/differences-with-ethereum.md) sections. This will help align -your development with the distinctive attributes of zkSync Era and ensure your projects are secure and optimized. - -Check out our step-by-step [quickstart guide](../../build/quick-start/hello-world.md), where you will learn: - -- How to install zkSync hardhat plugin and deploy smart contracts with it. -- How to build the front-end for your dApp using the `zksync-ethers` library. diff --git a/content/20.build/quick-start/useful-address.md b/content/20.build/quick-start/useful-address.md deleted file mode 100644 index 1d29229a..00000000 --- a/content/20.build/quick-start/useful-address.md +++ /dev/null @@ -1,67 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Useful Addresses | zkSync Docs ---- - -# Useful Addresses - -Here are some contract addresses that may be useful and/or of interest to those exploring zkSync Era: - -## Mainnet - -### Mainnet contract addresses - -| Contract | Address | -| ----------------- | -------------------------------------------------------------------------------------------------------------------------- | -| DiamondInit | [0xb91d905A698c28b73C61aF60C63919b754FCF4DE](https://etherscan.io/address/0xb91d905A698c28b73C61aF60C63919b754FCF4DE#code) | -| DiamondProxy | [0x32400084c286cf3e17e7b677ea9583e60a000324](https://etherscan.io/address/0x32400084c286cf3e17e7b677ea9583e60a000324#code) | -| DiamondUpgrade | [0xe79a6d29bB0520648F25D11d65e29FB06B195F0F](https://etherscan.io/address/0xe79a6d29bB0520648F25D11d65e29FB06B195F0F#code) | -| ExecutorFacet | [0xD059478a564dF1353A54AC0D0e7Fc55A90b92246](https://etherscan.io/address/0xD059478a564dF1353A54AC0D0e7Fc55A90b92246#code) | -| GettersFacet | [0xF3ACF6a03ea4a914B78Ec788624B25ceC37c14A4](https://etherscan.io/address/0xF3ACF6a03ea4a914B78Ec788624B25ceC37c14A4#code) | -| Verifier | [0xB465882F67d236DcC0D090F78ebb0d838e9719D8](https://etherscan.io/address/0xB465882F67d236DcC0D090F78ebb0d838e9719D8#code) | -| MailboxFacet | [0x63b5EC36B09384fFA7106A80Ec7cfdFCa521fD08](https://etherscan.io/address/0x63b5EC36B09384fFA7106A80Ec7cfdFCa521fD08#code) | -| ValidatorTimelock | [0xa8cb082a5a689e0d594d7da1e2d72a3d63adc1bd](https://etherscan.io/address/0xa8cb082a5a689e0d594d7da1e2d72a3d63adc1bd#code) | -| AllowList | [0x0C0dC1171258694635AA50cec5845aC1031cA6d7](https://etherscan.io/address/0x0C0dC1171258694635AA50cec5845aC1031cA6d7#code) | - -### Mainnet token bridge contract addresses - -:::warning - -**Do not transfer tokens or Ether to any of the addresses below;** it will result in a loss of funds. - -::: - -| Contract | Address | -| ------------------ | --------------------------------------------------------------------------------------------------------------------------- | -| L1ERC20BridgeProxy | [0x57891966931Eb4Bb6FB81430E6cE0A03AAbDe063](https://etherscan.io/address/0x57891966931Eb4Bb6FB81430E6cE0A03AAbDe063#code) | -| L1ERC20BridgeImpl | [0x03F3F3c12e11C2FAA60080bd3F7f80AADF369a33](https://etherscan.io/address/0x03F3F3c12e11C2FAA60080bd3F7f80AADF369a33#code) | -| L2ERC20Bridge | [0x11f943b2c77b743AB90f4A0Ae7d5A4e7FCA3E102](https://explorer.zksync.io/address/0x11f943b2c77b743AB90f4A0Ae7d5A4e7FCA3E102) | - -## Sepolia Testnet - -### Sepolia contract addresses - -| Contract | Address | -| ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------- | -| DiamondInit | [0x457701fDC6CaBc7D2EfB9b85f7faB0EE4bBD3c36](https://sepolia.etherscan.io/address/0x457701fDC6CaBc7D2EfB9b85f7faB0EE4bBD3c36#code) | -| DiamondProxy | [0x9a6de0f62Aa270A8bCB1e2610078650D539B1Ef9](https://sepolia.etherscan.io/address/0x9a6de0f62Aa270A8bCB1e2610078650D539B1Ef9#code) | -| DiamondUpgrade | [0xA6b2731c08385782fBaCfCcD63D3c7fc7b798E47](https://sepolia.etherscan.io/address/0xA6b2731c08385782fBaCfCcD63D3c7fc7b798E47#code) | -| ExecutorFacet | [0xe6cc1455217a8BBCF2c663607A0b8c200B8732F1](https://sepolia.etherscan.io/address/0xe6cc1455217a8BBCF2c663607A0b8c200B8732F1#code) | -| GettersFacet | [0x10f328c20dD2469b7e88f374B9794471599c1c8D](https://sepolia.etherscan.io/address/0x10f328c20dD2469b7e88f374B9794471599c1c8D#code) | -| Verifier | [0xf07ea72e071bc21612449570C365Ff3DC9176Ecb](https://sepolia.etherscan.io/address/0xf07ea72e071bc21612449570C365Ff3DC9176Ecb#code) | -| MailboxFacet | [0x2ed8eF54a16bBF721a318bd5a5C0F39Be70eaa65](https://sepolia.etherscan.io/address/0x2ed8eF54a16bBF721a318bd5a5C0F39Be70eaa65#code) | -| ValidatorTimeLock | [0x8CaC0a609A314E4161b8070cdEe065060B2486A1](https://sepolia.etherscan.io/address/0x8CaC0a609A314E4161b8070cdEe065060B2486A1#code) | -| AllowList | [0x7546a21cd4D74fc98Ef1A50145dfd8c043e2096F](https://sepolia.etherscan.io/address/0x7546a21cd4D74fc98Ef1A50145dfd8c043e2096F#code) | -| L2TestnetPaymaster | [0x3cb2b87d10ac01736a65688f3e0fb1b070b3eea3](https://sepolia.explorer.zksync.io/address/0x3cb2b87d10ac01736a65688f3e0fb1b070b3eea3#code) | - -### Sepolia Token bridge, contract addresses - -These are the addresses that have been deployed and integrated with the token bridge on testnet. - -| Contract | Address | -| ------------------ | ----------------------------------------------------------------------------------------------------------------------------------- | -| L1ERC20BridgeProxy | [0x2Ae09702F77a4940621572fBcDAe2382D44a2cbA](https://sepolia.etherscan.io/address/0x2Ae09702F77a4940621572fBcDAe2382D44a2cbA#code) | -| L1ERC20BridgeImpl | [0x84DbCC0B82124bee38e3Ce9a92CdE2f943bab60D](https://sepolia.etherscan.io/address/0x84DbCC0B82124bee38e3Ce9a92CdE2f943bab60D#code) | -| L2ERC20Bridge | [0x681A1AFdC2e06776816386500D2D461a6C96cB45](https://sepolia.explorer.zksync.io/address/0x681A1AFdC2e06776816386500D2D461a6C96cB45) | diff --git a/content/20.build/sdks/go/accounts-l1-l2.md b/content/20.build/sdks/go/accounts-l1-l2.md deleted file mode 100644 index af59ee8f..00000000 --- a/content/20.build/sdks/go/accounts-l1-l2.md +++ /dev/null @@ -1,56 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Go SDK L1/L2 Transactions | zkSync Docs ---- - -# Accounts: L1<->L2 Transactions - -This section explores the methods which allow the [account](./accounts.md) to send transactions among both L1 to L2 -networks. - -If you want some background on how L1<->L2 interaction works on zkSync, go through the -[introduction](../../developer-reference/l1-l2-interop.md). - -Full examples of actions below are available on the [getting started](./getting-started.md) page. - -## Deposit - -`WalletL1` and `Wallet` objects provide a deposit workflow. For more information, please refer to the method -specification [`Deposit`](accounts.md#deposit). - -For a comprehensive example demonstrating the deposit workflow, refer to the following: - -- [Deposit ETH](https://github.com/zksync-sdk/zksync2-examples/blob/main/go/01_deposit.go). -- [Deposit ERC20 tokens](https://github.com/zksync-sdk/zksync2-examples/blob/main/go/05_deposit_token.go). - -## Request execute - -`WalletL1` and `Wallet` objects provide an option to request execution of L2 transaction from L1. For more information, -please refer to the method specification [`RequestExecute`](accounts.md#requestexecute). - -## Base cost - -`WalletL1` and `Wallet` objects provide an option to calculate base cost for L2 transaction. For more information, -please refer to the method specification [`BaseCost`](accounts.md#basecost). - -## Claim failed deposit - -`WalletL1` and `Wallet` objects provide a claim fail deposit workflow. For more information, please refer to the method -specification [`ClaimFailedDeposit`](accounts.md#claimfaileddeposit). - -## Finalize withdraw - -`WalletL1` and `Wallet` objects provide a finalize withdraw workflow. For more information, please refer to the method -specification [`FinalizeWithdraw`](accounts.md#finalizewithdraw). - -## Withdrawal - -`WalletL2` and `Wallet` objects provide a withdrawal workflow. For more information, please refer to the method -specification [`Deposit`](accounts.md#deposit). - -For a complete example of how to execute the deposit workflow, take a look at the following: - -- [Withdraw ETH](https://github.com/zksync-sdk/zksync2-examples/blob/main/go/03_withdraw.go). -- [Withdraw ERC20 token](https://github.com/zksync-sdk/zksync2-examples/blob/main/go/07_withdraw_token.go). diff --git a/content/20.build/sdks/go/accounts.md b/content/20.build/sdks/go/accounts.md deleted file mode 100644 index 78cd3ff7..00000000 --- a/content/20.build/sdks/go/accounts.md +++ /dev/null @@ -1,1543 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Go SDK Accounts | zkSync Docs ---- - -# Accounts - -## Overview - -The `accounts` package provides abstractions that wrap operations that interact with an account. An account typically -contains a private key, allowing it to sign various types of payloads. There are the following interfaces that provide -account operations for different purposes: - -- `Signer` provides support for signing EIP-712 transactions as well as other types of transactions supported by - [`types.Signer`](https://pkg.go.dev/github.com/ethereum/go-ethereum@v1.12.0/core/types#Signer). -- `AdapterL1` is associated with an account and provides common operations on the L1 network for the associated account. -- `AdapterL2` is associated with an account and provides common operations on the L2 network for the associated account. -- `Deployer` is associated with an account and provides deployment of smart contracts and smart accounts on the L2 - network for the associated account. -- `Adapter` consists of `AdapterL1`, `AdapterL2`, and `Deployer` interfaces. - -There are the following objects that provide account operations: - -- `BaseSigner` implements the `Signer` interface. -- `WalletL1` implements the `AdapterL1` interface. -- `WalletL2` implements the `AdapterL2` interface. -- `BaseDeployer` implements the `Deployer` interface. -- `Wallet` implements the `Adapter` interface. - -In most cases, `Wallet` should be used because it provides all the necessary operations. Other objects and interfaces -are separated to make the SDK more flexible and extensible. - -## `BaseSigner` - -### `Init` - -Creates a new instance of `BaseSigner` based on the provided mnemonic phrase. - -```go -func NewBaseSignerFromMnemonic(mnemonic string, chainId int64) (*BaseSigner, error) -``` - -Creates a new instance of `BaseSigner` based on the provided mnemonic phrase and account ID. - -```go -func NewBaseSignerFromMnemonicAndAccountId(mnemonic string, accountId uint32, chainId int64) (*BaseSigner, error) -``` - -Creates a new instance of BaseSigner based on the provided raw private key. - -```go -func NewBaseSignerFromRawPrivateKey(rawPk []byte, chainId int64) (*BaseSigner, error) -``` - -Creates an instance of Signer with a randomly generated private key. - -```go -func NewRandomBaseSigner(chainId int64) (*BaseSigner, error) -``` - -### `Address` - -Returns the address associated with the signer. - -```go -Address() common.Address -``` - -### `Domain` - -Returns the EIP-712 domain used for signing. - -```go -Domain() *eip712.Domain -``` - -### `PrivateKey` - -Returns the private key associated with the signer. - -```go -PrivateKey() *ecdsa.PrivateKey -``` - -Signs the given hash using the signer's private key and returns the signature. The hash should be the 32-byte hash of -the data to be signed. - -### `SignHash` - -```go -SignHash(msg []byte) ([]byte, error) -``` - -### `SignTypeData` - -Signs the given EIP-712 typed data using the signer's private key and returns the signature. The domain parameter is the -EIP-712 domain separator, and the data parameter is the EIP-712 typed data. - -```go -SignTypedData(d *eip712.Domain, data eip712.TypedData) ([]byte, error) -``` - -## `WalletL1` - -### `Init` - -Creates an instance of WalletL1 associated with the account provided by the raw private key. - -```go -func NewWalletL1(rawPrivateKey []byte, clientL1 *ethclient.Client, clientL2 *clients.Client) (*WalletL1, error -``` - -Creates an instance of WalletL1 associated with the account provided by the signer. - -```go -NewWalletL1FromSigner(signer *Signer, clientL1 *ethclient.Client, clientL2 *clients.Client) (*WalletL1, error) -``` - -#### Example - -```go -PrivateKey := os.Getenv("PRIVATE_KEY") -ZkSyncEraProvider := "https://sepolia.era.zksync.dev" -EthereumProvider := "https://rpc.ankr.com/eth_sepolia" - -client, err := clients.Dial(ZkSyncEraProvider) -if err != nil { - log.Panic(err) -} -defer client.Close() - -ethClient, err := ethclient.Dial(EthereumProvider) -if err != nil { - log.Panic(err) -} -defer ethClient.Close() - -wallet, err := accounts.NewWalletL1(common.Hex2Bytes(PrivateKey), &client, ethClient) -if err != nil { - log.Panic(err) -} -``` - -### `MainContract` - -Returns the zkSync L1 smart contract. - -#### Inputs - -| Parameter | Type | Description | -| --------- | ----------------- | ----------- | -| `ctx` | `context.Context` | Context. | - -```go -MainContract(ctx context.Context) (*zksync.IZkSync, error) -``` - -#### Example - -```go -mainContract, err := wallet.MainContract(context.Background()) -if err != nil { - log.Panic(err) -} -``` - -### `L1BridgeContracts` - -Returns L1 bridge contracts. - -#### Inputs - -| Parameter | Type | Description | -| --------- | ----------------- | ----------- | -| `ctx` | `context.Context` | Context. | - -```go -L1BridgeContracts(ctx context.Context) (*zkTypes.L1BridgeContracts, error) -``` - -#### Example - -```go -contracts, err := wallet.L1BridgeContracts(context.Background()) -if err != nil { - log.Panic(err) -} -``` - -### `BalanceL1` - -Returns the balance of the specified token on L1 that can be either ETH or any ERC20 token. - -#### Inputs - -| Parameter | Type | Description | -| --------- | --------------------------------------------------- | -------------- | -| `opts` | [`CallOpts`](types/accounts.md#callopts) (optional) | Call options. | -| `token` | `common.Address` | Token address. | - -```go -BalanceL1(opts *CallOpts, token common.Address) (*big.Int, error) -``` - -#### Example - -```go -balance, err := wallet.BalanceL1(nil, utils.EthAddress) -if err != nil { - log.Panic(err) -} -fmt.Println("Balance: ", balance) -``` - -### `AllowanceL1` - -Returns the amount of approved tokens for a specific L1 bridge. - -#### Inputs - -| Parameter | Type | Description | -| --------------- | --------------------------------------------------- | --------------- | -| `opts` | [`CallOpts`](types/accounts.md#callopts) (optional) | Call options. | -| `token` | `common.Address` | Token address. | -| `bridgeAddress` | `common.Address` | Bridge address. | - -```go -AllowanceL1(opts *CallOpts, token common.Address, bridgeAddress common.Address) (*big.Int, error) -``` - -#### Example - -```go -ZkSyncEraProvider := "https://testnet.era.zksync.dev" -// The Crown token on testnet -TokenAddress := common.HexToAddress("0x927488F48ffbc32112F1fF721759649A89721F8F") - -client, err := clients.Dial(ZkSyncEraProvider) -if err != nil { - log.Panic(err) -} -defer client.Close() - - -contracts, err := client.BridgeContracts(context.Background()) -if err != nil { - log.Panic(err) -} -bridgeAllowance, err := wallet.AllowanceL1(nil, TokenAddress, contracts.L1Erc20DefaultBridge) -if err != nil { - log.Panic(err) -} -fmt.Println("Bridge allowance: ", bridgeAllowance) -``` - -### `L2TokenAddress` - -Returns the corresponding address on the L2 network for the token on the L1 network. - -#### Inputs - -| Parameter | Type | Description | -| --------- | ----------------- | ----------------- | -| `ctx` | `context.Context` | Context. | -| `token` | `common.Address` | L1 token address. | - -```go -L2TokenAddress(ctx context.Context, token common.Address) (common.Address, error) -``` - -#### Example - -```go -l1DAI := common.HexToAddress("0x5C221E77624690fff6dd741493D735a17716c26B") -l2DAI, err := wallet.L2TokenAddress(context.Background(), l1DAI) -if err != nil { - log.Panic(err) -} -fmt.Println("L2 DAI address: ", l2DAI) -``` - -### `ApproveERC20` - -Approves the specified amount of tokens for the specified L1 bridge. - -#### Inputs - -| Parameter | Type | Description | -| --------- | ----------------- | ----------------- | -| `ctx` | `context.Context` | Context. | -| `token` | `common.Address` | L1 token address. | -| `amount` | `*big.Int` | Approval amount. | - -```go -ApproveERC20(auth *TransactOpts, token common.Address, amount *big.Int, bridgeAddress common.Address) (*types.Transaction, error) -``` - -#### Example - -```go -ZkSyncEraProvider := "https://testnet.era.zksync.dev" -// The Crown token on testnet -TokenAddress := common.HexToAddress("0x927488F48ffbc32112F1fF721759649A89721F8F") - -client, err := clients.Dial(ZkSyncEraProvider) -if err != nil { - log.Panic(err) -} -defer client.Close() - - -contracts, err := client.BridgeContracts(context.Background()) -if err != nil { - log.Panic(err) -} -tx, err := wallet.ApproveERC20(nil, TokenAddress, contracts.L1Erc20DefaultBridge) -if err != nil { - log.Panic(err) -} -fmt.Println("Tx: ", tx.Hash()) -``` - -### `BaseCost` - -Returns base cost for L2 transaction. - -#### Inputs - -| Parameter | Type | Description | -| ------------------- | --------------------------------------------------- | -------------------------------------------------------------------------------------- | -| `opts` | [`CallOpts`](types/accounts.md#callopts) (optional) | Call options. | -| `gasLimit` | `*big.Int` | The gasLimit for the the L2 contract call. | -| `gasPerPubdataByte` | `*big.Int` | The L2 gas price for each published L1 calldata byte. | -| `gasPrice` | `*big.Int` (optional) | The L1 gas price of the L1 transaction that will send the request for an execute call. | - -```go -BaseCost(opts *CallOpts, gasLimit, gasPerPubdataByte, gasPrice *big.Int) (*big.Int, error) -``` - -#### Example - -```go -ZkSyncEraProvider := "https://testnet.era.zksync.dev" - -client, err := clients.Dial(ZkSyncEraProvider) -if err != nil { - log.Panic(err) -} -defer client.Close() - -gasPrice, err := client.SuggestGasPrice(context.Background()) -if err != nil { - log.Panic(err) -} - -baseCost, err := wallet.BaseCost(nil, big.NewInt(9000), utils.RequiredL1ToL2GasPerPubdataLimit, gasPrice) -if err != nil { - log.Panic(err) -} -fmt.Println("Base cost: ", baseCost) -``` - -### `Deposit` - -Transfers the specified token from the associated account on the L1 network to the target account on the L2 network. The -token can be either ETH or any ERC20 token. For ERC20 tokens, enough approved tokens must be associated with the -specified L1 bridge (default one or the one defined in `BridgeAddress`). In this case, `ApproveERC20` can be enabled to -perform token approval. If there are already enough approved tokens for the L1 bridge, token approval will be skipped. -To check the amount of approved tokens for a specific bridge, use the [`AllowanceL1`](#allowancel1) method. - -#### Inputs - -| Parameter | Type | Description | -| --------- | ------------------------------------------------------------ | ------------------------------- | -| `auth` | [`*TransactOpts`](types/accounts.md#transactopts) (optional) | Transaction options. | -| `tx` | [`DepositTransaction`](types/accounts.md#deposittransaction) | Deposit transaction parameters. | - -```go -Deposit(auth *TransactOpts, tx DepositTransaction) (*types.Transaction, error) -``` - -#### Example - -```go -tx, err := wallet.Deposit(nil, accounts.DepositTransaction{ - Token: utils.EthAddress, - Amount: big.NewInt(2_000_000_000_000_000_000), - To: common.HexToAddress(""), -}) -if err != nil { - log.Panic(err) -} -fmt.Println("L1 deposit transaction: ", tx.Hash()) -``` - -### `EstimateGasDeposit` - -Estimates the amount of gas required for a deposit transaction on L1 network. Gas of approving ERC20 token is not -included in the estimation. - -#### Inputs - -| Parameter | Type | Description | -| --------- | ---------------------------------------------------- | ------------------------ | -| `ctx` | `context.Context` | Context. | -| `msg` | [`DepositCallMsg`](types/accounts.md#depositcallmsg) | Deposit call parameters. | - -```go -EstimateGasDeposit(ctx context.Context, msg DepositCallMsg) (uint64, error) -``` - -#### Example - -```go -depositGas, err := wallet.EstimateGasDeposit(context.Background(), accounts.DepositCallMsg{ - To: wallet.Address(), - Token: utils.EthAddress, - Amount: big.NewInt(7_000_000_000), -}) -if err != nil { - log.Panic(err) -} -fmt.Println("Deposit gas: ", depositGas) -``` - -### `FullRequiredDepositFee` - -Retrieves the full needed ETH fee for the deposit on both L1 and L2 networks. - -#### Inputs - -| Parameter | Type | Description | -| --------- | ---------------------------------------------------- | ------------------------ | -| `ctx` | `context.Context` | Context. | -| `msg` | [`DepositCallMsg`](types/accounts.md#depositcallmsg) | Deposit call parameters. | - -```go -FullRequiredDepositFee(ctx context.Context, msg DepositCallMsg) (*FullDepositFee, error) -``` - -#### Example - -```go -fee, err := wallet.FullRequiredDepositFee(context.Background(), accounts.DepositCallMsg{ - To: wallet.Address(), - Token: utils.EthAddress, - Amount: big.NewInt(7_000_000_000), -}) -if err != nil { - log.Panic(err) -} -fmt.Printf("Fee: %+v\n", fee) -``` - -### `FinalizeWithdraw` - -Proves the inclusion of the L2 -> L1 withdrawal message. - -#### Inputs - -| Parameter | Type | Description | -| ---------------- | ------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------- | -| `auth` | [`*TransactOpts`](types/accounts.md#transactopts) (optional) | Transaction options. | -| `withdrawalHash` | `common.Hash` | Hash of the L2 transaction where the withdrawal was initiated. | -| `index` | `int` | In case there were multiple withdrawals in one transaction, you may pass an index of the withdrawal you want to finalize. | - -```go -FinalizeWithdraw(auth *TransactOpts, withdrawalHash common.Hash, index int) (*types.Transaction, error) -``` - -#### Example - -```go -withdrawalHash := common.HexToHash("") -finalizeWithdrawTx, err := wallet.FinalizeWithdraw(nil, withdrawalHash, 0) -if err != nil { - log.Panic(err) -} -fmt.Println("Finalize withdraw transaction: ", finalizeWithdrawTx.Hash()) -``` - -### `IsWithdrawFinalized` - -Checks if the withdrawal finalized on L1 network. - -#### Inputs - -| Parameter | Type | Description | -| ---------------- | --------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- | -| `opts` | [`CallOpts`](types/accounts.md#callopts) (optional) | Call options. | -| `withdrawalHash` | `common.Hash` | Hash of the L2 transaction where the withdrawal was initiated. | -| `index` | `int` | In case there where multiple withdrawals in one transaction, you may pass an index of the withdrawal you want to finalize. | - -```go -IsWithdrawFinalized(opts *CallOpts, withdrawalHash common.Hash, index int) (bool, error) -``` - -#### Example - -```go -withdrawalHash := common.HexToHash("") -isFinalized, err := wallet.IsWithdrawFinalized(nil, withdrawalHash, 0) -if err != nil { - log.Panic(err) -} -fmt.Println("Is withdrawal finalized: ", isFinalized) -``` - -### `ClaimFailedDeposit` - -Withdraws funds from the initiated deposit, which failed when finalizing on L2. If the deposit L2 transaction has -failed, it sends an L1 transaction calling ClaimFailedDeposit method of the L1 bridge, which results in returning L1 -tokens back to the depositor, otherwise throws the error. - -#### Inputs - -| Parameter | Type | Description | -| ------------- | ------------------------------------------------------------ | ---------------------------------------------- | -| `auth` | [`*TransactOpts`](types/accounts.md#transactopts) (optional) | Transaction options. | -| `depositHash` | `common.Hash` | The L2 transaction hash of the failed deposit. | - -```go -ClaimFailedDeposit(auth *TransactOpts, depositHash common.Hash) (*types.Transaction, error) -``` - -#### Example - -```go -failedDepositL2Hash := common.HexToHash("") -cfdTx, err := w.ClaimFailedDeposit(nil, failedDepositL2Hash) -if err != nil { - log.Panic(err) -} -fmt.Println("ClaimFailedDeposit hash: ", cfdTx.Hash) -``` - -### `RequestExecute` - -Request execution of L2 transaction from L1. - -#### Inputs - -| Parameter | Type | Description | -| --------- | -------------------------------------------------------------------------- | --------------------------------------- | -| `auth` | [`*TransactOpts`](types/accounts.md#transactopts) (optional) | Transaction options. | -| `tx` | [`RequestExecuteTransaction`](types/accounts.md#requestexecutetransaction) | Request execute transaction parameters. | - -```go -RequestExecute(auth *TransactOpts, tx RequestExecuteTransaction) (*types.Transaction, error) -``` - -#### Example - -```go -contractAddress := common.HexToAddress("") -requestExecuteTx, err := wallet.RequestExecute(nil, accounts.RequestExecuteTransaction{ - ContractAddress: contractAddress, - L2Value: big.NewInt(7_000_000_000), - L2GasLimit: big.NewInt(90_000), - GasPerPubdataByte: utils.RequiredL1ToL2GasPerPubdataLimit, - RefundRecipient: to, -}) -if err != nil { - log.Panic(err) -} -fmt.Println("Request execute tx: ", requestExecuteTx.Hash()) -``` - -### `EstimateGasRequestExecute` - -Estimates the amount of gas required for a request execute transaction. - -#### Inputs - -| Parameter | Type | Description | -| --------- | ------------------------------------------------------------------ | -------------------------------- | -| `ctx` | `context.Context` | Context. | -| `msg` | [`RequestExecuteCallMsg`](types/accounts.md#requestexecutecallmsg) | Request execute call parameters. | - -```go -EstimateGasRequestExecute(ctx context.Context, msg RequestExecuteCallMsg) (uint64, error) -``` - -#### Example - -```go -contractAddress := common.HexToAddress("") -gas, err := wallet.EstimateGasRequestExecute(context.Background(), accounts.RequestExecuteCallMsg{ - ContractAddress: contractAddress, - L2Value: big.NewInt(7_000_000_000), - L2GasLimit: big.NewInt(90_000), - GasPerPubdataByte: utils.RequiredL1ToL2GasPerPubdataLimit, - RefundRecipient: to, -}) -if err != nil { - log.Panic(err) -} -fmt.Println("Gas: ", gas) -``` - -### `EstimateCustomBridgeDepositL2Gas` - -Used by [`EstimateDefaultBridgeDepositL2Gas`](#estimatedefaultbridgedepositl2gas) to estimate L2 gas required for token -bridging via a custom ERC20 bridge. - -::: tip More info See the [default bridges documentation](../../developer-reference/bridging-asset.md) ::: - -#### Inputs - -| Parameter | Type | Description | -| ------------------- | --------------------------- | -------------------------------- | -| `ctx` | `context.Context` | Context. | -| `l1BridgeAddress` | `common.Address` | L1 bridge address. | -| `l2BridgeAddress` | `common.Address` | L2 bridge address. | -| `token` | `common.Address` | Token address. | -| `amount` | `*big.Int` | Deposit amount. | -| `to` | `common.Address` | Recipient address. | -| `bridgeData` | `[]byte` | Bridge data. | -| `from` | `common.Address` (optional) | Sender address. | -| `gasPerPubdataByte` | `*big.Int` (optional) | Current gas per byte of pubdata. | - -```go -EstimateCustomBridgeDepositL2Gas(ctx context.Context, l1BridgeAddress, l2BridgeAddress, token common.Address, - amount *big.Int, to common.Address, bridgeData []byte, from common.Address, gasPerPubdataByte *big.Int) (uint64, error) -``` - -#### Example - -```go -L1BridgeAddress := common.HexToAddress("") -Token := common.HexToAddress("") -From := common.HexToAddress("") -To := common.HexToAddress("") - - -bridge, err := l1bridge.NewIL1Bridge(L1BridgeAddress, ethClient) -if err != nil { - log.Panic(err) -} -l2BridgeAddress, err := bridge.L2Bridge(nil) -if err != nil { - log.Panic(err) -} -customBridgeData, err := utils.Erc20DefaultBridgeData(Token, ethClient) -if err != nil { - log.Panic(err) -} - -gas, err := wallet1.EstimateCustomBridgeDepositL2Gas(context.Background(), L1BridgeAddress, l2BridgeAddress, Token, - big.NewInt(7), To, customBridgeData, From, utils.RequiredL1ToL2GasPerPubdataLimit) -if err != nil { - log.Panic(err) -} -fmt.Println("L2 gas: ", gas) -``` - -### `EstimateDefaultBridgeDepositL2Gas` - -Returns an estimation of L2 gas required for token bridging via the default ERC20 bridge. - -::: tip More info See the [default bridges documentation](../../developer-reference/bridging-asset.md#default-bridges) -::: - -#### Inputs - -| Parameter | Type | Description | -| -------------------- | --------------------------- | -------------------------------- | -| `ctx` | `context.Context` | Context. | -| `token` | `common.Address` | Token address. | -| `amount` | `*big.Int` | Deposit amount. | -| `to` | `common.Address` | Recipient address. | -| `from?` | `common.Address` (optional) | Sender address. | -| `gasPerPubdataByte?` | `*big.Int` (optional) | Current gas per byte of pubdata. | - -```go -EstimateDefaultBridgeDepositL2Gas(ctx context.Context, token common.Address, amount *big.Int, - to, from common.Address, gasPerPubdataByte *big.Int) (uint64, error) -``` - -#### Example - -```go -Token := common.HexToAddress("") -From := common.HexToAddress("") -To := common.HexToAddress("") -gas, err := wallet1.EstimateDefaultBridgeDepositL2Gas( - context.Background(), Token, big.NewInt(7), To, From, utils.RequiredL1ToL2GasPerPubdataLimit, -) -if err != nil { - log.Panic(err) -} -fmt.Println("L2 gas: ", gas) -``` - -## `WalletL2` - -### `Init` - -Creates an instance of `WalletL2` associated with the account provided by the raw private key. - -```go -func NewWalletL2(rawPrivateKey []byte, client *clients.Client) (*WalletL2, error) -``` - -Creates an instance of `WalletL2`. The `client` can be optional; if it is not provided, only `SignTransaction`, -`Address`, `Signer` can be performed, as the rest of the functionalities require communication to the network. - -```go -func NewWalletL2FromSigner(signer *Signer, client *clients.Client) (*WalletL2, error) -``` - -#### Example - -```go -PrivateKey := os.Getenv("PRIVATE_KEY") -ZkSyncEraProvider := "https://testnet.era.zksync.dev" - -client, err := clients.Dial(ZkSyncEraProvider) -if err != nil { - log.Panic(err) -} -defer client.Close() - -wallet, err := accounts.NewWallet(common.Hex2Bytes(PrivateKey), &client) -if err != nil { - log.Panic(err) -} - -``` - -### `Address` - -Returns the address of the associated account. - -```go -Address() common.Address -``` - -#### Example - -```go -fmt.Println("Address: ", wallet.Address()) -``` - -### `Signer` - -Returns the signer of the associated account. - -```go -Signer() Signer -``` - -#### Example - -```go -fmt.Printf("Signer %+v\n", wallet.Signer()) -``` - -### `Balance` - -Returns the balance of the specified token that can be either ETH or any ERC20 token. The block number can be `nil`, in -which case the balance is taken from the latest known block. - -#### Inputs - -| Parameter | Type | Description | -| --------- | ----------------- | ----------------- | -| `ctx` | `context.Context` | Context. | -| `token` | `common.Address` | L2 token address. | -| `at` | `*big.Int` | Block number. | - -```go -Balance(ctx context.Context, token common.Address, at *big.Int) (*big.Int, error) -``` - -#### Example - -```go -balance, err := w.Balance(context.Background(), utils.EthAddress, nil) -if err != nil { - log.Panic(err) -} -fmt.Println("Balance: ", balance) -``` - -### `AllBalances` - -Returns all balances for confirmed tokens given by an associated account. - -#### Inputs - -| Parameter | Type | Description | -| --------- | ----------------- | ----------- | -| `ctx` | `context.Context` | Context. | - -```go -AllBalances(ctx context.Context) (map[common.Address]*big.Int, error) -``` - -#### Example - -```go -balances, err := wallet.AllBalances(context.Background()) -if err != nil { - log.Panic(err) -} -fmt.Printf("Balances: %+v\n", balances) -``` - -### `L2BridgeContracts` - -Returns L2 bridge contracts. - -#### Inputs - -| Parameter | Type | Description | -| --------- | ----------------- | ----------- | -| `ctx` | `context.Context` | Context. | - -```go -L2BridgeContracts(ctx context.Context) (*zkTypes.L2BridgeContracts, error) -``` - -#### Example - -```go -contracts, err := wallet.L2BridgeContracts(context.Background()) -if err != nil { - log.Panic(err) -} -``` - -### `Withdraw` - -Initiates the withdrawal process which withdraws ETH or any ERC20 token from the associated account on L2 network to the -target account on L1 network. - -#### Inputs - -| Parameter | Type | Description | -| --------- | ------------------------------------------------------------------ | ---------------------------------- | -| `auth` | [`*TransactOpts`](types/accounts.md#transactopts) (optional) | Transaction options. | -| `tx` | [`WithdrawalTransaction`](types/accounts.md#withdrawaltransaction) | Withdrawal transaction parameters. | - -```go -Withdraw(auth *TransactOpts, tx WithdrawalTransaction) (*types.Transaction, error) -``` - -#### Example - -```go -tx, err := wallet.Withdraw(nil, accounts.WithdrawalTransaction{ - To: wallet.Address(), - Amount: big.NewInt(1_000_000_000_000_000_000), - Token: utils.EthAddress, -}) -if err != nil { - panic(err) -} -fmt.Println("Withdraw transaction: ", tx.Hash()) -``` - -### `EstimateGasWithdraw` - -Estimates the amount of gas required for a withdrawal transaction. - -#### Inputs - -| Parameter | Type | Description | -| --------- | ---------------------------------------------------------- | --------------------------- | -| `ctx` | `context.Context` | Context. | -| `msg` | [`WithdrawalCallMsg`](types/accounts.md#withdrawalcallmsg) | Withdrawal call parameters. | - -```go -EstimateGasWithdraw(ctx context.Context, msg WithdrawalCallMsg) (uint64, error) -``` - -#### Example - -```go -gas, err := wallet.EstimateGasWithdraw(context.Background(), accounts.WithdrawalCallMsg{ - To: wallet.Address(), - Amount: big.NewInt(7_000_000), - Token: utils.EthAddress, -}) -if err != nil { - log.Panic(err) -} -fmt.Println("Gas: ", gas) -``` - -### `Transfer` - -Moves the ETH or any ERC20 token from the associated account to the target account. - -#### Inputs - -| Parameter | Type | Description | -| --------- | -------------------------------------------------------------- | -------------------------------- | -| `auth` | [`*TransactOpts`](types/accounts.md#transactopts) (optional) | Transaction options. | -| `tx` | [`TransferTransaction`](types/accounts.md#transfertransaction) | Transfer transaction parameters. | - -```go -Transfer(auth *TransactOpts, tx TransferTransaction) (*types.Transaction, error) -``` - -#### Example - -```go -tx, err := w.Transfer(nil, accounts.TransferTransaction{ - To: common.HexToAddress(""), - Amount: big.NewInt(7_000_000_000), - Token: utils.EthAddress, -}) -if err != nil { - log.Panic(err) -} -fmt.Println("Transaction: ", tx.Hash()) -``` - -### `EstimateGasTransfer` - -Estimates the amount of gas required for a transfer transaction. - -#### Inputs - -| Parameter | Type | Description | -| --------- | ------------------------------------------------------ | ------------------------- | -| `ctx` | `context.Context` | Context. | -| `msg` | [`TransferCallMsg`](types/accounts.md#transfercallmsg) | Transfer call parameters. | - -```go -EstimateGasTransfer(ctx context.Context, msg TransferCallMsg) (uint64, error) -``` - -#### Example - -```go -gas, err := wallet.EstimateGasTransfer(context.Background(), accounts.TransferCallMsg{ - To: common.HexToAddress(""), - Amount: big.NewInt(7_000_000_000), - Token: utils.EthAddress, -}) -if err != nil { - log.Panic(err) -} -fmt.Println("Gas: ", gas) -``` - -### `CallContract` - -Executes a message call for EIP-712 transaction, which is directly executed in the VM of the node, but never mined into -the blockchain. - -#### Inputs - -| Parameter | Type | Description | -| ------------- | -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `ctx` | `context.Context` | Context. | -| `msg` | [`CallMsg`](types/accounts.md#callmsg) | Contains parameters for contract call using EIP-712 transaction. | -| `blockNumber` | `*big.Int` (optional) | Selects the block height at which the call runs. It can be `nil`, in which case the code is taken from the latest known block. Note that state from very old blocks might not be available. | - -```go -CallContract(ctx context.Context, msg CallMsg, blockNumber *big.Int) ([]byte, error) -``` - -#### Example - -```go -// The Crown token on testnet -TokenAddress := common.HexToAddress("0x927488F48ffbc32112F1fF721759649A89721F8F") - -tokenAbi, err := erc20.IERC20MetaData.GetAbi() -if err != nil { - log.Panic(err) -} -symbolCalldata, err := tokenAbi.Pack("symbol") -if err != nil { - log.Panic(err) -} - -result, err := wallet.CallContract(context.Background(), types.CallMsg{ - CallMsg: ethereum.CallMsg{ - To: &TokenAddress, - Data: symbolCalldata, - }, -}, nil) -if err != nil { - log.Panic(err) -} -unpack, err := tokenAbi.Unpack("symbol", result) -if err != nil { - log.Panic(err) -} -symbol := *abi.ConvertType(unpack[0], new(string)).(*string) -fmt.Println("Symbol: ", symbol) -``` - -### PopulateTransaction - -Designed for users who prefer a simplified approach by providing only the necessary data to create a valid -[EIP-712 transaction](types/types.md#transaction712). The only required fields are `Transaction.To` and either -`Transaction.Data` or `Transaction.Value` (or both, if the method is payable). Any other fields that are not set will be -prepared by this method. - -#### Inputs - -| Parameter | Type | Description | -| --------- | ---------------------------------------------- | ----------------------- | -| `ctx` | `context.Context` | Context. | -| `tx` | [`Transaction`](types/accounts.md#transaction) | Transaction parameters. | - -```go -PopulateTransaction(ctx context.Context, tx Transaction) (*zkTypes.Transaction712, error) -``` - -#### Example - -```go -// The Crown token on testnet -TokenAddress := common.HexToAddress("0x927488F48ffbc32112F1fF721759649A89721F8F") -// Paymaster for Crown token on testnet -PaymasterAddress := common.HexToAddress("0x13D0D8550769f59aa241a41897D4859c87f7Dd46") -ReceiptAddress := common.HexToAddress("0xa61464658AfeAf65CccaaFD3a512b69A83B77618") - -abi, err := erc20.IERC20MetaData.GetAbi() -if err != nil { - log.Panic(err) -} - -// Encode transfer function from token contract -calldata, err := abi.Pack("transfer", ReceiptAddress, big.NewInt(7)) -if err != nil { - log.Panic(err) -} - -preparedTx, err := wallet.PopulateTransaction(context.Background(), &accounts.Transaction{ - To: &TokenAddress, - Data: calldata, -}) -fmt.Printf("Prepared tx: %+v\n", preparedTx) -``` - -### `SignTransaction` - -Returns a signed transaction that is ready to be broadcast to the network. The input transaction must be a valid -transaction with all fields having appropriate values. To obtain a valid transaction, you can use the -[`PopulateTransaction`](#populatetransaction) method. - -#### Inputs - -| Parameter | Type | Description | -| --------- | --------------------------------------------------------- | ------------------------------- | -| `tx` | [`zkTypes.Transaction712`](types/types.md#transaction712) | EIP-712 transaction parameters. | - -```go -SignTransaction(tx *zkTypes.Transaction712) ([]byte, error) -``` - -#### Example - -```go -// The Crown token on testnet -TokenAddress := common.HexToAddress("0x927488F48ffbc32112F1fF721759649A89721F8F") -// Paymaster for Crown token on testnet -PaymasterAddress := common.HexToAddress("0x13D0D8550769f59aa241a41897D4859c87f7Dd46") -ReceiptAddress := common.HexToAddress("0xa61464658AfeAf65CccaaFD3a512b69A83B77618") - -abi, err := erc20.IERC20MetaData.GetAbi() -if err != nil { - log.Panic(err) -} - -// Encode transfer function from token contract -calldata, err := abi.Pack("transfer", ReceiptAddress, big.NewInt(7)) -if err != nil { - log.Panic(err) -} - -preparedTx, err := wallet.PopulateTransaction(context.Background(), &accounts.Transaction{ - To: &TokenAddress, - Data: calldata, -}) - -signedTx, err := wallet.SignTransaction(preparedTx) -if err != nil { - log.Panic(err) -} -fmt.Printf("Signed tx: %+v\n", signedTx) -``` - -### `SendTransaction` - -Injects a transaction into the pending pool for execution. Any unset transaction fields are prepared using the -PopulateTransaction method. - -#### Inputs - -| Parameter | Type | Description | -| --------- | ---------------------------------------------- | ----------------------- | -| `ctx` | `context.Context` | Context. | -| `tx` | [`Transaction`](types/accounts.md#transaction) | Transaction parameters. | - -```go -SendTransaction(ctx context.Context, tx *Transaction) (common.Hash, error) -``` - -#### Example - -```go -// The Crown token on testnet -TokenAddress := common.HexToAddress("0x927488F48ffbc32112F1fF721759649A89721F8F") -// Paymaster for Crown token on testnet -PaymasterAddress := common.HexToAddress("0x13D0D8550769f59aa241a41897D4859c87f7Dd46") -ReceiptAddress := common.HexToAddress("0xa61464658AfeAf65CccaaFD3a512b69A83B77618") - -abi, err := erc20.IERC20MetaData.GetAbi() -if err != nil { - log.Panic(err) -} - -// Encode transfer function from token contract -calldata, err := abi.Pack("transfer", ReceiptAddress, big.NewInt(7)) -if err != nil { - log.Panic(err) -} - -// Create paymaster parameters with encoded paymaster input -paymasterParams, err := utils.GetPaymasterParams( - PaymasterAddress, - &zkTypes.ApprovalBasedPaymasterInput{ - Token: TokenAddress, - MinimalAllowance: big.NewInt(1), - InnerInput: []byte{}, - }) -if err != nil { - log.Panic(err) -} - -hash, err := wallet.SendTransaction(context.Background(), &accounts.Transaction{ - To: &TokenAddress, - Data: calldata, - Meta: &types.Eip712Meta{ - PaymasterParams: paymasterParams, - }, -}) -if err != nil { - log.Panic(err) -} - -_, err = client.WaitMined(context.Background(), hash) -if err != nil { - log.Panic(err) -} - -fmt.Println("Tx: ", hash) -``` - -## `BaseDeployer` - -### `Init` - -Creates an instance of `BaseDeployer` based on provided `AdapterL2`. - -```go -func NewBaseDeployer(adapter *AdapterL2) *BaseDeployer -``` - -### `Deploy` - -Deploys smart contract using CREATE2 opcode. - -#### Inputs - -| Parameter | Type | Description | -| --------- | ------------------------------------------------------------ | ------------------------------- | -| `auth` | [`*TransactOpts`](types/accounts.md#transactopts) (optional) | Transaction options. | -| `tx` | [`Create2Transaction`](types/accounts.md#create2transaction) | CREATE2 transaction parameters. | - -```go -Deploy(auth *TransactOpts, tx Create2Transaction) (common.Hash, error) -``` - -#### Example - -```go -bytecode, err := os.ReadFile("Storage.zbin") -if err != nil { - log.Panic(err) -} - -//Deploy smart contract -hash, err := w.Deploy(nil, accounts.Create2Transaction{Bytecode: bytecode}) -if err != nil { - panic(err) -} -fmt.Println("Transaction: ", hash) -``` - -### `DeployWithCreate` - -Deploys smart contract using CREATE opcode. - -#### Inputs - -| Parameter | Type | Description | -| --------- | ------------------------------------------------------------ | ------------------------------ | -| `auth` | [`*TransactOpts`](types/accounts.md#transactopts) (optional) | Transaction options. | -| `tx` | [`CreateTransaction`](types/accounts.md#createtransaction) | CREATE transaction parameters. | - -```go -DeployWithCreate(auth *TransactOpts, tx CreateTransaction) (common.Hash, error) -``` - -#### Example - -```go -bytecode, err := os.ReadFile("Storage.zbin") -if err != nil { - log.Panic(err) -} - -//Deploy smart contract -hash, err := w.DeployWithCreate(nil, accounts.CreateTransaction{Bytecode: bytecode}) -if err != nil { - panic(err) -} -fmt.Println("Transaction: ", hash) -``` - -### `DeployAccount` - -Deploys smart account using CREATE2 opcode. - -#### Inputs - -| Parameter | Type | Description | -| --------- | ------------------------------------------------------------ | ------------------------------- | -| `auth` | [`*TransactOpts`](types/accounts.md#transactopts) (optional) | Transaction options. | -| `tx` | [`Create2Transaction`](types/accounts.md#create2transaction) | CREATE2 transaction parameters. | - -```go -DeployAccount(auth *TransactOpts, tx Create2Transaction) (common.Hash, error) -``` - -#### Example - -```go -# Crown token on testnet -TokenAddress := common.HexToAddress("0x927488F48ffbc32112F1fF721759649A89721F8F") - -_, paymasterAbi, bytecode, err := utils.ReadStandardJson("Paymaster.json") -if err != nil { - log.Panic(err) -} - -// Encode paymaster constructor -constructor, err := paymasterAbi.Pack("", common.HexToAddress(TokenAddress)) -if err != nil { - log.Panic(err) -} - -// Deploy paymaster contract -hash, err := w.DeployAccount(nil, accounts.Create2Transaction{Bytecode: bytecode, Calldata: constructor}) -if err != nil { - log.Panic(err) -} -if err != nil { - log.Panic(err) -} -fmt.Println("Transaction: ", hash) - -``` - -### `DeployAccountWithCreate` - -Deploys smart account using CREATE opcode. - -#### Inputs - -| Parameter | Type | Description | -| --------- | ------------------------------------------------------------ | ------------------------------ | -| `auth` | [`*TransactOpts`](types/accounts.md#transactopts) (optional) | Transaction options. | -| `tx` | [`CreateTransaction`](types/accounts.md#createtransaction) | CREATE transaction parameters. | - -```go -DeployAccountWithCreate(auth *TransactOpts, tx CreateTransaction) (common.Hash, error) -``` - -#### Example - -```go -# Crown token on testnet -TokenAddress := common.HexToAddress("0x927488F48ffbc32112F1fF721759649A89721F8F") - -_, paymasterAbi, bytecode, err := utils.ReadStandardJson("Paymaster.json") -if err != nil { - log.Panic(err) -} - -constructor, err := paymasterAbi.Pack("", common.HexToAddress(TokenAddress)) -if err != nil { - log.Panic(err) -} - -// Deploy paymaster contract -hash, err := w.DeployAccountWithCreate(nil, accounts.CreateTransaction{ - Bytecode: bytecode, - Calldata: constructor, -}) -if err != nil { - log.Panic(err) -} -fmt.Println("Transaction: ", hash) -``` - -## `Wallet` - -It contains the same functions as [`WalletL1`](#walletl1), [`WalletL2`](#walletl2), and [`BaseDeployer`](#basedeployer) -since it implements the Adapter interface, and the usage of those methods is the same. - -### `Init` - -Creates an instance of `Wallet` associated with the account provided by the `rawPrivateKey`. The `clientL1` parameters -is optional; if not provided, only methods from `AdapterL2` and `Deployer` interfaces can be used, as the rest of the -functionalities require communication with the L1 network. A `Wallet` can be configured to communicate with L1 networks -by using and [`ConnectL1`](#connectl1) method. - -```go -func NewWallet(rawPrivateKey []byte, clientL2 *clients.Client, clientL1 *ethclient.Client) (*Wallet, error) -``` - -Creates an instance of Wallet associated with the account provided by the signer. The `clientL2` and `clientL1` -parameters are optional; if not provided, only `SignTransaction`, `Address` and `Signer` methods can be used, as the -rest of the functionalities require communication with the network. A wallet that contains only a signer can be -configured to communicate with L2 and L1 networks by using [`Connect`](#connect) and [`ConnectL1`](#connectl1), -respectively. - -```go -func NewWalletFromSigner(signer Signer, clientL2 *clients.Client, clientL1 *ethclient.Client) (*Wallet, error) -``` - -Creates a new instance of `Wallet` based on the provided mnemonic phrase. The `clientL2` and `clientL1` parameters are -optional, and can be configured with [`Connect`](#connect) and [`ConnectL1`](#connectl1), respectively. - -```go -func NewWalletFromMnemonic(mnemonic string, chainId int64, clientL2 *clients.Client, clientL1 *ethclient.Client) (*Wallet, error) -``` - -Creates a new instance of `Wallet` based on the provided private key of the account and chain ID. The `clientL2` and -`clientL1` parameters are optional, and can be configured with [`Connect`](#connect) and [`ConnectL1`](#connectl1), -respectively. - -```go -func NewWalletFromRawPrivateKey(rawPk []byte, chainId int64, clientL2 *clients.Client, clientL1 *ethclient.Client) (*Wallet, error) -``` - -Creates an instance of `Wallet` with a randomly generated account. The `clientL2` and `clientL1` parameters are -optional, and can be configured with [`Connect`](#connect) and [`ConnectL1`](#connectl1), respectively. - -```go -func NewRandomWallet(chainId int64, clientL2 *clients.Client, clientL1 *ethclient.Client) (*Wallet, error) -``` - -#### Example - -```go -PrivateKey := os.Getenv("PRIVATE_KEY") -ZkSyncEraProvider := "https://sepolia.era.zksync.dev" -EthereumProvider := "https://rpc.ankr.com/eth_sepolia" - -client, err := clients.Dial(ZkSyncEraProvider) -if err != nil { - log.Panic(err) -} -defer client.Close() - -ethClient, err := ethclient.Dial(EthereumProvider) -if err != nil { - log.Panic(err) -} -defer ethClient.Close() - -wallet, err := accounts.NewWallet(common.Hex2Bytes(PrivateKey), &client, ethClient) -if err != nil { - log.Panic(err) -} - -chainID, err := client.ChainID(context.Background()) -if err != nil { - log.Panic(err) -} -wallet, err = accounts.NewRandomWallet(chainID.Int64(),nil,nil) -if err != nil { - log.Panic(err) -} -``` - -### `Connect` - -Returns a new instance of `Wallet` with the provided client for the L2 network. - -#### Inputs - -| Parameter | Type | Description | -| --------- | ------------------------------- | ----------- | -| `client` | [`*clients.Client`](clients.md) | L2 client. | - -```go -Connect(client *clients.Client) (*Wallet, error) -``` - -#### Example - -```go -PrivateKey := os.Getenv("PRIVATE_KEY") -ZkSyncEraProvider := "https://testnet.era.zksync.dev" - -client, err := clients.Dial(ZkSyncEraProvider) -if err != nil { - log.Panic(err) -} -defer client.Close() - -chainID, err := client.ChainID(context.Background()) -if err != nil { - log.Panic(err) -} - -wallet, err := accounts.NewRandomWallet(chainID, nil, nil) -if err != nil { - log.Panic(err) -} - -// create new wallet with connection to L2 -walleet, err = wallet.Connect(&client) -if err != nil { - log.Panic(err) -} -``` - -### `ConnectL1` - -Returns a new instance of `Wallet` with the provided client for the L1 network. - -#### Inputs - -| Parameter | Type | Description | -| --------- | -------------------------------------------------------------------------------------------------- | ----------- | -| `client` | [`*ethclient.Client`](https://pkg.go.dev/github.com/ethereum/go-ethereum@v1.12.0/ethclient#Client) | L1 client. | - -```go -ConnectL1(client *ethclient.Client) (*Wallet, error) -``` - -#### Example - -```go -PrivateKey := os.Getenv("PRIVATE_KEY") -ZkSyncEraProvider := "https://sepolia.era.zksync.dev" -EthereumProvider := "https://rpc.ankr.com/eth_sepolia" - -client, err := clients.Dial(ZkSyncEraProvider) -if err != nil { - log.Panic(err) -} -defer client.Close() - -chainID, err := client.ChainID(context.Background()) -if err != nil { - log.Panic(err) -} - -wallet, err := accounts.NewRandomWallet(chainID, nil, nil) -if err != nil { - log.Panic(err) -} - -ethClient, err := ethclient.Dial(EthereumProvider) -if err != nil { - log.Panic(err) -} -defer ethClient.Close() - -// create new wallet with connection to L1 -w, err = w.Connect(ðClient) -if err != nil { - log.Panic(err) -} -``` - -### `Nonce` - -Returns the account nonce of the associated account. The block number can be `nil`, in which case the nonce is taken -from the latest known block. - -#### Inputs - -| Parameter | Type | Description | -| ------------- | --------------------- | ------------- | -| `ctx` | `context.Context` | Context. | -| `blockNumber` | `*big.Int` (optional) | Block number. | - -```go -Nonce(ctx context.Context, blockNumber *big.Int) (uint64, error) -``` - -#### Example - -```go -nonce, err := wallet.Nonce(context.Background(), big.NewInt(9000)) -if err != nil { - log.Panic(err) -} -fmt.Println("Nonce: ", nonce) -``` - -### `PendingNonce` - -Returns the account nonce of the associated account in the pending state. This is the nonce that should be used for the -next transaction. - -#### Inputs - -| Parameter | Type | Description | -| --------- | ----------------- | ----------- | -| `ctx` | `context.Context` | Context. | - -```go -PendingNonce(ctx context.Context) (uint64, error) -``` - -#### Example - -```go -nonce, err := wallet.PendingNonce(context.Background()) -if err != nil { - log.Panic(err) -} -fmt.Println("Nonce: ", nonce) -``` diff --git a/content/20.build/sdks/go/clients.md b/content/20.build/sdks/go/clients.md deleted file mode 100644 index 2fdd22ad..00000000 --- a/content/20.build/sdks/go/clients.md +++ /dev/null @@ -1,1038 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Go SDK Clients | zkSync Docs ---- - -# Clients - -:::info Note Since the `geth` library has the concept of a `Client`, not a `Provider`, that's why the Go SDK for zkSync -Era also adopts the concept of a `Client`, as opposed to using a Provider like in the other zkSync Era SDKs. ::: - -`Client` is a wrapper around the zkSync Era RPC API, which supports `ethclient.Client` from the `geth` library and -additional methods specific to zkSync Era. - -`Client` in code represents the interface that is composed of the following two interfaces: - -- `EthereumClient` provides Ethereum RPC methods on the zkSync Era node, those with the `eth_` prefix. This interface - contains the same methods as `ethclient.Client` from the `geth` library. Additionally, it has extra methods capable of - working with EIP-712 transactions. It is designed to be compatible with the `bind.ContractBackend` interface from - `geth`, enabling support for smart contracts generated using the `abigen` tool. -- `ZkSyncEraClient` provides the API for zkSync Era features and specific RPC methods, those with the `zks_` prefix. - -These interfaces are separated to make the SDK more flexible and extensible. - -## `BaseClient` - -`BaseClient` implements the `Client` interface and provides interaction with zkSync Era RPC API. - -### `Init` - -`Dial` connects a client to the given URL. - -```go -func Dial(rawUrl string) (Client, error) -``` - -`DialContext` connects a client to the given URL with context. - -```go -func DialContext(ctx context.Context, rawUrl string) (Client, error) -``` - -`NewClient` creates a client that uses the given RPC client. - -```go -func NewClient(c *rpc.Client) Client -``` - -#### Example - -```go -ZkSyncEraProvider := "https://testnet.era.zksync.dev" -ZkSyncEraWSProvider := "ws://testnet.era.zksync.dev:3051" - -// Connect to zkSync network -client, err := clients.Dial(ZkSyncEraProvider) -if err != nil { - log.Panic(err) -} -defer client.Close() - -// Connect to zkSync network using Web Socket -wsClient, err := clients.Dial(ZkSyncEraWSProvider) -if err != nil { - log.Panic(err) -} -defer wsClient.Close() -``` - -### `FilterLogsL2` - -Executes a log filter operation, blocking during execution, and returns all the results in one batch. This method is a -replacement for `FilterLogs` because the returned `types.Log` type does not contain additional data specific to L2, as -found in [`Log`](types/types.md#log). The `FilterLogs` method is kept in order to be compatible with -`bind.ContractBackend`, and this method can be used, but additional L2 data won't be retrieved. - -#### Inputs - -| Parameter | Type | Description | -| --------- | ------------------------------------------------------------------------------------------------ | ------------------------ | -| `ctx` | `context.Context` | Context. | -| `query` | [`ethereum.FilterQuery`](https://pkg.go.dev/github.com/ethereum/go-ethereum@v1.12.0#FilterQuery) | Filter query parameters. | - -```go -FilterLogsL2(ctx context.Context, query ethereum.FilterQuery) ([]zkTypes.Log, error) -``` - -#### Example - -```go -contracts, err := client.BridgeContracts(context.Background()) -if err != nil { - log.Panic(err) -} -zkLogs, err := client.FilterLogsL2(context.Background(), ethereum.FilterQuery{ - FromBlock: big.NewInt(0), - ToBlock: big.NewInt(1000), - Addresses: []common.Address{contracts.L2Erc20DefaultBridge}, -}) -if err != nil { - log.Panic(err) -} - -for _, l := range zkLogs { - fmt.Println("Log address:", l.Address.Hex()) - fmt.Println("Log data:", l.Data) - fmt.Println("L1 batch number: ", l.L1BatchNumber) -} -``` - -### `SubscribeFilterLogsL2` - -Creates a background log filtering operation, returning a subscription immediately, which can be used to stream the -found events. This method is a replacement for `SubscribeFilterLogs` because the returned `types.Log` type does not -contain additional data specific to L2, as found in [`Log`](types/types.md#log). The `SubscribeFilterLogs` method is -kept in order to be compatible with `bind.ContractBackend`, and this method can be used, but additional L2 data won't be -retrieved. - -#### Inputs - -| Parameter | Type | Description | -| --------- | ------------------------------------------------------------------------------------------------ | -------------------------- | -| `ctx` | `context.Context` | Context. | -| `query` | [`ethereum.FilterQuery`](https://pkg.go.dev/github.com/ethereum/go-ethereum@v1.12.0#FilterQuery) | Filter query parameters. | -| `ch` | [`chan<- zkTypes.Log`](types/types.md#log) | Channel that receives Log. | - -```go -SubscribeFilterLogsL2(ctx context.Context, query ethereum.FilterQuery, ch chan<- zkTypes.Log) (ethereum.Subscription, error) -``` - -#### Example - -```go -contracts, err := client.BridgeContracts(context.Background()) -if err != nil { - log.Panic(err) -} - -filterLogs := make(chan zkTypes.Log) -sub, err := wsClient.SubscribeFilterLogsL2(context.Background(), ethereum.FilterQuery{ - FromBlock: big.NewInt(0), - ToBlock: big.NewInt(1000), - Addresses: []common.Address{contracts.L2Erc20DefaultBridge}, -}, filterLogs) -if err != nil { - log.Panic(err) -} -defer sub.Unsubscribe() - -for { - select { - case err := <-sub.Err(): - log.Println(err) - break - case l := <-filterLogs: - fmt.Println("Address: ", l.Address) - fmt.Println("Data", l.Data) - } -} -``` - -### `CallContractL2` - -Executes a message call for EIP-712 transaction, which is directly executed in the VM of the node, but never mined into -the blockchain. - -#### Inputs - -| Parameter | Type | Description | -| ------------- | ------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `ctx` | `context.Context` | Context. | -| `msg` | [`zkTypes.CallMsg`](types/types.md#callmsg) | Contains parameters for contract call using EIP-712 transaction. | -| `blockNumber` | `*big.Int` (optional) | Selects the block height at which the call runs. It can be `nil`, in which case the code is taken from the latest known block. Note that state from very old blocks might not be available. | - -```go -CallContractL2(ctx context.Context, msg zkTypes.CallMsg, blockNumber *big.Int) ([]byte, error) -``` - -#### Example - -```go -// The Crown token on testnet -TokenAddress := common.HexToAddress("0x927488F48ffbc32112F1fF721759649A89721F8F") - -tokenAbi, err := erc20.IERC20MetaData.GetAbi() -if err != nil { - log.Panic(err) -} -symbolCalldata, err := tokenAbi.Pack("symbol") -if err != nil { - log.Panic(err) -} - -result, err := client.CallContractL2(context.Background(), types.CallMsg{ - CallMsg: ethereum.CallMsg{ - To: &TokenAddress, - Data: symbolCalldata, - }, -}, nil) -if err != nil { - log.Panic(err) -} -unpack, err := tokenAbi.Unpack("symbol", result) -if err != nil { - log.Panic(err) -} -symbol := *abi.ConvertType(unpack[0], new(string)).(*string) -fmt.Println("Symbol: ", symbol) -``` - -### `CallContractAtHashL2` - -Almost the same as [`CallContractL2`](#callcontractl2) except that it selects the block by block hash instead of block -height. - -#### Inputs - -| Parameter | Type | Description | -| ----------- | ------------------------------------------- | ---------------------------------------------------------------- | -| `ctx` | `context.Context` | Context. | -| `msg` | [`zkTypes.CallMsg`](types/types.md#callmsg) | Contains parameters for contract call using EIP-712 transaction. | -| `blockHash` | `common.Hash` | Block hash. | - -```go -CallContractAtHashL2(ctx context.Context, msg zkTypes.CallMsg, blockHash common.Hash) ([]byte, error) -``` - -### `PendingCallContractL2` - -Almost the same as [`CallContractL2`](#callcontractl2) except that the state seen by the contract call is the pending -state. - -#### Inputs - -| Parameter | Type | Description | -| --------- | ------------------------------------------- | ---------------------------------------------------------------- | -| `ctx` | `context.Context` | Context. | -| `msg` | [`zkTypes.CallMsg`](types/types.md#callmsg) | Contains parameters for contract call using EIP-712 transaction. | - -```go -PendingCallContractL2(ctx context.Context, msg zkTypes.CallMsg) ([]byte, error) -``` - -### `EstimateGasL2` - -Tries to estimate the gas needed to execute an EIP-712 transaction based on the current pending state of the backend -blockchain. There is no guarantee that this is the true gas limit requirement as other transactions may be added or -removed by miners, but it should provide a basis for setting a reasonable default. - -#### Inputs - -| Parameter | Type | Description | -| --------- | ------------------------------------------- | ---------------------------------------------------------------- | -| `ctx` | `context.Context` | Context. | -| `msg` | [`zkTypes.CallMsg`](types/types.md#callmsg) | Contains parameters for contract call using EIP-712 transaction. | - -```go -EstimateGasL2(ctx context.Context, msg zkTypes.CallMsg) (uint64, error) -``` - -#### Example - -```go -// The Crown token on testnet -TokenAddress := common.HexToAddress("0x927488F48ffbc32112F1fF721759649A89721F8F") -// Paymaster for Crown token on testnet -PaymasterAddress := common.HexToAddress("0x13D0D8550769f59aa241a41897D4859c87f7Dd46") -ReceiptAddress := common.HexToAddress("0xa61464658AfeAf65CccaaFD3a512b69A83B77618") - -abi, err := erc20.IERC20MetaData.GetAbi() -if err != nil { - log.Panic(err) -} - -// Encode transfer function from token contract -calldata, err := abi.Pack("transfer", ReceiptAddress, big.NewInt(7)) -if err != nil { - log.Panic(err) -} - -// Create paymaster parameters with encoded paymaster input -paymasterParams, err := utils.GetPaymasterParams( - PaymasterAddress, - &zkTypes.ApprovalBasedPaymasterInput{ - Token: TokenAddress, - MinimalAllowance: big.NewInt(1), - InnerInput: []byte{}, - }) -if err != nil { - log.Panic(err) -} - -gas, err := client.EstimateGasL2(context.Background(), zkTypes.CallMsg{ - CallMsg: ethereum.CallMsg{ - To: &TokenAddress, - Data: calldata, - }, - Meta: &zkTypes.Eip712Meta{ - PaymasterParams: paymasterParams, - }, -}) -if err != nil { - log.Panic(err) -} -fmt.Println("Gas: ", gas) -``` - -### `SendRawTransaction` - -Injects a signed raw transaction into the pending pool for execution. Is meant to be used for sending EIP-712 -transaction, - -#### Inputs - -| Parameter | Type | Description | -| --------- | ----------------- | ---------------- | -| `ctx` | `context.Context` | Context. | -| `tx` | `[]byte` | Raw transaction. | - -```go -SendRawTransaction(ctx context.Context, tx []byte) (common.Hash, error) -``` - -#### Example - -```go -// The Crown token on testnet -TokenAddress := common.HexToAddress("0x927488F48ffbc32112F1fF721759649A89721F8F") -// Paymaster for Crown token on testnet -PaymasterAddress := common.HexToAddress("0x13D0D8550769f59aa241a41897D4859c87f7Dd46") -ReceiptAddress := common.HexToAddress("0xa61464658AfeAf65CccaaFD3a512b69A83B77618") - -w, err := accounts.NewWallet(common.Hex2Bytes(), &client, nil) -if err != nil { - log.Panic(err) -} - -abi, err := erc20.IERC20MetaData.GetAbi() -if err != nil { - log.Panic(err) -} - -// Encode mint function from token contract -calldata, err := abi.Pack("transfer", ReceiptAddress, big.NewInt(7)) -if err != nil { - log.Panic(err) -} - -// Create paymaster parameters with encoded paymaster input -paymasterParams, err := utils.GetPaymasterParams( - PaymasterAddress, - &zkTypes.ApprovalBasedPaymasterInput{ - Token: TokenAddress, - MinimalAllowance: big.NewInt(1), - InnerInput: []byte{}, - }) -if err != nil { - log.Panic(err) -} - -hash, err := w.SendTransaction(context.Background(), &accounts.Transaction{ - To: &TokenAddress, - Data: calldata, - Meta: &zkTypes.Eip712Meta{ - PaymasterParams: paymasterParams, - }, -}) -if err != nil { - log.Panic(err) -} -fmt.Println("Tx: ", hash) -``` - -### `WaitMined` - -Waits for transaction to be mined on the L2. It stops waiting when the context is canceled. - -#### Inputs - -| Parameter | Type | Description | -| --------- | ----------------- | ----------------- | -| `ctx` | `context.Context` | Context. | -| `txHash` | `common.Hash` | Transaction hash. | - -```go -WaitMined(ctx context.Context, txHash common.Hash) (*zkTypes.Receipt, error) -``` - -#### Example - -```go -// Create wallet -w, err := accounts.NewWallet(common.Hex2Bytes(), &client, nil) -if err != nil { - log.Panic(err) -} - -tx, err := w.Transfer(accounts.TransferTransaction{ - To: common.HexToAddress(
), - Amount: big.NewInt(7_000_000_000), - Token: utils.EthAddress, -}) -if err != nil { - log.Panic(err) -} - -// Wait for transaction to be mined on L2 network -_, err = client.WaitMined(context.Background(), tx.Hash()) -if err != nil { - log.Panic(err) -} -``` - -### `WaitFinalized` - -Waits for tx to be finalized on the L2. It stops waiting when the context is canceled. - -#### Inputs - -| Parameter | Type | Description | -| --------- | ----------------- | ----------------- | -| `ctx` | `context.Context` | Context. | -| `txHash` | `common.Hash` | Transaction hash. | - -```go -WaitFinalized(ctx context.Context, txHash common.Hash) (*zkTypes.Receipt, error) -``` - -#### Example - -```go -// Create wallet -w, err := accounts.NewWallet(common.Hex2Bytes(), &client, nil) -if err != nil { - log.Panic(err) -} - -tx, err := w.Transfer(accounts.TransferTransaction{ - To: common.HexToAddress(
), - Amount: big.NewInt(7_000_000_000), - Token: utils.EthAddress, -}) -if err != nil { - log.Panic(err) -} - -// Wait for transaction to be finalized on L2 network -_, err = client.WaitFinalized(context.Background(), tx.Hash()) -if err != nil { - log.Panic(err) -} -``` - -### `MainContractAddress` - -Returns the address of the zkSync Era contract. - -#### Inputs - -| Parameter | Type | Description | -| --------- | ----------------- | ----------- | -| `ctx` | `context.Context` | Context. | - -```go -MainContractAddress(ctx context.Context) (common.Address, error) -``` - -#### Example - -```go -address, err := client.MainContractAddress(context.Background()) -if err != nil { - log.Panic() -} -fmt.Println("Main contract address: ", address) -``` - -### `TestnetPaymaster` - -Returns the testnet paymaster address if available, or `nil`. - -#### Inputs - -| Parameter | Type | Description | -| --------- | ----------------- | ----------- | -| `ctx` | `context.Context` | Context. | - -```go -TestnetPaymaster(ctx context.Context) (common.Address, error) -``` - -#### Example - -```go -address, err := client.TestnetPaymaster(context.Background()) -if err != nil { - log.Panic() -} -fmt.Println("Testnet paymaster address: ", address) -``` - -### `BridgeContracts` - -Returns the addresses of the default zkSync Era bridge contracts on both L1 and L2. - -#### Inputs - -| Parameter | Type | Description | -| --------- | ----------------- | ----------- | -| `ctx` | `context.Context` | Context. | - -```go -BridgeContracts(ctx context.Context) (*zkTypes.BridgeContracts, error) -``` - -#### Example - -```go -contracts, err := client.BridgeContracts(context.Background()) -if err != nil { - log.Panic(err) -} -fmt.Println("Bridge contracts: ", contracts) -``` - -### `ContractAccountInfo` - -Returns the version of the supported account abstraction and nonce ordering from a given contract address. - -#### Inputs - -| Parameter | Type | Description | -| --------- | ----------------- | ----------------- | -| `ctx` | `context.Context` | Context. | -| `address` | `common.Address` | Contract address. | - -```go -ContractAccountInfo(ctx context.Context, address common.Address) (*zkTypes.ContractAccountInfo, error) -``` - -#### Example - -```go -// Paymaster for Crown token on testnet -PaymasterAddress := common.HexToAddress("0x13D0D8550769f59aa241a41897D4859c87f7Dd46") -accountInfo, err := client.ContractAccountInfo(context.Background(), PaymasterAddress) -if err != nil { - log.Panic() -} -fmt.Printf("Account info: %+v\n", accountInfo) -``` - -### `L1ChainID` - -Returns the chain id of the underlying L1. - -#### Inputs - -| Parameter | Type | Description | -| --------- | ----------------- | ----------- | -| `ctx` | `context.Context` | Context. | - -```go -L1ChainID(ctx context.Context) (*big.Int, error) -``` - -#### Example - -```go -l1ChainID, err := client.L1ChainID(context.Background()) -if err != nil { - log.Panic() -} -fmt.Println("L1 chain ID: ", l1ChainID) -``` - -### `L1BatchNumber` - -Returns the latest L1 batch number. - -#### Inputs - -| Parameter | Type | Description | -| --------- | ----------------- | ----------- | -| `ctx` | `context.Context` | Context. | - -```go -L1BatchNumber(ctx context.Context) (*big.Int, error) -``` - -#### Example - -```go -l1BatchNumber, err := client.L1BatchNumber(context.Background()) -if err != nil { - log.Panic() -} -fmt.Println("L1 chain ID: ", l1BatchNumber) -``` - -### `L1BatchBlockRange` - -Returns the range of blocks contained within a batch given by batch number. - -#### Inputs - -| Parameter | Type | Description | -| --------------- | ----------------- | ---------------- | -| `ctx` | `context.Context` | Context. | -| `l1BatchNumber` | `*big.Int` | L1 batch number. | - -```go -L1BatchBlockRange(ctx context.Context, l1BatchNumber *big.Int) (*BlockRange, error) -``` - -#### Example - -```go -batchBlockRange, err := client.L1BatchBlockRange(context.Background(), big.NewInt(83277)) -if err != nil { - log.Panic(err) -} -fmt.Printf("Batch block range: %+v\n", *batchBlockRange) -``` - -### `L1BatchDetails` - -Returns data pertaining to a given batch. - -#### Inputs - -| Parameter | Type | Description | -| --------------- | ----------------- | ---------------- | -| `ctx` | `context.Context` | Context. | -| `l1BatchNumber` | `*big.Int` | L1 batch number. | - -```go -L1BatchDetails(ctx context.Context, l1BatchNumber *big.Int) (*zkTypes.BatchDetails, error) -``` - -#### Example - -```go -batchDetails, err := client.L1BatchDetails(context.Background(), big.NewInt(83277)) -if err != nil { - log.Panic(err) -} -fmt.Printf("Batch details: %+v\n", *batchDetails) -``` - -### `BlockDetails` - -Returns additional zkSync Era-specific information about the L2 block. - -#### Inputs - -| Parameter | Type | Description | -| --------- | ----------------- | ---------------- | -| `ctx` | `context.Context` | Context. | -| `block` | `uint32` | L2 block number. | - -```go -BlockDetails(ctx context.Context, block uint32) (*zkTypes.BlockDetails, error) -``` - -#### Example - -```go -blockDetails, err := client.BlockDetails(context.Background(), 90000) -if err != nil { - log.Panic(err) -} -fmt.Printf("Block details: %+v\n", *blockDetails) -``` - -### `TransactionDetails` - -Returns data from a specific transaction given by the transaction hash. - -#### Inputs - -| Parameter | Type | Description | -| --------- | ----------------- | ----------------- | -| `ctx` | `context.Context` | Context. | -| `txHash` | `common.Hash` | Transaction hash. | - -```go -TransactionDetails(ctx context.Context, txHash common.Hash) (*zkTypes.TransactionDetails, error) -``` - -#### Example - -```go -txHash := common.HexToHash("0x7765b9d5ace5798ab4c1cdd246bbf934cfbf17011dceba844adf207de5bc0a39") -txDetails, err := client.TransactionDetails(context.Background(), txHash) -if err != nil { - log.Panic(err) -} -fmt.Printf("Transaction details: %+v\n", *txDetails) -``` - -### `LogProof` - -Returns the proof for a transaction's L2 to L1 log sent via the L1Messenger system contract. - -#### Inputs - -| Parameter | Type | Description | -| ---------- | ----------------- | ---------------------------------------------------------------- | -| `ctx` | `context.Context` | Context. | -| `txHash` | `common.Hash` | Hash of the L2 transaction the L2 to L1 log was produced within. | -| `logIndex` | `int` | The index of the L2 to L1 log in the transaction. | - -```go -LogProof(ctx context.Context, txHash common.Hash, logIndex int) (*zkTypes.MessageProof, error) -``` - -#### Example - -```go -txHash := common.HexToHash("0x2a1c6c74b184965c0cb015aae9ea134fd96215d2e4f4979cfec12563295f610e") -logProof, err := client.LogProof(context.Background(), txHash, 0) -if err != nil { - log.Panic(err) -} -fmt.Printf("Log proof: %+v\n", *logProof) -``` - -### `L2TransactionFromPriorityOp` - -Returns transaction on L2 network from transaction receipt on L1 network. - -#### Inputs - -| Parameter | Type | Description | -| ------------- | ----------------- | ----------------------- | -| `ctx` | `context.Context` | Context. | -| `l1TxReceipt` | `*types.Receipt` | L1 transaction receipt. | - -```go -L2TransactionFromPriorityOp(ctx context.Context, l1TxReceipt *types.Receipt) (*zkTypes.TransactionResponse, error) -``` - -#### Example - -```go -// Connect to Ethereum network -ethClient, err := ethclient.Dial("https://rpc.ankr.com/eth_sepolia") -if err != nil { - log.Panic(err) -} -defer ethClient.Close() - -txHash := common.HexToHash("0xcca5411f3e514052f4a4ae1c2020badec6e0998adb52c09959c5f5ff15fba3a8") -l1Receipt, err := ethClient.TransactionReceipt(context.Background(), txHash) -if err != nil { - log.Panic(err) -} - -l2Tx, err := client.L2TransactionFromPriorityOp(context.Background(), l1Receipt) -if err != nil { - log.Panic(err) -} -fmt.Printf("L2 transaction: %+v\n", l2Tx) -``` - -### `ConfirmedTokens` - -Returns {address, symbol, name, and decimal} information of all tokens within a range of ids given by parameters from -and limit. - -#### Inputs - -| Parameter | Type | Description | -| --------- | ----------------- | ---------------------------------------------------------------------------- | -| `ctx` | `context.Context` | Context. | -| `from` | `uint32` | The token id from which to start returning the information about the tokens. | -| `limit` | `limit` | The number of tokens to be returned from the API. | - -```go -ConfirmedTokens(ctx context.Context, from uint32, limit uint8) ([]*zkTypes.Token, error) -``` - -#### Example - -```go -// get first 255 tokens -tokens, err := client.ConfirmedTokens(context.Background(), 0, 255) -if err != nil { - log.Panic(err) -} - -for _, token := range tokens { - fmt.Printf("%+v\n", *token) -} -``` - -### `L2TokenAddress` - -Returns the L2 token address equivalent for a L1 token address as they are not equal. ETH address is set to zero -address. - -#### Inputs - -| Parameter | Type | Description | -| --------- | ----------------- | ----------------- | -| `ctx` | `context.Context` | Context. | -| `address` | `common.Address` | L1 token address. | - -```go -L2TokenAddress(ctx context.Context, token common.Address) (common.Address, error) -``` - -#### Example - -```go -l1DAI := common.HexToAddress("0x5C221E77624690fff6dd741493D735a17716c26B") -l2DAI, err := client.L2TokenAddress(context.Background(), l1DAI) -if err != nil { - log.Panic(err) -} -fmt.Println("L2 DAI address: ", l2DAI) -``` - -### `L1TokenAddress` - -Returns the L1 token address equivalent for a L2 token address as they are not equal. ETH address is set to zero -address. - -#### Inputs - -| Parameter | Type | Description | -| --------- | ----------------- | ----------------- | -| `ctx` | `context.Context` | Context. | -| `address` | `common.Address` | L2 token address. | - -```go -L1TokenAddress(ctx context.Context, token common.Address) (common.Address, error) -``` - -#### Example - -```go -l2DAI := common.HexToAddress("0x3e7676937A7E96CFB7616f255b9AD9FF47363D4b") -l1DAI, err := client.L1TokenAddress(context.Background(), l2DAI) -if err != nil { - log.Panic(err) -} -fmt.Println("L2 DAI address: ", l1DAI) -``` - -### `AllAccountBalances` - -Returns all balances for confirmed tokens given by an account address. - -#### Inputs - -| Parameter | Type | Description | -| --------- | ----------------- | ---------------- | -| `ctx` | `context.Context` | Context. | -| `address` | `common.Address` | Account address. | - -```go -AllAccountBalances(ctx context.Context, address common.Address) (map[common.Address]*big.Int, error) -``` - -#### Example - -```go -// Paymaster on testnet -paymaster := common.HexToAddress("0x8f0ea1312da29f17eabeb2f484fd3c112cccdd63") -balances, err := client.AllAccountBalances(context.Background(), paymaster) -if err != nil { - log.Panic(err) -} -fmt.Printf("Balances: %+v\n", balances) -``` - -### `EstimateFee` - -Returns the fee for the transaction. - -#### Inputs - -| Parameter | Type | Description | -| --------- | ------------------------------------------- | ---------------------------------------------------------------- | -| `ctx` | `context.Context` | Context. | -| `msg` | [`zkTypes.CallMsg`](types/types.md#callmsg) | Contains parameters for contract call using EIP-712 transaction. | - -```go -EstimateFee(ctx context.Context, tx zkTypes.CallMsg) (*zkTypes.Fee, error) -``` - -#### Example - -```go -from := common.HexToAddress("") -to := common.HexToAddress("") -fee, err := client.EstimateFee(context.Background(), zkTypes.CallMsg{ - CallMsg: ethereum.CallMsg{ - From: from, - To: &to, - Value: big.NewInt(7_000_000_000), - }, -}) -if err != nil { - log.Panic(err) -} -fmt.Printf("Fee: %+v\n", *fee) -``` - -### `EstimateGasL1` - -Estimates the amount of gas required to submit a transaction from L1 to L2. - -#### Inputs - -| Parameter | Type | Description | -| --------- | ------------------------------------------- | ---------------------------------------------------------------- | -| `ctx` | `context.Context` | Context. | -| `msg` | [`zkTypes.CallMsg`](types/types.md#callmsg) | Contains parameters for contract call using EIP-712 transaction. | - -```go -EstimateGasL1(ctx context.Context, tx zkTypes.CallMsg) (uint64, error) -``` - -#### Example - -```go -account := common.HexToAddress("
") -gas, err := client.EstimateGasL1(context.Background(), zkTypes.CallMsg{ - CallMsg: ethereum.CallMsg{ - From: account, - To: &account, - Value: big.NewInt(7_000_000_000), - }, - Meta: &zkTypes.Eip712Meta{ - GasPerPubdata: utils.NewBig(utils.RequiredL1ToL2GasPerPubdataLimit.Int64()), - }, -}) -if err != nil { - log.Panic(err) -} -fmt.Println("Gas: ", gas) -``` - -### `EstimateGasTransfer` - -Estimates the amount of gas required for a transfer transaction. - -#### Inputs - -| Parameter | Type | Description | -| --------- | ----------------------------------------------------- | -------------------------------------- | -| `ctx` | `context.Context` | Context. | -| `msg` | [`TransferCallMsg`](types/clients.md#transfercallmsg) | Contains parameters for transfer call. | - -```go -EstimateGasTransfer(ctx context.Context, msg TransferCallMsg) (uint64, error) -``` - -#### Example - -```go -gas, err := client.EstimateGasTransfer(context.Background(), clients.TransferCallMsg{ - From: common.HexToAddress(""), - To: common.HexToAddress(""), - Amount: big.NewInt(7_000_000_000), - Token: utils.EthAddress, -}) -if err != nil { - log.Panic(err) -} -fmt.Println("Gas: ", gas) -``` - -### `EstimateGasWithdraw` - -Estimates the amount of gas required for a withdrawal transaction. - -#### Inputs - -| Parameter | Type | Description | -| --------- | --------------------------------------------------------- | ---------------------------------------- | -| `ctx` | `context.Context` | Context. | -| `msg` | [`WithdrawalCallMsg`](types/clients.md#withdrawalcallmsg) | Contains parameters for withdrawal call. | - -```go -EstimateGasWithdraw(ctx context.Context, msg WithdrawalCallMsg) (uint64, error) -``` - -#### Example - -```go -gas, err := client.EstimateGasWithdraw(context.Background(), clients.WithdrawalCallMsg{ - From: common.HexToAddress(""), - To: common.HexToAddress(""), - Amount: big.NewInt(7_000_000_000), - Token: utils.EthAddress, -}) -if err != nil { - log.Panic(err) -} -fmt.Println("Gas: ", gas) -``` - -### `EstimateL1ToL2Execute` - -Estimates the amount of gas required for an L1 to L2 execute operation. - -#### Inputs - -| Parameter | Type | Description | -| --------- | ------------------------------------------- | ---------------------------------------------------------------- | -| `ctx` | `context.Context` | Context. | -| `msg` | [`zkTypes.CallMsg`](types/types.md#callmsg) | Contains parameters for contract call using EIP-712 transaction. | - -```go -EstimateL1ToL2Execute(ctx context.Context, msg zkTypes.CallMsg) (uint64, error) -``` - -#### Example - -```go -account := common.HexToAddress("
") -gas, err := client.EstimateL1ToL2Execute(context.Background(), zkTypes.CallMsg{ - CallMsg: ethereum.CallMsg{ - From: account, - To: &account, - Value: big.NewInt(7_000_000_000), - }, -}) -if err != nil { - log.Panic(err) -} -fmt.Println("Gas: ", gas) -``` diff --git a/content/20.build/sdks/go/contracts.md b/content/20.build/sdks/go/contracts.md deleted file mode 100644 index 93156b7d..00000000 --- a/content/20.build/sdks/go/contracts.md +++ /dev/null @@ -1,30 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Go SDK Contracts | zkSync Docs ---- - -# Contracts - -The usual way to deploy a contract with the `geth` library is to use `abigen` with the provided `--bin` option, which -generates a function that deploys the smart contract. Since the deployment of a smart contract requires an EIP-712 -transaction, the deployment function generated with the `abigen` tool does not work. In this matter, the `Deploy` -interface is created, which provides methods for the deployment of smart contracts and smart accounts. There are the -following objects that implement the `Deploy` interface: - -- [`BaseDeployer`](accounts.md#basedeployer), -- [`Wallet`](accounts.md#wallet). - -Contract instantiation is the same as in the -[`geth`](https://geth.ethereum.org/docs/developers/dapp-developer/native-bindings) library. For examples of how to -deploy and instantiate contracts and accounts, refer to the following: - -- [Deploy smart contracts using CREATE opcode](https://github.com/zksync-sdk/zksync2-examples/blob/main/go/09_deploy_create.go). -- [Deploy smart contracts using CREATE2 opcode](https://github.com/zksync-sdk/zksync2-examples/blob/main/go/12_deploy_create2.go). -- [Deploy smart accounts using CREATE opcode](https://github.com/zksync-sdk/zksync2-examples/blob/main/go/17_deploy_create_account.go). -- [Deploy smart accounts using CREATE2 opcode](https://github.com/zksync-sdk/zksync2-examples/blob/main/go/18_deploy_create2_account.go). - -## Contracts interfaces - -The `contracts` package provides [zkSync Era system contracts](../../developer-reference/system-contracts.md). diff --git a/content/20.build/sdks/go/features.md b/content/20.build/sdks/go/features.md deleted file mode 100644 index 2762e8ad..00000000 --- a/content/20.build/sdks/go/features.md +++ /dev/null @@ -1,129 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Go SDK Features | zkSync Docs ---- - -# zkSync Era Features - -While zkSync Era is mostly Web3-compatible, it has some differences compared to Ethereum. The major of those are: - -- Account abstraction support (accounts may have near-arbitrary validation logic, and also paymaster support is - enabled). -- Deployment transactions require the contracts' bytecode to be passed in a separate field. -- The fee system is somewhat different. - -These require us to extend standard Ethereum transactions with new custom fields. Such extended transactions are called -EIP-712 transactions since [EIP-712](https://eips.ethereum.org/EIPS/eip-712) is used to sign them. You can look at the -internal structure of the EIP-712 transactions [here](../../../zk-stack/concepts/transaction-lifecycle.md#eip-712-0x71). - -This document will focus solely on how to pass these arguments to the SDK. - -## EIP-712 Metadata - -[`EIP712Meta`](types/types.md#eip712meta) contains EIP-712 transaction metadata. The following objects contain -`EIP712Meta` and provides working with EIP-712 transactions: - -- [`types.CallMsg`](types/types.md#callmsg) -- [`types.Transaction712`](types/types.md#transaction712) -- [`accounts.CallMsg`](types/accounts.md#callmsg) -- [`accounts.Transaction`](types/accounts#transaction) - -## Encoding paymaster params - -While the paymaster feature by itself does not impose any limitations on values of the `paymasterInput`, the Matter Labs -team endorses certain types of -[paymaster flows](../../developer-reference/account-abstraction.md#built-in-paymaster-flows) that are processable by -EOAs. - -zkSync SDK provides a utility method that can be used to get the correctly formed `PaymasterParams` object: -[GetPaymasterParams](./paymaster-utils.md#getpaymasterparams). - -## See in action - -If you want to call the method `setGreeting` of a contract called `greeter`, this would look the following way, while -paying fees with the [testnet paymaster](../../developer-reference/account-abstraction.md#testnet-paymaster): - -```go -PrivateKey := os.Getenv("PRIVATE_KEY") -ZkSyncEraProvider := "https://testnet.era.zksync.dev" - -TokenAddress := common.HexToAddress("") -GreeterAddress := common.HexToAddress("") -ReceiptAddress := common.HexToAddress("") - - -client, err := clients.Dial(ZkSyncEraProvider) -if err != nil { - log.Panic(err) -} -defer client.Close() - -// Create wallet -wallet, err := accounts.NewWallet(common.Hex2Bytes(PrivateKey), &client, ethClient) -if err != nil { - log.Panic(err) -} - -abi, err := greeter.GreeterMetaData.GetAbi() -if err != nil { - log.Panic(err) -} - -// Encode transfer function from token contract -calldata, err := abi.Pack("setGreeting") -if err != nil { - log.Panic(err) -} - -gasPrice, err := client.SuggestGasPrice(context.Background()) -if err != nil { - log.Panic(err) -} - -gas, err := client.EstimateGas(context.Background(), ethereum.CallMsg{ - From: wallet.Address(), - To: ReceiptAddress, - Data: calldata, -}) -if err != nil { - log.Panic(err) -} - -testnetPaymaster, err := client.TestnetPaymaster(context.Background()) -if err != nil { - log.Panic(err) -} - -// Create paymaster parameters with encoded paymaster input -paymasterParams, err := utils.GetPaymasterParams( - PaymasterAddress, - &zkTypes.ApprovalBasedPaymasterInput{ - Token: testnetPaymaster, - MinimalAllowance: new(big.Int).Mul(gasPrice, new(big.Int).SetUint64(gas)), - InnerInput: []byte{}, - }) -if err != nil { - log.Panic(err) -} - -hash, err := wallet.SendTransaction(context.Background(), &accounts.Transaction{ - To: &TokenAddress, - Data: calldata, - Meta: &types.Eip712Meta{ - PaymasterParams: paymasterParams, - }, -}) -if err != nil { - log.Panic(err) -} - -_, err = client.WaitMined(context.Background(), hash) -if err != nil { - log.Panic(err) -} - -fmt.Println("Tx: ", hash) - -``` diff --git a/content/20.build/sdks/go/getting-started.md b/content/20.build/sdks/go/getting-started.md deleted file mode 100644 index 4b10350d..00000000 --- a/content/20.build/sdks/go/getting-started.md +++ /dev/null @@ -1,116 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Go SDK Getting Started | zkSync Docs ---- - -# Getting Started - -This is a short introduction to `zksync2-go` SDK, but covers many of the most common operations that developers require -and provides a starting point for those newer to zkSync Era. - -## Getting zksync2-go - -### Prerequisites - -- Go: >=1.17 ([installation guide](https://go.dev/dl/)) - -In order to install SDK for zkSync Era, run the command below in your terminal. - -```shell - go get github.com/zksync-sdk/zksync2-go -``` - -## Overview - -While most of the existing SDKs should work out of the box, deploying smart contracts or using unique zkSync features, -like account abstraction, requires providing additional fields to those that Ethereum transactions have by default. - -To begin, it is useful to have a basic understanding of the types of objects available and what they are responsible -for, at a high level: - -- `Client` provides connection to the zkSync Era blockchain, which allows querying the blockchain state, such as - account, block or transaction details, querying event logs or evaluating read-only code using call. Additionally, the - client facilitates writing to the blockchain by sending transactions. -- `Signer` wraps all operations that interact with an account. An account generally has a private key, which can be used - to sign a variety of types of payloads. -- `Wallet` is a wrapper around `Client` and `Signer` that provides easy usage of the most common features. - -## Examples - -Connect to the zkSync Era network: - -```go -ZkSyncEraProvider := "https://testnet.era.zksync.dev" -ZkSyncEraWSProvider := "ws://testnet.era.zksync.dev:3051" - -// Connect to zkSync network -client, err := clients.Dial(ZkSyncEraProvider) -if err != nil { - log.Panic(err) -} -defer client.Close() - -// Connect to zkSync network using Web Socket -wsClient, err := clients.Dial(ZkSyncEraWSProvider) -if err != nil { - log.Panic(err) -} -defer wsClient.Close() -``` - -Get the chain ID: - -```go -chainID, err := client.ChainID(context.Background()) -if err != nil { - log.Panic(err) -} -fmt.Println("Chain ID: ", chainID) -``` - -Get the latest block: - -```go -block, err := client.BlockByNumber(context.Background(), nil) -if err != nil { - log.Panic(err) - } -fmt.Printf("%+v\n", *block) -``` - -Get the block by hash: - -```go -blockHash := common.HexToHash("b472c070c9e121ba42702f6c322b7b266e287a4d8b5fa426ed265b105430c397") -block, err := client.BlockByHash(context.Background(), blockHash) -if err != nil { - log.Panic(err) -} -fmt.Printf("%+v\n", *block) -``` - -Get the transaction by hash: - -```go -transactionByHash, _, err := client.TransactionByHash(context.Background(), common.HexToHash("0x9af27afed9a4dd018c0625ea1368afb8ba08e4cfb69b3e76dfb8521c8a87ecfc")) -if err != nil { - log.Panic(err) -} -fmt.Printf("%+v\n", transactionByHash) -``` - -Also, the following examples demonstrate how to: - -1. [Deposit ETH and tokens from Ethereum into zkSync Era](https://github.com/zksync-sdk/zksync2-examples/blob/main/go/01_deposit.go). -2. [Transfer ETH and tokens on zkSync Era](https://github.com/zksync-sdk/zksync2-examples/blob/main/go/02_transfer.go). -3. [Withdraw ETH and tokens from zkSync Era to Ethereum](https://github.com/zksync-sdk/zksync2-examples/blob/main/go/03_withdraw.go). -4. [Deploy a smart contract using CREATE opcode](https://github.com/zksync-sdk/zksync2-examples/blob/main/go/09_deploy_create.go). -5. [Deploy a smart contract using CREATE2 opcode](https://github.com/zksync-sdk/zksync2-examples/blob/main/go/12_deploy_create2.go). -6. [Deploy custom token on zkSync Era](https://github.com/zksync-sdk/zksync2-examples/blob/main/go/15_deploy_token_create.go). -7. [Deploy smart account](https://github.com/zksync-sdk/zksync2-examples/blob/main/go/17_deploy_create_account.go). -8. [Use paymaster to pay fee with token](https://github.com/zksync-sdk/zksync2-examples/blob/main/go/19_use_paymaster.go). - -Full code for all examples is available [here](https://github.com/zksync-sdk/zksync2-examples/tree/main/go). Examples -are configured to interact with `zkSync Era`, and `Sepolia` test networks. diff --git a/content/20.build/sdks/go/paymaster-utils.md b/content/20.build/sdks/go/paymaster-utils.md deleted file mode 100644 index cd3386ce..00000000 --- a/content/20.build/sdks/go/paymaster-utils.md +++ /dev/null @@ -1,78 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Go SDK Paymaster Utilities | zkSync Docs ---- - -# Paymaster Utilities - -The [paymaster utilities library](https://github.com/zksync-sdk/zksync2-go/blob/main/utils/paymaster.go) contains -essential utilities for using paymasters on zkSync Era. - -## Contract interfaces - -### `IPaymasterFlow` - -Constant ABI definition for the -[Paymaster Flow Interface](https://github.com/matter-labs/era-contracts/blob/87cd8d7b0f8c02e9672c0603a821641a566b5dd8/l2-contracts/contracts/interfaces/IPaymasterFlow.sol). - -```go -IPaymasterFlow := abi.JSON(strings.NewReader(paymasterflow.IPaymasterFlowMetaData.ABI)); -``` - -## Functions - -### `GetApprovalBasedPaymasterInput` - -Returns encoded input for an approval-based paymaster. - -#### Inputs - -| Parameter | Type | Description | -| ---------------- | ----------------------------- | -------------------------------- | -| `paymasterInput` | `ApprovalBasedPaymasterInput` | The input data to the paymaster. | - -```go -func GetApprovalBasedPaymasterInput(paymasterInput types.ApprovalBasedPaymasterInput) ([]byte, error) { - return paymasterFlowAbi.Pack("approvalBased", - paymasterInput.Token, - paymasterInput.MinimalAllowance, - paymasterInput.InnerInput) -} -``` - -### `GetGeneralPaymasterInput` - -Returns encoded input for a general-based paymaster. - -#### Inputs - -| Parameter | Type | Description | -| ---------------- | ----------------------- | -------------------------------- | -| `paymasterInput` | `GeneralPaymasterInput` | The input data to the paymaster. | - -```go -func GetGeneralPaymasterInput(paymasterInput types.GeneralPaymasterInput) ([]byte, error) { - return paymasterFlowAbi.Pack("general", paymasterInput) -} -``` - -### `GetPaymasterParams` - -Returns a correctly-formed `paymasterParams` object for common -[paymaster flows](../../developer-reference/account-abstraction.md#built-in-paymaster-flows). - -#### Inputs - -| Parameter | Type | Description | -| ------------------ | ---------------- | --------------------------------- | -| `paymasterAddress` | `Address` | The non-zero `paymaster` address. | -| `paymasterInput` | `PaymasterInput` | The input data to the paymaster. | - -```go -func GetPaymasterParams(paymasterAddress common.Address, paymasterInput types.PaymasterInput) (*types.PaymasterParams, error) -``` - -Find out more about the [`PaymasterInput` type](types/types.md). Check out the -[example](https://github.com/zksync-sdk/zksync2-examples/blob/main/go/19_use_paymaster.go) how to use paymaster. diff --git a/content/20.build/sdks/go/types/accounts.md b/content/20.build/sdks/go/types/accounts.md deleted file mode 100644 index 9b9a11ab..00000000 --- a/content/20.build/sdks/go/types/accounts.md +++ /dev/null @@ -1,384 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Go SDK Accounts Package | zkSync Docs ---- - -# `accounts` Package - -### `CallOpts` - -Is the collection of options to fine tune a contract call request from an account associated with `AdapterL1`, -`AdapterL2`, `Deployer` or `Adapter`. Its primary purpose is to be transformed into `bind.CallOpts`, wherein the `From` -field represents the associated account. - -```go -type CallOpts struct { - Pending bool // Whether to operate on the pending state or the last known one - BlockNumber *big.Int // Optional the block number on which the call should be performed - Context context.Context // Network context to support cancellation and timeouts (nil = no timeout) -} -``` - -### `FullDepositFee` - -Represents the total ETH fee required for performing the deposit on both L1 and L2 networks. - -```go -type FullDepositFee struct { - MaxFeePerGas, // MaxFeePerGas of the L1 transaction if 1559 transaction is used. - MaxPriorityFeePerGas, // MaxPriorityFeePerGas of the L1 transaction if 1559 transaction is used. - GasPrice, // Gas price of the L1 transaction if legacy transaction is used. - BaseCost, // Base cost of the L2 transaction. - L1GasLimit, // Gas limit of the L1 transaction. - L2GasLimit *big.Int // Gas limit of the L2 transaction. -} -``` - -### `CallMsg` - -Contains parameters for contract call from an account associated with `AdapterL1`, `AdapterL2`, `Deployer` or`Adapter`. -Its primary purpose is to be transformed into [`types.CallMsg`](#callmsg), wherein the `From` field represents the -associated account. - -```go -type CallMsg struct { - To *common.Address // The address of the recipient. - Gas uint64 // If 0, the call executes with near-infinite gas. - GasPrice *big.Int // Wei <-> gas exchange ratio. - GasFeeCap *big.Int // EIP-1559 fee cap per gas. - GasTipCap *big.Int // EIP-1559 tip per gas. - Value *big.Int // Amount of wei sent along with the call. - Data []byte // Input data, usually an ABI-encoded contract method invocation - AccessList types.AccessList // EIP-2930 access list. - Meta *zkTypes.Eip712Meta // EIP-712 metadata. -} - -func (m *CallMsg) ToCallMsg(from common.Address) zkTypes.CallMsg -``` - -### `WithdrawalCallMsg` - -Contains the common data required to execute a withdrawal call on L1 from L2. This execution is initiated by the account -associated with `AdapterL2` - -```go -type WithdrawalCallMsg struct { - To common.Address // The address of the recipient on L1. - Amount *big.Int // The amount of the token to transfer. - Token common.Address // The address of the token. ETH by default. - BridgeAddress *common.Address // The address of the bridge contract to be used. - - Gas uint64 // If 0, the call executes with near-infinite gas. - GasPrice *big.Int // Wei <-> gas exchange ratio. - GasFeeCap *big.Int // EIP-1559 fee cap per gas. - GasTipCap *big.Int // EIP-1559 tip per gas. - - AccessList types.AccessList // EIP-2930 access list. -} - -func (m *WithdrawalCallMsg) ToWithdrawalCallMsg(from common.Address) clients.WithdrawalCallMsg -``` - -### `TransferCallMsg` - -Contains the common data required to execute a transfer call on L2. This execution is initiated by the account -associated with `AdapterL2`. - -```go -type TransferCallMsg struct { - To common.Address // The address of the recipient. - Amount *big.Int // The amount of the token to transfer. - Token common.Address // The address of the token. ETH by default. - - Gas uint64 // If 0, the call executes with near-infinite gas. - GasPrice *big.Int // Wei <-> gas exchange ratio. - GasFeeCap *big.Int // EIP-1559 fee cap per gas. - GasTipCap *big.Int // EIP-1559 tip per gas. - - AccessList types.AccessList // EIP-2930 access list. -} - -func (m *TransferCallMsg) ToTransferCallMsg(from common.Address) clients.TransferCallMsg -``` - -### `DepositCallMsg` - -Contains the common data required to execute a deposit call on L2 from L1. This execution is initiated by the account -associated with `AdapterL2`. - -```go -type DepositCallMsg struct { - To common.Address // The address that will receive the deposited tokens on L2. - Token common.Address // The address of the token to deposit. - Amount *big.Int // The amount of the token to be deposited. - - // If the ETH value passed with the transaction is not explicitly stated Value, - // this field will be equal to the tip the operator will receive on top of the base cost - // of the transaction. - OperatorTip *big.Int - - // The address of the bridge contract to be used. Defaults to the default zkSync bridge - // (either L1EthBridge or L1Erc20Bridge). - BridgeAddress *common.Address - - L2GasLimit *big.Int // Maximum amount of L2 gas that transaction can consume during execution on L2. - - // The maximum amount L2 gas that the operator may charge the user for single byte of pubdata. - GasPerPubdataByte *big.Int - - // The address on L2 that will receive the refund for the transaction. - // If the transaction fails, it will also be the address to receive L2Value. - RefundRecipient common.Address - - CustomBridgeData []byte // Additional data that can be sent to a bridge. - - Value *big.Int // The amount of wei sent along with the call. - Gas uint64 // If 0, the call executes with near-infinite gas. - GasPrice *big.Int // Wei <-> gas exchange ratio. - GasFeeCap *big.Int // EIP-1559 fee cap per gas. - GasTipCap *big.Int // EIP-1559 tip per gas. - - AccessList types.AccessList // EIP-2930 access list. -} - -func (m *DepositCallMsg) ToDepositTransaction() DepositTransaction -func (m *DepositCallMsg) ToRequestExecuteCallMsg() RequestExecuteCallMsg -func (m *DepositCallMsg) ToCallMsg(from, l1Bridge common.Address) (ethereum.CallMsg, error) -func (m *DepositCallMsg) ToTransactOpts() *TransactOpts -``` - -### `RequestExecuteCallMsg` - -Contains the common data required to execute a call for a request execution of an L2 transaction from L1. This execution -is initiated by the account associated with `AdapterL1`. - -```go -type RequestExecuteCallMsg struct { - ContractAddress common.Address // The L2 receiver address. - Calldata []byte // The input of the L2 transaction. - L2GasLimit *big.Int // Maximum amount of L2 gas that transaction can consume during execution on L2. - L2Value *big.Int // `msg.value` of L2 transaction. - FactoryDeps [][]byte // An array of L2 bytecodes that will be marked as known on L2. - - // If the ETH value passed with the transaction is not explicitly stated Value, - // this field will be equal to the tip the operator will receive on top of the base cost - // of the transaction. - OperatorTip *big.Int - - // The maximum amount L2 gas that the operator may charge the user for single byte of pubdata. - GasPerPubdataByte *big.Int - - // The address on L2 that will receive the refund for the transaction. - // If the transaction fails, it will also be the address to receive L2Value. - RefundRecipient common.Address - - Value *big.Int // The amount of wei sent along with the call. - Gas uint64 // If 0, the call executes with near-infinite gas. - GasPrice *big.Int // Wei <-> gas exchange ratio. - GasFeeCap *big.Int // EIP-1559 fee cap per gas. - GasTipCap *big.Int // EIP-1559 tip per gas. - - AccessList types.AccessList // EIP-2930 access list. -} - -func (m *RequestExecuteCallMsg) ToRequestExecuteTransaction() RequestExecuteTransaction -func (m *RequestExecuteCallMsg) ToCallMsg(from common.Address) (ethereum.CallMsg, error) -func (m *RequestExecuteCallMsg) ToTransactOpts() TransactOpts -``` - -### `TransactOpts` - -Contains common data required to create a valid transaction on both L1 and L2 using the account associated with -`AdapterL1`, `AdapterL2` or `Deployer`. Its primary purpose is to be transformed into -[`bind.TransactOpts`](https://pkg.go.dev/github.com/ethereum/go-ethereum@v1.12.0/accounts/abi/bind#TransactOpts), -wherein the `From` and `Signer` fields are linked to the associated account. - -```go -type TransactOpts struct { - Nonce *big.Int // Nonce to use for the transaction execution (nil = use pending state). - Value *big.Int // Funds to transfer along the transaction (nil = 0 = no funds). - GasPrice *big.Int // Gas price to use for the transaction execution (nil = gas price oracle). - GasFeeCap *big.Int // Gas fee cap to use for the 1559 transaction execution (nil = gas price oracle). - GasTipCap *big.Int // Gas priority fee cap to use for the 1559 transaction execution (nil = gas price oracle). - GasLimit uint64 // Gas limit to set for the transaction execution (0 = estimate). - Context context.Context // Network context to support cancellation and timeouts (nil = no timeout). -} - -func (t *TransactOpts) ToTransactOpts(from common.Address, signer bind.SignerFn) *bind.TransactOpts -``` - -### `Transaction` - -Transaction is similar to [`types.Transaction712`](types.md#transaction712) but does not include the From field. This -design is intended for use abstraction which already have an associated account with `AdapterL2`. The From field is -bound to the specific account, and thus, it is not included in this type. - -```go -type Transaction struct { - To *common.Address // The address of the recipient. - Data hexutil.Bytes // Input data, usually an ABI-encoded contract method invocation. - Value *big.Int // Funds to transfer along the transaction (nil = 0 = no funds). - Nonce *big.Int // Nonce to use for the transaction execution. - GasTipCap *big.Int // EIP-1559 tip per gas. - GasFeeCap *big.Int // EIP-1559 fee cap per gas. - Gas uint64 // Gas limit to set for the transaction execution. - - AccessList types.AccessList // EIP-2930 access list. - - ChainID *big.Int // Chain ID of the network. - Meta *zkTypes.Eip712Meta // EIP-712 metadata. -} - -func (t *Transaction) ToTransaction712(from common.Address) *zkTypes.Transaction712 -func (t *Transaction) ToCallMsg(from common.Address) zkTypes.CallMsg -``` - -### `TransferTransaction` - -Represents a transfer transaction on L2 initiated by the account associated with `AdapterL2`. - -```go -type TransferTransaction struct { - To common.Address // The address of the recipient. - Amount *big.Int // The amount of the token to transfer. - Token common.Address // The address of the token. ETH by default. -} - -func (t *TransferTransaction) ToTransaction(opts *TransactOpts) *Transaction -func (t *TransferTransaction) ToTransferCallMsg(from common.Address, opts *TransactOpts) clients.TransferCallMsg -``` - -### `WithdrawalTransaction` - -Represents a withdrawal transaction on L1 from L2 initiated by the account associated with `AdapterL2`. - -```go -type WithdrawalTransaction struct { - To common.Address // The address that will receive the withdrawn tokens on L1. - Token common.Address // The address of the token to withdraw. - Amount *big.Int // The amount of the token to withdraw. - - // The address of the bridge contract to be used. Defaults to the default zkSync bridge - // (either L2EthBridge or L2Erc20Bridge). - BridgeAddress *common.Address -} - -func (t *WithdrawalTransaction) ToWithdrawalCallMsg(from common.Address, opts *TransactOpts) *clients.WithdrawalCallMsg -``` - -### `RequestExecuteTransaction` - -Represents a request execution of L2 transaction from L1 initiated by the account associated with `AdapterL1`. - -```go -type RequestExecuteTransaction struct { - ContractAddress common.Address // The L2 receiver address. - Calldata []byte // The input of the L2 transaction. - L2GasLimit *big.Int // Maximum amount of L2 gas that transaction can consume during execution on L2. - L2Value *big.Int // `msg.value` of L2 transaction. - FactoryDeps [][]byte // An array of L2 bytecodes that will be marked as known on L2. - - // If the ETH value passed with the transaction is not explicitly stated Auth.Value, - // this field will be equal to the tip the operator will receive on top of the base cost - // of the transaction. - OperatorTip *big.Int - - // The maximum amount L2 gas that the operator may charge the user for single byte of pubdata. - GasPerPubdataByte *big.Int - - // The address on L2 that will receive the refund for the transaction. - // If the transaction fails, it will also be the address to receive L2Value. - RefundRecipient common.Address -} - -func (t *RequestExecuteTransaction) ToRequestExecuteCallMsg(opts *TransactOpts) RequestExecuteCallMsg -func (t *RequestExecuteTransaction) ToCallMsg(from common.Address, opts *TransactOpts) zkTypes.CallMsg -``` - -### `DepositTransaction` - -Represents a deposit transaction on L2 from L1 initiated by the account associated with `AdapterL1`. - -```go -type DepositTransaction struct { - To common.Address // The address of the token to deposit. - Token common.Address // The address of the token to deposit. - Amount *big.Int // The amount of the token to be deposited. - - // If the ETH value passed with the transaction is not explicitly stated Auth.Value, - // this field will be equal to the tip the operator will receive on top of the base cost - // of the transaction. - OperatorTip *big.Int - - // The address of the bridge contract to be used. Defaults to the default zkSync bridge - // (either L1EthBridge or L1Erc20Bridge). - BridgeAddress *common.Address - - // Whether should the token approval be performed under the hood. Set this flag to true if you - // bridge an ERC20 token and didn't call the approveERC20 function beforehand. - ApproveERC20 bool - - L2GasLimit *big.Int // Maximum amount of L2 gas that transaction can consume during execution on L2. - - // The maximum amount L2 gas that the operator may charge the user for single byte of pubdata. - GasPerPubdataByte *big.Int - - // The address on L2 that will receive the refund for the transaction. - // If the transaction fails, it will also be the address to receive L2Value. - RefundRecipient common.Address - - CustomBridgeData []byte // Additional data that can be sent to a bridge. - ApproveAuth *TransactOpts // Authorization data for the approval token transaction. -} - -func (t *DepositTransaction) ToRequestExecuteTransaction() *RequestExecuteTransaction -func (t *DepositTransaction) ToDepositCallMsg(opts *TransactOpts) DepositCallMsg -``` - -### `DeploymentType` - -Represents an enumeration of deployment types. - -```go -type DeploymentType string - -const ( - DeployContract DeploymentType = "CONTRACT" - DeployAccount DeploymentType = "ACCOUNT" -) -``` - -### `CreateTransaction` - -Represents the parameters for deploying a contract or account using the CREATE opcode. This transaction is initiated by -the account associated with `Deployer`. - -```go -type CreateTransaction struct { - Bytecode []byte // The bytecode of smart contract or smart account. - Calldata []byte // The constructor calldata. - Dependencies [][]byte // The bytecode of dependent smart contracts or smart accounts. - Auth *TransactOpts // Authorization data. -} - -func (t *CreateTransaction) ToTransaction(deploymentType DeploymentType) (*Transaction, error) -``` - -### `Create2Transaction` - -Represents the parameters for deploying a contract or account using the CREATE2 opcode. This transaction is initiated by -the account associated with `Deployer`. - -```go -type Create2Transaction struct { - Bytecode []byte // The bytecode of smart contract or smart account. - Calldata []byte // The constructor calldata. - Salt []byte // The create2 salt. - Dependencies [][]byte // The bytecode of dependent smart contracts or smart accounts. - Auth *TransactOpts // Authorization data. -} - -func (t *Create2Transaction) ToTransaction(deploymentType DeploymentType) (*Transaction, error) -``` diff --git a/content/20.build/sdks/go/types/clients.md b/content/20.build/sdks/go/types/clients.md deleted file mode 100644 index 8f057b8c..00000000 --- a/content/20.build/sdks/go/types/clients.md +++ /dev/null @@ -1,66 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Go SDK Clients Package | zkSync Docs ---- - -# `clients` Package - -### `BlockRange` - -Represents a range of blocks with the starting and ending block numbers. - -```go -type BlockRange struct { - Beginning *big.Int `json:"beginning"` // Starting block number of the range. - End *big.Int `json:"end"` // Ending block number of the range. -} -``` - -### `WithdrawalCallMsg` - -Contains parameters for withdrawal call. It can be transformed into an `ethereum.CallMsg` by encoding the withdrawal -parameters with `ToCallMsg` method. - -```go -type WithdrawalCallMsg struct { - To common.Address // The address of the recipient on L1. - Amount *big.Int // The amount of the token to transfer. - Token common.Address // The address of the token. ETH by default. - BridgeAddress *common.Address // The address of the bridge contract to be used. - From common.Address // The address of the sender. - - Gas uint64 // If 0, the call executes with near-infinite gas. - GasPrice *big.Int // Wei <-> gas exchange ratio. - GasFeeCap *big.Int // EIP-1559 fee cap per gas. - GasTipCap *big.Int // EIP-1559 tip per gas. - - AccessList types.AccessList // EIP-2930 access list. -} - -func (m *WithdrawalCallMsg) ToCallMsg(defaultL2Bridge *common.Address) (*ethereum.CallMsg, error) -``` - -### `TransferCallMsg` - -Contains parameters for transfer call. It can be transformed into `ethereum.CallMsg` by encoding the transfer parameters -with `ToCallMsg` method. - -```go -type TransferCallMsg struct { - To common.Address // The address of the recipient. - Amount *big.Int // The amount of the token to transfer. - Token common.Address // The address of the token. ETH by default. - From common.Address // The address of the sender. - - Gas uint64 // If 0, the call executes with near-infinite gas. - GasPrice *big.Int // Wei <-> gas exchange ratio. - GasFeeCap *big.Int // EIP-1559 fee cap per gas. - GasTipCap *big.Int // EIP-1559 tip per gas. - - AccessList types.AccessList // EIP-2930 access list. -} - -func (m *TransferCallMsg) ToCallMsg() (*ethereum.CallMsg, error) -``` diff --git a/content/20.build/sdks/go/types/eip712.md b/content/20.build/sdks/go/types/eip712.md deleted file mode 100644 index 065e5dd5..00000000 --- a/content/20.build/sdks/go/types/eip712.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Go SDK EIP712 Package | zkSync Docs ---- - -# `eip712` Package - -### `Domain` - -Represents the domain parameters used for EIP-712 signing. - -```go -type Domain struct { - Name string `json:"name"` // Name of the domain. - Version string `json:"version"` // Version of the domain. - ChainId *big.Int `json:"chainId"` // Chain ID associated with the domain. - VerifyingContract *common.Address `json:"verifyingContract"` // Address of the verifying contract for the domain. -} -``` diff --git a/content/20.build/sdks/go/types/intro.md b/content/20.build/sdks/go/types/intro.md deleted file mode 100644 index 41308f6c..00000000 --- a/content/20.build/sdks/go/types/intro.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Go SDK Types | zkSync Docs ---- - -# Types - -Types are placed in three packages for different purposes: - -- [`types`](types.md): Contains common and general types used to build basic features and other types. -- [`eip712`](eip712.md): Contains types used for EIP-712 implementation. -- [`clients`](clients.md): Contains types that are meant to be used along with [`Client`](clients.md). -- [`accounts`](accounts.md): Contains types that are meant to be used along with an account, specifically with the - [`Adapter`](../accounts.md) abstraction. Many types are similar to those from the `geth` library, but the `From` or - `Signer` fields are omitted because these fields are inherited from `Adapter`, which already has an associated - account. diff --git a/content/20.build/sdks/go/types/types.md b/content/20.build/sdks/go/types/types.md deleted file mode 100644 index 5a6e79d5..00000000 --- a/content/20.build/sdks/go/types/types.md +++ /dev/null @@ -1,411 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Go SDK Types Package | zkSync Docs ---- - -# `types` Package - -### `AccountAbstractionVersion` - -Represents an enumeration of account abstraction versions. - -```go -type AccountAbstractionVersion uint8 - -const ( - None AccountAbstractionVersion = iota - Version1 -) -``` - -### `AccountNonceOrdering` - -Represents an enumeration of account nonce ordering formats. - -```go -type AccountNonceOrdering uint8 - -const ( - Sequential AccountNonceOrdering = iota - Arbitrary -) -``` - -### `ApprovalBasedPaymasterInput` - -Contains approval-based paymaster input. It should be used if the user is required to set a certain allowance to a token -for the paymaster to operate. - -```go -type ApprovalBasedPaymasterInput struct { - Token common.Address // ERC20 token used to pay transaction fee. - // Minimal allowance of Token towards the paymaster from the account that pays the fee with the token. - MinimalAllowance *big.Int - InnerInput []byte // Additional payload that can be sent to the paymaster to implement any logic. -} -``` - -### `BatchDetails` - -Contains batch information. - -```go -type BatchDetails struct { - BaseSystemContractsHashes struct { - Bootloader common.Hash `json:"bootloader"` - DefaultAa common.Hash `json:"default_aa"` - } `json:"baseSystemContractsHashes"` - CommitTxHash common.Hash `json:"commitTxHash"` - CommittedAt time.Time `json:"committedAt"` - ExecuteTxHash common.Hash `json:"executeTxHash"` - ExecutedAt time.Time `json:"executedAt"` - L1GasPrice uint64 `json:"l1GasPrice"` - L1TxCount uint `json:"l1TxCount"` - L2FairGasPrice uint `json:"l2FairGasPrice"` - L2TxCount uint `json:"l2TxCount"` - Number uint `json:"number"` - ProveTxHash common.Hash `json:"proveTxHash"` - ProvenAt time.Time `json:"provenAt"` - RootHash common.Hash `json:"rootHash"` - Status string `json:"status"` - Timestamp uint `json:"timestamp"` -} -``` - -### `Block` - -Extends the [`types.Block`](https://pkg.go.dev/github.com/ethereum/go-ethereum@v1.12.0/core/types#Block) definition with -additional `L1BatchNumber`, `L1BatchTimestamp` fields. - -```go -type Block struct { - Header *types.Header - Uncles []*types.Header - Transactions []*TransactionResponse - Withdrawals types.Withdrawals - Hash common.Hash - Size *big.Int - TotalDifficulty *big.Int - SealFields []interface{} - ReceivedAt time.Time - ReceivedFrom interface{} - L1BatchNumber *big.Int - L1BatchTimestamp *big.Int -} -``` - -### `BlockDetails` - -Contains block information. - -```go -type BlockDetails struct { - CommitTxHash common.Hash `json:"commitTxHash"` - CommittedAt time.Time `json:"committedAt"` - ExecuteTxHash common.Hash `json:"executeTxHash"` - ExecutedAt time.Time `json:"executedAt"` - L1TxCount uint `json:"l1TxCount"` - L2TxCount uint `json:"l2TxCount"` - Number uint `json:"number"` - ProveTxHash common.Hash `json:"proveTxHash"` - ProvenAt time.Time `json:"provenAt"` - RootHash common.Hash `json:"rootHash"` - Status string `json:"status"` - Timestamp uint `json:"timestamp"` -} -``` - -### `BridgeContracts` - -Represents the addresses of default bridge contracts for both L1 and L2. - -```go -type BridgeContracts struct { - L1Erc20DefaultBridge common.Address `json:"l1Erc20DefaultBridge"` // Default L1Bridge contract address. - L2Erc20DefaultBridge common.Address `json:"l2Erc20DefaultBridge"` // Default L2Bridge contract address. -} -``` - -### `CallMsg` - -Contains parameters for contract call using EIP-712 transaction. Extends -[`ethereum.CallMsg`](https://pkg.go.dev/github.com/ethereum/go-ethereum@v1.12.0#CallMsg) with additional -[`Eip712Meta`](#eip712meta) field. - -```go -type CallMsg struct { - ethereum.CallMsg - Meta *Eip712Meta // EIP-712 metadata. -} -``` - -### `Eip712Meta` - -Contains EIP-712 transaction metadata. - -```go -type Eip712Meta struct { - // GasPerPubdata denotes the maximum amount of gas the user is willing - // to pay for a single byte of pubdata. - GasPerPubdata *hexutil.Big `json:"gasPerPubdata,omitempty"` - // CustomSignature is used for the cases in which the signer's account - // is not an EOA. - CustomSignature hexutil.Bytes `json:"customSignature,omitempty"` - // FactoryDeps is a non-empty array of bytes. For deployment transactions, - // it should contain the bytecode of the contract being deployed. - // If the contract is a factory contract, i.e. it can deploy other contracts, - // the array should also contain the bytecodes of the contracts which it can deploy. - FactoryDeps []hexutil.Bytes `json:"factoryDeps"` - // PaymasterParams contains parameters for configuring the custom paymaster - // for the transaction. - PaymasterParams *PaymasterParams `json:"paymasterParams,omitempty"` -} -``` - -### `Fee` - -Represents the transaction fee parameters. - -```go -type Fee struct { - GasLimit *hexutil.Big `json:"gas_limit"` // Maximum amount of gas allowed for the transaction. - // Maximum amount of gas the user is willing to pay for a single byte of pubdata. - GasPerPubdataLimit *hexutil.Big `json:"gas_per_pubdata_limit"` - MaxFeePerGas *hexutil.Big `json:"max_fee_per_gas"` // EIP-1559 fee cap per gas. - MaxPriorityFeePerGas *hexutil.Big `json:"max_priority_fee_per_gas"` // EIP-1559 tip per gas. -} -``` - -### `GeneralPaymasterInput` - -Contains general paymaster input. It should be used if no prior actions are required from the user for the paymaster to -operate. - -```go -type GeneralPaymasterInput []byte -``` - -### `L1BridgeContracts` - -Represents the L1 bridge contracts. - -```go -type L1BridgeContracts struct { - Erc20 *l1bridge.IL1Bridge // Default L1Bridge contract. -} -``` - -### `L2BridgeContracts` - -Represents the L2 bridge contracts. - -```go -type L2BridgeContracts struct { - Erc20 *l2bridge.IL2Bridge // Default L2Bridge contract. -} -``` - -### `L2ToL1Log` - -Represents a layer 2 to layer 1 transaction log. - -```go -type L2ToL1Log struct { - BlockNumber *hexutil.Big `json:"blockNumber"` - BlockHash common.Hash `json:"blockHash"` - L1BatchNumber *hexutil.Big `json:"l1BatchNumber"` - TransactionIndex *hexutil.Uint `json:"transactionIndex"` - ShardId *hexutil.Uint `json:"shardId"` - IsService bool `json:"isService"` - Sender common.Address `json:"sender"` - Key string `json:"key"` - Value string `json:"value"` - TxHash common.Hash `json:"transactionHash"` - Index *hexutil.Uint `json:"logIndex"` -} -``` - -### `Log` - -Extends the [`types.Log`](https://pkg.go.dev/github.com/ethereum/go-ethereum@v1.12.0/core/types#Log) definition with -additional `L1BatchNumber` field. - -```go -// Log represents a log entry. -type Log struct { - types.Log - L1BatchNumber *hexutil.Big `json:"l1BatchNumber"` -} -``` - -### `MessageProof` - -Represents a message proof. - -```go -type MessageProof struct { - Id int `json:"id"` - Proof []common.Hash `json:"proof"` - Root common.Hash `json:"root"` -} -``` - -### `Receipt` - -Extends the [`types.Receipt`](https://pkg.go.dev/github.com/ethereum/go-ethereum@v1.12.0/core/types#Receipts) definition -with additional `From`, `To`, `EffectiveGasPrice`, `L1BatchNumber`, `L1BatchTxIndex`, `Logs`, `L2ToL1Logs` fields. - -```go -type Receipt struct { - types.Receipt - - From common.Address `json:"from"` - To common.Address `json:"to"` - EffectiveGasPrice *hexutil.Big `json:"effectiveGasPrice"` - L1BatchNumber *hexutil.Big `json:"l1BatchNumber"` - L1BatchTxIndex *hexutil.Big `json:"l1BatchTxIndex"` - Logs []*Log `json:"logs"` - L2ToL1Logs []*L2ToL1Log `json:"l2ToL1Logs"` -} -``` - -### `StandardConfiguration` - -Represents the standard-json configuration generated as output of zksolc compiler. - -```go -type StandardConfiguration struct { - Format string `json:"_format"` - ContractName string `json:"contractName"` - SourceName string `json:"sourceName"` - Abi []struct { - Inputs []struct { - InternalType string `json:"internalType"` - Name string `json:"name"` - Type string `json:"type"` - Indexed bool `json:"indexed,omitempty"` - } `json:"inputs"` - StateMutability string `json:"stateMutability,omitempty"` - Type string `json:"type"` - Anonymous bool `json:"anonymous,omitempty"` - Name string `json:"name,omitempty"` - Outputs []struct { - InternalType string `json:"internalType"` - Name string `json:"name"` - Type string `json:"type"` - } `json:"outputs,omitempty"` - } `json:"abi"` - Bytecode string `json:"bytecode"` - DeployedBytecode string `json:"deployedBytecode"` - LinkReferences struct { - } `json:"linkReferences"` - DeployedLinkReferences struct { - } `json:"deployedLinkReferences"` - FactoryDeps struct { - } `json:"factoryDeps"` -} -``` - -### `PaymasterParams` - -Contains parameters for configuring the custom paymaster for the transaction. - -```go -type PaymasterParams struct { - Paymaster common.Address `json:"paymaster"` // address of the paymaster - PaymasterInput []byte `json:"paymasterInput"` // encoded input -} -``` - -### `Token` - -Represents a token with addresses on both L1 and L2 chains. - -```go -type Token struct { - L1Address common.Address `json:"l1Address"` // Token address on L1. - L2Address common.Address `json:"l2Address"` // Token address on L2. - Name string `json:"name"` // Token name. - Symbol string `json:"symbol"` // Token symbol. - Decimals uint `json:"decimals"` // Number of decimals for the token. -} -``` - -### `EIP712TxType` - -Represents an EIP-712 transaction type. - -```go -const EIP712TxType = `0x71` -``` - -### `Transaction712` - -Represents an EIP-712 compliant transaction. It shares similarities with regular transactions but also includes zkSync -Era-specific features such as account abstraction and paymasters. Smart contracts must be deployed with support for the -EIP-712 transaction type. - -```go -type Transaction712 struct { - Nonce *big.Int // Nonce to use for the transaction execution. - GasTipCap *big.Int // EIP-1559 tip per gas. - GasFeeCap *big.Int // EIP-1559 fee cap per gas. - Gas *big.Int // Gas limit to set for the transaction execution. - To *common.Address // The address of the recipient. - Value *big.Int // Funds to transfer along the transaction (nil = 0 = no funds). - Data hexutil.Bytes // Input data, usually an ABI-encoded contract method invocation. - AccessList types.AccessList // EIP-2930 access list. - - ChainID *big.Int // Chain ID of the network. - From *common.Address // The address of the sender. - Meta *Eip712Meta // EIP-712 metadata. -} -``` - -### `TransactionDetails` - -Contains transaction details. - -```go -type TransactionDetails struct { - EthCommitTxHash common.Hash `json:"ethCommitTxHash"` - EthExecuteTxHash common.Hash `json:"ethExecuteTxHash"` - EthProveTxHash common.Hash `json:"ethProveTxHash"` - Fee hexutil.Big `json:"fee"` - InitiatorAddress common.Address `json:"initiatorAddress"` - IsL1Originated bool `json:"isL1Originated"` - ReceivedAt time.Time `json:"receivedAt"` - Status string `json:"status"` -} -``` - -### `TransactionResponse` - -Includes all properties of a transaction as well as several properties that are useful once it has been mined. - -```go -type TransactionResponse struct { - BlockHash *common.Hash `json:"blockHash"` - BlockNumber *hexutil.Big `json:"blockNumber"` - ChainID hexutil.Big `json:"chainId"` - From common.Address `json:"from"` - Gas hexutil.Uint64 `json:"gas"` - GasPrice hexutil.Big `json:"gasPrice"` - Hash common.Hash `json:"hash"` - Data hexutil.Bytes `json:"input"` - L1BatchNumber hexutil.Big `json:"l1BatchNumber"` - L1BatchTxIndex hexutil.Big `json:"l1BatchTxIndex"` - MaxFeePerGas hexutil.Big `json:"maxFeePerGas"` - MaxPriorityFeePerGas hexutil.Big `json:"maxPriorityFeePerGas"` - Nonce hexutil.Uint64 `json:"nonce"` - V *hexutil.Big `json:"v"` - R *hexutil.Big `json:"r"` - S *hexutil.Big `json:"s"` - To common.Address `json:"to"` - TransactionIndex hexutil.Uint `json:"transactionIndex"` - Type hexutil.Uint64 `json:"type"` - Value hexutil.Big `json:"value"` -} -``` diff --git a/content/20.build/sdks/go/utils.md b/content/20.build/sdks/go/utils.md deleted file mode 100644 index a760b5ea..00000000 --- a/content/20.build/sdks/go/utils.md +++ /dev/null @@ -1,308 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Go SDK Utils | zkSync Docs ---- - -# Utils - -Provides essential utilities for building on zkSync Era. - -## Constants - -#### L1 to L2 alias offset - -Used for applying and undoing aliases on contract addresses during bridging from L1 to L2. - -```go -L1ToL2AliasOffset := common.HexToAddress("0x1111000000000000000000000000000000001111") -``` - -### Useful addresses - -#### ETH token on L1 - -```go -EthAddress := common.HexToAddress("0x0000000000000000000000000000000000000000") -``` - -#### ETH token alias on ZkSync Era - -```go -L2EthTokenAddress := common.HexToAddress("0x000000000000000000000000000000000000800a") -``` - -#### Bootloader - -```go -BootloaderFormalAddress := common.HexToAddress("0x0000000000000000000000000000000000008001") -``` - -#### Contract deployer - -```go -ContractDeployerAddress := common.HexToAddress("0x0000000000000000000000000000000000008006") -``` - -#### L1 messenger - -```go -L1MessengerAddress := common.HexToAddress("0x0000000000000000000000000000000000008008") -``` - -### Gas - -#### `DefaultGasPerPubdataLimit` - -- Use a large amount of gas per pubdata for signing on layer 2. -- The amount ensures any reasonable limit is accepted. - -:::info The operator is NOT required to use the actual value and can use any value up to that signed by the user. ::: - -```go -DefaultGasPerPubdataLimit := big.NewInt(50_000) -``` - -#### `RequiredL1ToL2GasPerPubdataLimit` - -The current required gas per pubdata for L1->L2 transactions. - -```go -RequiredL1ToL2GasPerPubdataLimit := big.NewInt(800) -``` - -## Functions - -### `ApplyL1ToL2Alias` - -Converts the address that submitted a transaction to the inbox on L1 to the `msg.sender` viewed on L2. - -#### Inputs - -| Parameter | Type | Description | -| --------- | ---------------- | ----------------- | -| `address` | `common.Address` | Contract address. | - -#### Outputs - -Returns the `msg.sender` of the L1->L2 transaction as the `common.Address` of the contract that initiated the -transaction. - -:::tip More info - -1. During a normal transaction, if contract A calls contract B, the `msg.sender` is A. -2. During L1->L2 communication, if an EOA X calls contract B, the `msg.sender` is X. -3. During L1->L2 communication, if a contract A calls contract B, the `msg.sender` is `ApplyL1ToL2Alias(A)`. ::: - -```go -func ApplyL1ToL2Alias(address common.Address) common.Address -``` - -See also [`UndoL1ToL2Alias`](#undol1tol2alias). - -### `Create2Address` - -Generates a future-proof contract address using salt plus bytecode which allows determination of an address before -deployment. - -:::warning The zkSync Era implementation is slightly different from Ethereum. ::: - -#### Inputs - -| Parameter | Type | Description | -| ------------- | ---------------- | ---------------------------------- | -| `sender` | `common.Address` | Sender address. | -| `bytecode` | `[]byte` | Output from zkSolc. | -| `constructor` | `[]byte` | ABI encoded constructor arguments. | -| `salt` | `[]byte` | Randomization element. | - -#### Outputs - -Returns a `common.Address` of the future contract. - -```go -func Create2Address(sender common.Address, bytecode, constructor, salt []byte) (common.Address, error) -``` - -:::tip The `prefix` is equal to `keccak256("zksyncCreate2")`. ::: - -### `CreateAddress` - -Generates a contract address from deployer's account and nonce. - -#### Inputs - -| Parameter | Type | Description | -| --------- | ----------------- | --------------- | -| `sender` | `common.Address` | Sender address. | -| `nonce` | `*big.Int` object | Sender nonce. | - -#### Outputs - -Returns a `common.Address` of the future contract. - -```go -func CreateAddress(sender common.Address, nonce *big.Int) (common.Address, error) -``` - -:::tip The `prefix` is equal to `keccak256("zksyncCreate")`. ::: - -### `CreateETH` - -Creates ETH token with appropriate Name, Symbol and Decimals values. - -```go -func CreateETH() *types.Token -``` - -### `EncodeCreate` - -Returns the encoded constructor data for CREATE method used for smart contract deployment. - -#### Inputs - -| Parameter | Type | Description | -| ---------- | -------- | ---------------------------------- | -| `bytecode` | `[]byte` | Output from zkSolc. | -| `calldata` | `[]byte` | ABI encoded constructor arguments. | - -```go -func EncodeCreate(bytecode, calldata []byte) ([]byte, error) -``` - -### `EncodeCreate2` - -Returns the encoded constructor data for CREATE2 method used for smart contract deployment. - -#### Inputs - -| Parameter | Type | Description | -| ---------- | -------- | ---------------------------------- | -| `bytecode` | `[]byte` | Output from zkSolc. | -| `calldata` | `[]byte` | ABI encoded constructor arguments. | -| `salt` | `[]byte` | Randomization element. | - -```go -func EncodeCreate2(bytecode, calldata, salt []byte) ([]byte, error) -``` - -### `EncodeCreateAccount` - -Returns the encoded constructor data for CREATE method used for smart account deployment. - -#### Inputs - -| Parameter | Type | Description | -| ---------- | ----------------------------------------------------------------------------- | ---------------------------------- | -| `bytecode` | `[]byte` | Output from zkSolc. | -| `calldata` | `[]byte` | ABI encoded constructor arguments. | -| `version` | [`types.AccountAbstractionVersion`](types/types.md#accountabstractionversion) | Account abstraction version. | - -```go - EncodeCreate2Account(bytecode, calldata, version types.AccountAbstractionVersion) ([]byte, error) -``` - -### `EncodeCreate2Account` - -Returns the encoded constructor data for CREATE2 method used for smart account deployment. - -#### Inputs - -| Parameter | Type | Description | -| ---------- | ----------------------------------------------------------------------------- | ---------------------------------- | -| `bytecode` | `[]byte` | Output from zkSolc. | -| `calldata` | `[]byte` | ABI encoded constructor arguments. | -| `salt` | `[]byte` | Randomization element. | -| `version` | [`types.AccountAbstractionVersion`](types/types.md#accountabstractionversion) | Account abstraction version. | - -```go - EncodeCreate2Account(bytecode, calldata, salt []byte, version types.AccountAbstractionVersion) ([]byte, error) -``` - -### `Erc20BridgeCalldata` - -Returns the calldata sent by an L1 ERC20 bridge to its L2 counterpart during token-bridging. - -#### Inputs - -| Parameter | Type | Description | -| ---------------- | ---------------- | ------------------------------------------- | -| `l1TokenAddress` | `common.Address` | Token address on L1. | -| `l1Sender` | `common.Address` | Sender address on L1. | -| `l2Receiver` | `common.Address` | Recipient address on L2. | -| `amount` | `*big.Int` | Gas fee for the number of tokens to bridge. | -| `bridgeData` | `*big.Int` | Data | - -```go -func Erc20BridgeCalldata(l1TokenAddress, l1Sender, l2Receiver common.Address, amount *big.Int, bridgeData []byte) -``` - -### `Erc20DefaultBridgeData` - -Returns the data needed for correct initialization of an L1 token counterpart on L2. - -#### Inputs - -| Parameter | Type | Description | -| ---------------- | ---------------------- | ----------------------------------------------------------------- | -| `l1TokenAddress` | `common.Address` | Token address on L1. | -| `backend` | `bind.ContractBackend` | Client that is able to work with contracts on a read-write basis. | - -#### Outputs - -An ABI-encoded `[]byte` which contains token name, symbol and decimals. - -```go -func Erc20DefaultBridgeData(l1TokenAddress common.Address, backend bind.ContractBackend) ([]byte, error) -``` - -### `HashBytecode` - -Returns the hash of given bytecode. - -#### Inputs - -| Parameter | Type | Description | -| ---------- | -------- | ----------- | -| `bytecode` | `[]byte` | Bytecode. | - -```go -func HashBytecode(bytecode []byte) ([]byte, error) -``` - -### `ReadStandardJson` - -Reads standard-json file generated as output from zksolc. Returns standard json configuration and extracted contracts -abi and bytecode from config file. - -#### Inputs - -| Parameter | Type | Description | -| --------- | -------- | ------------------------------- | -| `path` | `string` | Path to the standard-json file. | - -```go -func ReadStandardJson(path string) (*types.StandardConfiguration, abi.ABI, []byte, error) -``` - -### `UndoL1ToL2Alias` - -Converts and returns the `msg.sender` viewed on L2 to the address that submitted a transaction to the inbox on L1. - -#### Inputs - -| Parameter | Type | Description | -| --------- | ---------------- | --------------- | -| `address` | `common.Address` | Sender address. | - -#### Outputs - -Returns the `msg.sender` of the L2->L1 transaction as the `common.Address` of the contract that initiated the -transaction. - -```go -func UndoL1ToL2Alias(address common.Address) common.Address -``` - -See also [`ApplyL1ToL2Alias`](#applyl1tol2alias). diff --git a/content/20.build/sdks/java/accounts-l1-l2.md b/content/20.build/sdks/java/accounts-l1-l2.md deleted file mode 100644 index d50b018c..00000000 --- a/content/20.build/sdks/java/accounts-l1-l2.md +++ /dev/null @@ -1,98 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Java SDK L1/L2 Transactions | zkSync Docs ---- - -# Accounts: L1->L2 Transactions - -This section explores the methods which allow the [account](./accounts.md) classes to send transactions from L1 to L2. - -If you want some background on how L1->L2 interaction works on zkSync Era, go through the -[L1 / L2 interoperability doc](../../developer-reference/l1-l2-interop.md). - -## EthereumProvider - -### `approveDeposits` - -Send approve transaction to token contract. - -Example: - -```java -TransactionReceipt approveReceipt = provider.approveDeposits(token, Optional.of(token.toBigInteger(10000000000L))).join(); -``` - -| Name | Description | -| ------ | ----------------------------------------------------- | -| token | Token object supported by ZkSync Era. | -| limit | Maximum amount to approve for ZkSync Era contract. | -| return | `CompletableFuture` for waiting for transaction mine. | - -### `deposit` - -Send deposit transaction to ZkSync Era contract. For ERC20 token must be approved before. See -[approveDeposits](#approvedeposits) - -| Name | Description | -| ------------ | ----------------------------------------------------- | -| token | Token object supported by ZkSync Era. | -| amount | Amount of tokens to transfer. | -| operatorTips | Tips for operator that executes deposit on L2. | -| userAddress | Address of L2 receiver of deposit in ZkSync Era. | -| return | `CompletableFuture` for waiting for transaction mine. | - -Example: - -```java - TransactionManager manager = new RawTransactionManager(web3j, credentials, chainId.longValue()); - BigInteger gasPrice = web3j.ethGasPrice().send().getGasPrice(); - ContractGasProvider gasProvider = new StaticGasProvider(gasPrice, BigInteger.valueOf(300_000L)); - TransactionReceipt receipt = EthereumProvider - .load(wallet.getZksync(), web3j, manager, gasProvider).join() - .deposit(Token.ETH, Convert.toWei("0.001", Convert.Unit.ETHER).toBigInteger(), BigInteger.ZERO, credentials.getAddress()).join(); - - System.out.println(receipt); -``` - -### `getBaseCost` - -Get base cost for L2 transaction. - -Example: - -```java -BigInteger baseCost = provider.getBaseCost(gasLimit, L1_TO_L2_GAS_PER_PUBDATA, gasPriceValue).join(); -``` - -| Name | Description | -| ----------------- | ----------------------------------------------------- | -| gasLimit | Gas limit for L2 transaction. | -| gasPerPubdataByte | Gas per pubdata byte. | -| gasPrice | Gas price for L2 transaction. | -| return | `CompletableFuture` for waiting for transaction mine. | - -### `transfer` - -Send transfer transaction. This is the regular transfer of ERC20 tokens. - -Example: - -```java -TransactionManager manager = new RawTransactionManager(web3j, credentials, chainId.longValue()); -BigInteger gasPrice = web3j.ethGasPrice().send().getGasPrice(); -ContractGasProvider gasProvider = new StaticGasProvider(gasPrice, BigInteger.valueOf(300_000L)); -TransactionReceipt receipt = EthereumProvider - .load(wallet.getZksync(), web3j, manager, gasProvider).join() - .transfer(Token.ETH, Convert.toWei("0.117649", Convert.Unit.ETHER).toBigInteger(), credentials.getAddress()).join(); - - System.out.println(receipt); -``` - -| Name | Description | -| ------ | ----------------------------------------------------- | -| token | Token object supported by ZkSync Era. | -| amount | Amount of tokens to transfer. | -| to | Address of token recipient. | -| return | `CompletableFuture` for waiting for transaction mine. | diff --git a/content/20.build/sdks/java/accounts.md b/content/20.build/sdks/java/accounts.md deleted file mode 100644 index 7dcff24c..00000000 --- a/content/20.build/sdks/java/accounts.md +++ /dev/null @@ -1,313 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Java SDK Accounts | zkSync Docs ---- - -# Accounts - -## PrivateKeyEthSigner - -Used to get wallet address, generate signatures, and verify messages. - -### Create from credentials and chain id - -[Example](getting-started.md#ethsigner) - -#### Inputs and outputs - -| Name | Description | -| ----------- | ------------------------ | -| credentials | Credentials object. | -| chainId | Chain id of the network. | -| returns | PrivateKeyEthSigner. | - -### `signTypedData` - -```java -String signature = signer.signTypedData(domain, message).join(); -``` - -Signs typed-struct using Ethereum private key with the EIP-712 signature standard. - -#### Inputs and outputs - -| Name | Description | -| --------- | ---------------------------------------------- | -| domain | EIP712 domain. | -| typedData | Object implementing EIP712 structure standard. | -| returns | Prepared gas estimate request. | - -### `verifyTypedData` - -Verify typed, EIP-712 struct standard. - -```java -boolean verified = signer.verifyTypedData(domain, message, signature).join(); -``` - -#### Inputs and outputs - -| Name | Description | -| --------- | ---------------------------------------------- | -| domain | EIP712 domain. | -| typedData | Object implementing EIP712 structure standard. | -| returns | Prepared gas estimate request. | - -### `signMessage` - -Sign raw message. - -```java -signer.signMessage(Eip712Encoder.typedDataToSignedBytes(domain, typedData), false); -``` - -#### Inputs and outputs - -| Name | Description | -| --------- | ---------------------------------------------------------------------------------------------- | -| message | Message to sign. | -| addPrefix | If true then add secure prefix (EIP-712). | -| returns | Signature object. | - -### `verifySignature` - -Verify signature with raw message. - -```java -signer.verifySignature(signature, Eip712Encoder.typedDataToSignedBytes(domain, typedData), false); -``` - -#### Inputs and outputs - -| Name | Description | -| --------- | ---------------------------------------------------------------------------------------------- | -| signature | Signature string. | -| message | Message to verify in bytes. | -| prefixed | If true then add secure prefix (EIP-712). | -| returns | true on verification success. | - -### `getAddress` - -Get wallet address. - -```java -signer.getAddress(); -``` - -#### Inputs and outputs - -| Name | Description | -| ------- | ---------------------- | -| returns | Address in hex string. | - -## Wallet - -### Creating wallet from a private key - -The `Wallet` object from `zksync-ethers` can be created from an Ethereum private key. -[Example](getting-started.md#zksync-era-wallet) - -#### Inputs and outputs - -| Name | Description | -| ------- | --------------------------------------------------------------------- | -| zksync | A zkSync Era node provider. Needed for interaction with zkSync Era. | -| signer | Used to get wallet address, generate signatures, and verify messages. | -| token | Token object. | -| returns | The new `Wallet` object. | - -### `transfer` - -There are multiple ways to transfer coins or tokens with a wallet object. - -#### Transfer coins - -[Native coins example](getting-started.md#transfer-native-coins-via-zksyncwallet) - -| Name | Description | -| ------- | ---------------------------------------------------------------- | -| to | Recipient address. | -| amount | Amount of funds to be transferred in minimum denomination (wei). | -| returns | Prepared remote call of transaction. | - -##### Transfer coins or tokens - -##### With specific token - -[Example](getting-started.md#transfer-erc20-coins-via-zksyncwallet) - -| Name | Description | -| ------- | ---------------------------------------------------------------- | -| to | Recipient address. | -| amount | Amount of funds to be transferred in minimum denomination (wei). | -| token | Token object supported by ZkSync Era. | -| returns | Prepared remote call of transaction. | - -##### With specific token and custom nonce - -| Name | Description | -| ------- | ---------------------------------------------------------------- | -| to | Recipient address. | -| amount | Amount of funds to be transferred in minimum denomination (wei). | -| token | Token object supported by ZkSync Era. | -| nonce | Custom nonce value of the wallet. | -| returns | Prepared remote call of transaction. | - -### `withdraw` - -Withdraw native coins or tokens from L1. - -[Example](getting-started.md#withdraw-funds-via-zksyncwallet) - -| Name | Description | -| ------- | ------------------------------------------------------------ | -| to | Address of the L1 wallet from which funds will be withdrawn. | -| amount | Amount of funds to be withdrawn. | -| returns | Prepared remote call of transaction. | - -#### With specific token - -| Name | Description | -| ------- | --------------------------------------------------------------- | -| to | Address of the L1 wallet L1 from which funds will be withdrawn. | -| amount | Amount of funds to be withdrawn. | -| token | Token object supported by ZkSync Era. | -| returns | Prepared remote call of transaction. | - -#### With specific token and custom nonce - -| Name | Description | -| ------- | ------------------------------------------------------------ | -| to | Address of the L1 wallet from which funds will be withdrawn. | -| amount | Amount of funds to be withdrawn. | -| token | Token object supported by ZkSync Era. | -| nonce | Custom nonce value of the wallet. | -| returns | Prepared remote call of transaction. | - -### `deploy` - -Deploy new smart contract onto chain (this method uses `create2`, see -EIP-1014) - -[Example](getting-started.md#deploy-contract-via-zksyncwallet) - -| Name | Description | -| -------- | ------------------------------------ | -| bytecode | Compiled bytecode of the contract. | -| returns | Prepared remote call of transaction. | - -#### With constructor - -[Example](getting-started.md#deploy-contract-with-constructor-via-zksyncwallet) - -| Name | Description | -| -------- | --------------------------------------------- | -| bytecode | Compiled bytecode of the contract. | -| calldata | Encoded constructor parameter(s) of contract. | -| returns | Prepared remote call of transaction. | - -#### With constructor and custom nonce - -| Name | Description | -| -------- | --------------------------------------------- | -| bytecode | Compiled bytecode of the contract. | -| calldata | Encoded constructor parameter(s) of contract. | -| nonce | Custom nonce value of the wallet. | -| returns | Prepared remote call of transaction. | - -### `execute` - -Execute function of deployed contract. - -[Example](getting-started.md#execute-contact-via-zksyncwallet) - -| Name | Description | -| --------------- | -------------------------------------------------- | -| contractAddress | Address of deployed contract. | -| function | Prepared function call with or without parameters. | -| returns | Prepared remote call of transaction. | - -#### With custom nonce - -| Name | Description | -| --------------- | -------------------------------------------------- | -| contractAddress | Address of deployed contract. | -| function | Prepared function call with or without parameters. | -| nonce | Custom nonce value of the wallet. | -| returns | Prepared remote call of transaction. | - -### `getBalance` - -#### Get balance of wallet in native coin - -```java -BigInteger balance = wallet.getBalance().send(); -``` - -| Name | Description | -| ------- | -------------------------- | -| address | Wallet address. | -| returns | Prepared get balance call. | - -#### Get balance of wallet in token - -```java -Token token = new Token("L1_ADDRESS", "L2_ADDRESS", "SYMBOL", 18); -BigInteger = wallet.getBalance(token).send(); -``` - -| Name | Description | -| ------- | ------------------------------------- | -| token | Token object supported by ZkSync Era. | -| returns | Prepared get balance call. | - -#### Get balance of wallet by address of token - -```java -Token token = new Token("L1_ADDRESS", "L2_ADDRESS", "SYMBOL", 18); -BigInteger = wallet.getBalance("ADDRESS" ,token).send(); -``` - -| Name | Description | -| ------- | ------------------------------------- | -| address | Wallet address. | -| token | Token object supported by ZkSync Era. | -| returns | Prepared get balance call. | - -#### Get balance of wallet by address of token at block `DefaultBlockParameter` - -```java -BigInteger = wallet.getBalance(address, token, ZkBlockParameterName.COMMITTED).send(); -``` - -| Name | Description | -| ------- | ------------------------------------- | -| address | Wallet address. | -| token | Token object supported by ZkSync Era. | -| at | Block variant. | -| returns | Prepared get balance call. | - -### `getNonce` - -#### Get nonce for wallet at block `DefaultBlockParameter` - -```java -BigInteger = wallet.getNonce(ZkBlockParameterName.COMMITTED).send(); //ZkBlockParameterName.FINALIZED -``` - -| Name | Description | -| ------- | ------------------------ | -| at | Block variant. | -| returns | Prepared get nonce call. | - -#### Get nonce for wallet at block `COMMITTED` `ZkBlockParameterName` - -```java -BigInteger = wallet.getNonce().send(); -``` - -| Name | Description | -| ------- | ------------------------ | -| returns | Prepared get nonce call. | diff --git a/content/20.build/sdks/java/getting-started.md b/content/20.build/sdks/java/getting-started.md deleted file mode 100644 index 6804b316..00000000 --- a/content/20.build/sdks/java/getting-started.md +++ /dev/null @@ -1,1085 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Java | zkSync Docs ---- - -# Getting Started - -In this guide we will demonstrate how to: - -1. Connect to the zkSync network. -2. Deposit assets from Ethereum into zkSync. -3. Check balances. -4. Transfer and withdraw funds (native and ERC20 tokens). -5. Deploy a smart contract. -6. Deploy a smart contract with `create2`. - -## Prerequisites - -This guide assumes that you are familiar with the basics of [Java](https://docs.oracle.com/en/java/) programming -language. - -## Dependency - -To install the ZkSync2 Java SDK, just add the following dependency to your build file: ::: code-tabs - -Maven `pom.xml` - -```xml - - ... - - - io.zksync - zksync2 - 0.1.1 - - - org.web3j - core - 4.9.7 - - - -``` - -Gradle `build.gradle` - -```groovy -dependencies { - implementation "io.zksync:zksync2:0.1.1" -} -``` - -## Examples - -### Instantiating the SDK - -To start using this SDK, you just need to pass in a provider configuration. - -```java - -import io.zksync.protocol.ZkSync; -import org.web3j.protocol.http.HttpService; - -public class Main { - public static void main(String ...args) { - ZkSync zksync = zksync.build(new HttpService("")); - } -} - -``` - -### EthSigner - -```java -import io.zksync.crypto.signer.EthSigner; -import io.zksync.crypto.signer.PrivateKeyEthSigner; -import org.web3j.crypto.Credentials; - -public class Main { - public static void main(String ...args) { - long chainId = 123L;// Chainid of the ZkSync Era network - - Credentials credentials = Credentials.create("0x"); - - EthSigner signer = new PrivateKeyEthSigner(credentials, chainId); - } -} -``` - -:::tip Mainnet chain id: 324 Sepolia testnet chain id: 300 Local setup chain id: 270 ::: - -### ZkSync Era wallet - -You can connect the zkSync Era wallet for easier operations. - -```java -import io.zksync.crypto.signer.EthSigner; -import io.zksync.ZkSyncWallet; -import io.zksync.protocol.ZkSync; -import io.zksync.protocol.core.Token; - -public class Main { - public static void main(String ...args) { - ZkSync zksync; // Initialize client - EthSigner signer; // Initialize signer - - ZkSyncWallet wallet = new ZkSyncWallet(zksync, signer, Token.ETH); - } -} -``` - -## Examples - -### Transactions - -ZkSync2 supports Ethereum's `Legacy` and `EIP-1155` transactions, except for deploying contracts. - -### Transfer - -#### Transfer ETH - -```java -import io.zksync.abi.TransactionEncoder; -import io.zksync.crypto.signer.EthSigner; -import io.zksync.methods.request.Transaction; -import io.zksync.protocol.ZkSync; -import io.zksync.protocol.core.Token; -import io.zksync.protocol.core.ZkBlockParameterName; -import io.zksync.transaction.fee.DefaultTransactionFeeProvider; -import io.zksync.transaction.fee.ZkTransactionFeeProvider; -import io.zksync.transaction.type.Transaction712; -import io.zksync.transaction.response.ZkSyncTransactionReceiptProcessor; - -import org.web3j.protocol.core.methods.response.TransactionReceipt; -import org.web3j.protocol.core.methods.response.EthSendTransaction; -import org.web3j.protocol.exceptions.TransactionException; -import org.web3j.utils.Convert; -import org.web3j.utils.Numeric; - -import java.io.IOException; -import java.math.BigInteger; - -import static io.zksync.transaction.manager.ZkSyncTransactionManager.DEFAULT_POLLING_ATTEMPTS_PER_TX_HASH; -import static io.zksync.transaction.manager.ZkSyncTransactionManager.DEFAULT_POLLING_FREQUENCY; - -public class Main { - public static void main(String ...args) throws IOException, TransactionException { - ZkSync zksync; // Initialize client - EthSigner signer; // Initialize signer - ZkSyncTransactionReceiptProcessor processor = new ZkSyncTransactionReceiptProcessor(zksync, DEFAULT_POLLING_FREQUENCY, DEFAULT_POLLING_ATTEMPTS_PER_TX_HASH); - BigInteger chainId = zksync.ethChainId().send().getChainId(); - - BigInteger amountInWei = Convert.toWei("1", Convert.Unit.ETHER).toBigInteger(); - - BigInteger nonce = zksync - .ethGetTransactionCount(signer.getAddress(), ZkBlockParameterName.COMMITTED).send() - .getTransactionCount(); - - Transaction estimate = Transaction.createFunctionCallTransaction( - signer.getAddress(), - "0x", - BigInteger.ZERO, - BigInteger.ZERO, - amountInWei, - "0x" - ); - - ZkTransactionFeeProvider feeProvider = new DefaultTransactionFeeProvider(zksync, Token.ETH); - - Transaction712 transaction = new Transaction712( - chainId.longValue(), - nonce, - feeProvider.getGasLimit(estimate), - estimate.getTo(), - estimate.getValueNumber(), - estimate.getData(), - BigInteger.valueOf(100000000L), - feeProvider.getGasPrice(), - signer.getAddress(), - estimate.getEip712Meta() - ); - - String signature = signer.getDomain().thenCompose(domain -> signer.signTypedData(domain, transaction)).join(); - byte[] message = TransactionEncoder.encode(transaction, TransactionEncoder.getSignatureData(signature)); - - EthSendTransaction sent = zksync.ethSendRawTransaction(Numeric.toHexString(message)).send(); - - TransactionReceipt receipt = processor.waitForTransactionReceipt(sent.getResult()); - } -} -``` - -#### Transfer ERC20 tokens - -```java -import io.zksync.abi.TransactionEncoder; -import io.zksync.crypto.signer.EthSigner; -import io.zksync.methods.request.Transaction; -import io.zksync.protocol.ZkSync; -import io.zksync.protocol.core.Token; -import io.zksync.protocol.core.ZkBlockParameterName; -import io.zksync.transaction.fee.DefaultTransactionFeeProvider; -import io.zksync.transaction.fee.ZkTransactionFeeProvider; -import io.zksync.transaction.response.ZkSyncTransactionReceiptProcessor; -import io.zksync.transaction.type.Transaction712; -import io.zksync.wrappers.ERC20; -import org.web3j.abi.FunctionEncoder; -import org.web3j.protocol.core.methods.response.EthSendTransaction; -import org.web3j.protocol.core.methods.response.TransactionReceipt; -import org.web3j.protocol.exceptions.TransactionException; -import org.web3j.utils.Numeric; - -import java.io.IOException; -import java.math.BigInteger; - -import static io.zksync.transaction.manager.ZkSyncTransactionManager.DEFAULT_POLLING_ATTEMPTS_PER_TX_HASH; -import static io.zksync.transaction.manager.ZkSyncTransactionManager.DEFAULT_POLLING_FREQUENCY; - -public class Main { - public static void main(String ...args) throws IOException, TransactionException { - ZkSync zksync; // Initialize client - EthSigner signer; // Initialize signer - ZkSyncTransactionReceiptProcessor processor = new ZkSyncTransactionReceiptProcessor(zksync, DEFAULT_POLLING_FREQUENCY, DEFAULT_POLLING_ATTEMPTS_PER_TX_HASH); - BigInteger chainId = zksync.ethChainId().send().getChainId(); - - // Here we're getting tokens supported by ZkSync - Token token = zksync.zksGetConfirmedTokens(0, (short) 100).send() - .getResult().stream() - .findAny().orElseThrow(IllegalArgumentException::new); - - BigInteger amount = token.toBigInteger(1.0); - - BigInteger nonce = zksync - .ethGetTransactionCount(signer.getAddress(), ZkBlockParameterName.COMMITTED).send() - .getTransactionCount(); - String calldata = FunctionEncoder.encode(ERC20.encodeTransfer("0x", amount)); - - Transaction estimate = Transaction.createFunctionCallTransaction( - signer.getAddress(), - token.getL2Address(), - BigInteger.ZERO, - BigInteger.ZERO, - calldata - ); - - ZkTransactionFeeProvider feeProvider = new DefaultTransactionFeeProvider(zksync, Token.ETH); - - Transaction712 transaction = new Transaction712( - chainId.longValue(), - nonce, - feeProvider.getGasLimit(estimate), - estimate.getTo(), - estimate.getValueNumber(), - estimate.getData(), - BigInteger.valueOf(100000000L), - feeProvider.getGasPrice(), - signer.getAddress(), - estimate.getEip712Meta() - ); - - String signature = signer.getDomain().thenCompose(domain -> signer.signTypedData(domain, transaction)).join(); - byte[] message = TransactionEncoder.encode(transaction, TransactionEncoder.getSignatureData(signature)); - - EthSendTransaction sent = zksync.ethSendRawTransaction(Numeric.toHexString(message)).send(); - - TransactionReceipt receipt = processor.waitForTransactionReceipt(sent.getResult()); - } -} -``` - -#### Transfer native coins via ZkSyncWallet - -```java -import io.zksync.ZkSyncWallet; -import io.zksync.protocol.core.Token; -import org.web3j.protocol.core.methods.response.TransactionReceipt; - -import java.math.BigDecimal; -import java.math.BigInteger; - -public class Main { - public static void main(String... args) throws Exception { - ZkSyncWallet wallet; // Initialize wallet - - BigInteger amount = Token.ETH.toBigInteger(0.5); - - TransactionReceipt receipt = wallet.transfer("0x", amount).send(); - - //You can check balance - BigInteger balance = wallet.getBalance().send(); - - //Also, you can convert amount number to decimal - BigDecimal decimalBalance = Token.ETH.intoDecimal(balance); - } -} -``` - -#### Transfer ERC20 coins via ZkSyncWallet - -```java -import io.zksync.ZkSyncWallet; -import io.zksync.protocol.core.Token; -import org.web3j.protocol.core.methods.response.TransactionReceipt; - -import java.math.BigDecimal; -import java.math.BigInteger; - -public class Main { - public static void main(String... args) throws Exception { - ZkSyncWallet wallet; // Initialize wallet - - Token token = new Token("L1_ADDRESS", "L2_ADDRESS", "SYMBOL", 18); - - BigInteger amount = Token.ETH.toBigInteger(0.5); - - TransactionReceipt receipt = wallet.transfer("0x", amount, token).send(); - - //You can check balance - BigInteger balance = wallet.getBalance().send(); - - //Also, you can convert amount number to decimal - BigDecimal decimalBalance = Token.ETH.intoDecimal(balance); - } -} -``` - -### Deposit - -#### Deposit ETH - -```java -import io.zksync.protocol.ZkSync; -import org.web3j.crypto.Credentials; -import org.web3j.tx.RawTransactionManager; -import org.web3j.tx.TransactionManager; -import org.web3j.tx.gas.ContractGasProvider; -import org.web3j.protocol.core.methods.response.TransactionReceipt; -import io.zksync.protocol.core.Token; -import io.zksync.protocol.provider.EthereumProvider; -import org.web3j.protocol.Web3j; -import org.web3j.tx.gas.StaticGasProvider; -import org.web3j.utils.Convert; - -import java.io.IOException; -import java.math.BigInteger; - -public class Main { - public static void main(String... args) throws IOException { - ZkSync zksync; // Initialize client - Web3j web3j; // Initialize web3j client - Credentials credentials; // Initialize credentials - BigInteger chainId; // Initialize chainId - - TransactionManager manager = new RawTransactionManager(web3j, credentials, chainId.longValue()); - BigInteger gasPrice = web3j.ethGasPrice().send().getGasPrice(); - ContractGasProvider gasProvider = new StaticGasProvider(gasPrice, BigInteger.valueOf(300_000L)); - TransactionReceipt receipt = EthereumProvider - .load(zksync, web3j, manager, gasProvider).join() - .deposit(Token.ETH, Convert.toWei("0.001", Convert.Unit.ETHER).toBigInteger(), BigInteger.ZERO, credentials.getAddress()).join(); - - System.out.println(receipt); - } -} -``` - -#### Deposit ERC20 tokens - -```java -import io.zksync.protocol.ZkSync; -import org.web3j.crypto.Credentials; -import org.web3j.tx.RawTransactionManager; -import org.web3j.tx.TransactionManager; -import org.web3j.tx.gas.ContractGasProvider; -import org.web3j.protocol.core.methods.response.TransactionReceipt; -import io.zksync.protocol.core.Token; -import io.zksync.protocol.provider.EthereumProvider; -import org.web3j.protocol.Web3j; -import org.web3j.tx.gas.StaticGasProvider; -import org.web3j.utils.Convert; - -import java.io.IOException; -import java.math.BigInteger; - -public class Main { - public static void main(String... args) throws IOException { - ZkSync zksync; // Initialize client - Web3j web3j; // Initialize web3j client - Credentials credentials; // Initialize credentials - BigInteger chainId; // Initialize chainId - Token token = new Token("L1_ADDRESS", "L2_ADDRESS", "SYMBOL", 18); - - TransactionManager manager = new RawTransactionManager(web3j, credentials, chainId.longValue()); - BigInteger gasPrice = web3j.ethGasPrice().send().getGasPrice(); - ContractGasProvider gasProvider = new StaticGasProvider(gasPrice, BigInteger.valueOf(300_000L)); - TransactionReceipt receipt = EthereumProvider - .load(zksync, web3j, manager, gasProvider).join() - .deposit(token, Convert.toWei("0.001", Convert.Unit.ETHER).toBigInteger(), BigInteger.ZERO, credentials.getAddress()).join(); - - System.out.println(receipt); - } -} -``` - -### Withdraw - -#### Withdraw ETH - -```java -import io.zksync.abi.TransactionEncoder; -import io.zksync.crypto.signer.EthSigner; -import io.zksync.methods.request.Transaction; -import io.zksync.protocol.ZkSync; -import io.zksync.protocol.core.Token; -import io.zksync.protocol.core.ZkBlockParameterName; -import io.zksync.transaction.fee.DefaultTransactionFeeProvider; -import io.zksync.transaction.fee.ZkTransactionFeeProvider; -import io.zksync.transaction.type.Transaction712; -import io.zksync.wrappers.IL2Bridge; -import io.zksync.transaction.response.ZkSyncTransactionReceiptProcessor; - -import org.web3j.abi.FunctionEncoder; -import org.web3j.abi.datatypes.Address; -import org.web3j.abi.datatypes.Function; -import org.web3j.protocol.core.methods.response.TransactionReceipt; -import org.web3j.protocol.core.methods.response.EthSendTransaction; -import org.web3j.protocol.exceptions.TransactionException; -import org.web3j.utils.Numeric; - -import java.io.IOException; -import java.math.BigInteger; -import java.util.Arrays; -import java.util.Collections; - -import static io.zksync.transaction.manager.ZkSyncTransactionManager.DEFAULT_POLLING_ATTEMPTS_PER_TX_HASH; -import static io.zksync.transaction.manager.ZkSyncTransactionManager.DEFAULT_POLLING_FREQUENCY; -import static io.zksync.utils.ZkSyncAddresses.L2_ETH_TOKEN_ADDRESS; - -public class Main { - public static void main(String ...args) throws IOException, TransactionException { - ZkSync zksync; // Initialize client - EthSigner signer; // Initialize signer - ZkSyncTransactionReceiptProcessor processor = new ZkSyncTransactionReceiptProcessor(zksync, DEFAULT_POLLING_FREQUENCY, DEFAULT_POLLING_ATTEMPTS_PER_TX_HASH); - - BigInteger chainId = zksync.ethChainId().send().getChainId(); - - BigInteger nonce = zksync - .ethGetTransactionCount(signer.getAddress(), ZkBlockParameterName.COMMITTED).send() - .getTransactionCount(); - - // Get address of the default bridge contract - String l2EthBridge = L2_ETH_TOKEN_ADDRESS; - final Function withdraw = new Function( - IL2Bridge.FUNC_WITHDRAW, - Arrays.asList(new Address("TO_ADDRESS")), - Collections.emptyList()); - - String calldata = FunctionEncoder.encode(withdraw); - - BigInteger amount; // Amount you want to withdraw - - Transaction estimate = Transaction.createFunctionCallTransaction( - signer.getAddress(), - l2EthBridge, - BigInteger.ZERO, - BigInteger.ZERO, - amount, - calldata - ); - - ZkTransactionFeeProvider feeProvider = new DefaultTransactionFeeProvider(zksync, Token.ETH); - - Transaction712 transaction = new Transaction712( - chainId.longValue(), - nonce, - feeProvider.getGasLimit(estimate), - estimate.getTo(), - estimate.getValueNumber(), - estimate.getData(), - BigInteger.valueOf(100000000L), - feeProvider.getGasPrice(), - signer.getAddress(), - estimate.getEip712Meta() - ); - - String signature = signer.getDomain().thenCompose(domain -> signer.signTypedData(domain, transaction)).join(); - byte[] message = TransactionEncoder.encode(transaction, TransactionEncoder.getSignatureData(signature)); - - EthSendTransaction sent = zksync.ethSendRawTransaction(Numeric.toHexString(message)).send(); - - TransactionReceipt receipt = processor.waitForTransactionReceipt(sent.getResult()); - } -} -``` - -#### Withdraw ERC20 tokens - -```java -import io.zksync.abi.TransactionEncoder; -import io.zksync.crypto.signer.EthSigner; -import io.zksync.methods.request.Transaction; -import io.zksync.protocol.ZkSync; -import io.zksync.protocol.core.Token; -import io.zksync.protocol.core.ZkBlockParameterName; -import io.zksync.transaction.fee.DefaultTransactionFeeProvider; -import io.zksync.transaction.fee.ZkTransactionFeeProvider; -import io.zksync.transaction.response.ZkSyncTransactionReceiptProcessor; -import io.zksync.transaction.type.Transaction712; -import io.zksync.wrappers.IL2Bridge; -import org.web3j.abi.FunctionEncoder; -import org.web3j.abi.datatypes.Address; -import org.web3j.abi.datatypes.Function; -import org.web3j.abi.datatypes.generated.Uint256; -import org.web3j.protocol.core.methods.response.EthSendTransaction; -import org.web3j.protocol.core.methods.response.TransactionReceipt; -import org.web3j.protocol.exceptions.TransactionException; -import org.web3j.utils.Numeric; - -import java.io.IOException; -import java.math.BigInteger; -import java.util.Arrays; -import java.util.Collections; - -import static io.zksync.transaction.manager.ZkSyncTransactionManager.DEFAULT_POLLING_ATTEMPTS_PER_TX_HASH; -import static io.zksync.transaction.manager.ZkSyncTransactionManager.DEFAULT_POLLING_FREQUENCY; - -public class Main { - public static void main(String ...args) throws IOException, TransactionException { - ZkSync zksync; // Initialize client - EthSigner signer; // Initialize signer - - ZkSyncTransactionReceiptProcessor processor = new ZkSyncTransactionReceiptProcessor(zksync, DEFAULT_POLLING_FREQUENCY, DEFAULT_POLLING_ATTEMPTS_PER_TX_HASH); - - BigInteger chainId = zksync.ethChainId().send().getChainId(); - - BigInteger nonce = zksync - .ethGetTransactionCount(signer.getAddress(), ZkBlockParameterName.COMMITTED).send() - .getTransactionCount(); - - Token token = new Token("L1_ADDRESS", "L2_ADDRESS", "SYMBOL", 18); - - BigInteger amount; - - // Get address of the default bridge contract (ERC20) - String l2Erc20Bridge = zksync.zksGetBridgeContracts().send().getResult().getL2Erc20DefaultBridge(); - final Function withdraw = new Function( - IL2Bridge.FUNC_WITHDRAW, - Arrays.asList(new Address("TO_ADDRESS"), - new Address(token.getL2Address()), - new Uint256(amount)), - Collections.emptyList()); - - String calldata = FunctionEncoder.encode(withdraw); - - Transaction estimate = Transaction.createFunctionCallTransaction( - signer.getAddress(), - l2Erc20Bridge, - BigInteger.ZERO, - BigInteger.ZERO, - calldata - ); - - ZkTransactionFeeProvider feeProvider = new DefaultTransactionFeeProvider(zksync, Token.ETH); - - Transaction712 transaction = new Transaction712( - chainId.longValue(), - nonce, - feeProvider.getGasLimit(estimate), - estimate.getTo(), - estimate.getValueNumber(), - estimate.getData(), - BigInteger.valueOf(100000000L), - feeProvider.getGasPrice(), - signer.getAddress(), - estimate.getEip712Meta() - ); - - String signature = signer.getDomain().thenCompose(domain -> signer.signTypedData(domain, transaction)).join(); - byte[] message = TransactionEncoder.encode(transaction, TransactionEncoder.getSignatureData(signature)); - - EthSendTransaction sent = zksync.ethSendRawTransaction(Numeric.toHexString(message)).send(); - - TransactionReceipt receipt = processor.waitForTransactionReceipt(sent.getResult()); - } -} -``` - -#### Withdraw funds via ZkSyncWallet - -```java -import io.zksync.ZkSyncWallet; -import io.zksync.protocol.core.Token; -import org.web3j.protocol.core.methods.response.TransactionReceipt; - -import java.math.BigInteger; - -public class Main { - public static void main(String... args) { - ZkSyncWallet wallet; // Initialize wallet - - BigInteger amount = Token.ETH.toBigInteger(0.5); - - // ETH By default - TransactionReceipt receipt = wallet.withdraw("0x", amount).send(); - - // Also we can withdraw ERC20 token - Token token; - - // ERC20 token - TransactionReceipt receipt = wallet.withdraw("0x", amount, token).send(); - } -} -``` - -#### Finalize Withdraw - -```java -import io.zksync.protocol.ZkSync; -import io.zksync.protocol.provider.EthereumProvider; -import org.web3j.crypto.Credentials; -import org.web3j.protocol.Web3j; -import org.web3j.protocol.core.methods.response.TransactionReceipt; -import org.web3j.tx.RawTransactionManager; -import org.web3j.tx.TransactionManager; -import org.web3j.tx.gas.ContractGasProvider; -import org.web3j.tx.gas.StaticGasProvider; - -import java.math.BigInteger; - -public class Main { - public static void main(String... args) { - Web3j web3j; //Initialize web3j - ZkSync zksync; //Initialize zksync - Credentials credentials; //Initialize credentials - BigInteger chainId; //Initialize chainId - - TransactionManager manager = new RawTransactionManager(web3j, credentials, chainId.longValue()); - BigInteger gasPrice = web3j.ethGasPrice().send().getGasPrice(); - ContractGasProvider gasProvider = new StaticGasProvider(gasPrice, BigInteger.valueOf(300_000L)); - TransactionReceipt receipt = EthereumProvider - .load(zksync, web3j, manager, gasProvider).join() - .finalizeWithdraw("TRANSACTION_HASH", 0); - } -} -``` - -### Deploy contract - -With zkSync Era, you can deploy a contract, using the `create` method, by transforming the contract into binary and -deploying it to the zkSync Era network. - -Find below some smart contract examples: - -- [Storage](https://github.com/zksync-sdk/zksync2-python/blob/master/examples/solidity/storage/Storage.sol): Contract - without constructor. -- [Incrementer](https://github.com/zksync-sdk/zksync2-python/blob/master/examples/solidity/incrementer/Incrementer.sol): - Contract with constructor. -- [Demo](https://github.com/zksync-sdk/zksync2-python/blob/master/examples/solidity/demo/Demo.sol): Contract that has a - dependency on [Foo](https://github.com/zksync-sdk/zksync2-python/blob/master/examples/solidity/demo/Foo.sol) contract. - -Follow -[this guide to compile Solidity smart contracts using the `zksolc` compiler](https://github.com/zksync-sdk/zksync2-python/blob/master/examples/README.md). -The compiler generates a `combined.json` file that contains the bytecode and ABI of a smart contract. Those files are -used in the following examples. - -#### Deploy contract (create2) [EIP-1014](https://eips.ethereum.org/EIPS/eip-1014) - -Code: - -```java -import io.zksync.abi.TransactionEncoder; -import io.zksync.crypto.signer.EthSigner; -import io.zksync.crypto.signer.PrivateKeyEthSigner; -import io.zksync.methods.request.Transaction; -import io.zksync.protocol.ZkSync; -import io.zksync.protocol.core.Token; -import io.zksync.transaction.fee.DefaultTransactionFeeProvider; -import io.zksync.transaction.fee.ZkTransactionFeeProvider; -import io.zksync.transaction.type.Transaction712; -import io.zksync.utils.ContractDeployer; -import org.web3j.abi.datatypes.Address; -import org.web3j.crypto.Credentials; -import org.web3j.protocol.core.DefaultBlockParameterName; -import org.web3j.protocol.core.methods.response.TransactionReceipt; -import org.web3j.protocol.core.methods.response.EthSendTransaction; -import io.zksync.transaction.response.ZkSyncTransactionReceiptProcessor; - - -import org.web3j.protocol.exceptions.TransactionException; -import org.web3j.protocol.http.HttpService; -import org.web3j.utils.Numeric; - -import java.io.IOException; -import java.math.BigInteger; -import java.security.SecureRandom; - -import static io.zksync.transaction.manager.ZkSyncTransactionManager.DEFAULT_POLLING_ATTEMPTS_PER_TX_HASH; -import static io.zksync.transaction.manager.ZkSyncTransactionManager.DEFAULT_POLLING_FREQUENCY; - -public class Main { - public static void main(String... args) throws TransactionException, IOException { - ZkSync zksync = ZkSync.build(new HttpService("")); - Credentials credentials = Credentials.create("PRIVATE_KEY"); // Initialize signer - BigInteger chainId = zksync.ethChainId().send().getChainId(); - EthSigner signer = new PrivateKeyEthSigner(credentials, chainId.longValue()); - ZkSyncTransactionReceiptProcessor processor = new ZkSyncTransactionReceiptProcessor(zksync, DEFAULT_POLLING_FREQUENCY, DEFAULT_POLLING_ATTEMPTS_PER_TX_HASH); - - String binary = "0x"; - - byte[] salt = SecureRandom.getSeed(32); - - // Here we can precompute contract address before its deploying - String precomputedAddress = ContractDeployer.computeL2Create2Address(new Address(signer.getAddress()), Numeric.hexStringToByteArray(binary), new byte[]{}, salt).getValue(); - - BigInteger nonce = zksync - .ethGetTransactionCount(credentials.getAddress(), DefaultBlockParameterName.PENDING).send() - .getTransactionCount(); - - Transaction estimate = Transaction.create2ContractTransaction( - credentials.getAddress(), - BigInteger.ZERO, - BigInteger.ZERO, - binary, - "0x", - salt - ); - - ZkTransactionFeeProvider feeProvider = new DefaultTransactionFeeProvider(zksync, Token.ETH); - - Transaction712 transaction = new Transaction712( - chainId.longValue(), - nonce, - feeProvider.getGasLimit(estimate), - estimate.getTo(), - estimate.getValueNumber(), - estimate.getData(), - BigInteger.valueOf(100000000L), - feeProvider.getGasPrice(), - credentials.getAddress(), - estimate.getEip712Meta() - ); - - String signature = signer.getDomain().thenCompose(domain -> signer.signTypedData(domain, transaction)).join(); - byte[] message = TransactionEncoder.encode(transaction, TransactionEncoder.getSignatureData(signature)); - - EthSendTransaction sent = zksync.ethSendRawTransaction(Numeric.toHexString(message)).send(); - - TransactionReceipt receipt = processor.waitForTransactionReceipt(sent.getResult()); - } -} -``` - -#### Deploy contract (create) - -Code: - -```java -import io.zksync.abi.TransactionEncoder; -import io.zksync.crypto.signer.EthSigner; -import io.zksync.methods.request.Transaction; -import io.zksync.protocol.ZkSync; -import io.zksync.protocol.core.Token; -import io.zksync.protocol.core.ZkBlockParameterName; -import io.zksync.transaction.fee.DefaultTransactionFeeProvider; -import io.zksync.transaction.fee.ZkTransactionFeeProvider; -import io.zksync.transaction.type.Transaction712; -import io.zksync.utils.ZkSyncAddresses; -import io.zksync.wrappers.NonceHolder; -import org.web3j.protocol.core.methods.response.TransactionReceipt; -import org.web3j.protocol.core.methods.response.EthSendTransaction; -import io.zksync.transaction.response.ZkSyncTransactionReceiptProcessor; - -import org.web3j.tx.ReadonlyTransactionManager; -import org.web3j.tx.gas.DefaultGasProvider; -import org.web3j.utils.Numeric; - -import java.math.BigInteger; - -import static io.zksync.transaction.manager.ZkSyncTransactionManager.DEFAULT_POLLING_ATTEMPTS_PER_TX_HASH; -import static io.zksync.transaction.manager.ZkSyncTransactionManager.DEFAULT_POLLING_FREQUENCY; - -public class Main { - public static void main(String... args) throws Exception { - ZkSync zksync; // Initialize client - EthSigner signer; // Initialize signer - ZkSyncTransactionReceiptProcessor processor = new ZkSyncTransactionReceiptProcessor(zksync, DEFAULT_POLLING_FREQUENCY, DEFAULT_POLLING_ATTEMPTS_PER_TX_HASH); - - String binary = "0x"; - - BigInteger chainId = zksync.ethChainId().send().getChainId(); - - NonceHolder nonceHolder = NonceHolder.load(ZkSyncAddresses.NONCE_HOLDER_ADDRESS, zksync, new ReadonlyTransactionManager(zksync, signer.getAddress()), new DefaultGasProvider()); - - BigInteger deploymentNonce = nonceHolder.getDeploymentNonce(signer.getAddress()).send(); - - BigInteger nonce = zksync - .ethGetTransactionCount(signer.getAddress(), ZkBlockParameterName.COMMITTED).send() - .getTransactionCount(); - - Transaction estimate = Transaction.createContractTransaction( - signer.getAddress(), - BigInteger.ZERO, - BigInteger.ZERO, - binary, - "0x" - ); - - ZkTransactionFeeProvider feeProvider = new DefaultTransactionFeeProvider(zksync, Token.ETH); - - Transaction712 transaction = new Transaction712( - chainId.longValue(), - nonce, - feeProvider.getGasLimit(estimate), - estimate.getTo(), - estimate.getValueNumber(), - estimate.getData(), - BigInteger.valueOf(100000000L), - feeProvider.getGasPrice(), - signer.getAddress(), - estimate.getEip712Meta() - ); - - String signature = signer.getDomain().thenCompose(domain -> signer.signTypedData(domain, transaction)).join(); - byte[] message = TransactionEncoder.encode(transaction, TransactionEncoder.getSignatureData(signature)); - - EthSendTransaction sent = zksync.ethSendRawTransaction(Numeric.toHexString(message)).send(); - - // You can check transaction status as the same way as in Web3 - TransactionReceipt receipt = processor.waitForTransactionReceipt(sent.getResult()); - } -} -``` - -#### Deploy contract via ZkSyncWallet - -Code: - -```java -import io.zksync.ZkSyncWallet; -import org.web3j.protocol.core.methods.response.TransactionReceipt; -import org.web3j.utils.Numeric; - -public class Main { - public static void main(String ...args) { - ZkSyncWallet wallet; // Initialize wallet - - TransactionReceipt receipt = wallet.deploy(Numeric.hexStringToByteArray("0x")).send(); - } -} -``` - -#### Deploy contract with constructor via ZkSyncWallet - -```java -import io.zksync.ZkSyncWallet; -import org.web3j.abi.FunctionEncoder; -import org.web3j.abi.datatypes.Type; -import org.web3j.abi.datatypes.Utf8String; -import org.web3j.abi.datatypes.generated.Uint256; -import org.web3j.protocol.core.methods.response.TransactionReceipt; -import org.web3j.utils.Numeric; - -import java.math.BigInteger; -import java.util.ArrayList; -import java.util.List; - -public class Main { - public static void main(String ...args) { - ZkSyncWallet wallet; // Initialize wallet - - String name = "NAME"; - String symbol = "SYMBOL"; - BigInteger amount = new BigInteger("666234").multiply(new BigInteger("10").pow(18)); - - List inputParameter = new ArrayList<>(); - inputParameter.add(new Utf8String(name)); - inputParameter.add(new Utf8String(symbol)); - inputParameter.add(new Uint256(amount)); - - String bytecode = "0x"; - String calldata = FunctionEncoder.encodeConstructor(inputParameter); - TransactionReceipt receipt = wallet.deploy(Numeric.hexStringToByteArray(bytecode), Numeric.hexStringToByteArray(calldata)).send(); - } -} -``` - -### Contract interaction (execute) - -#### Execute contract - -```java -import io.zksync.abi.TransactionEncoder; -import io.zksync.crypto.signer.EthSigner; -import io.zksync.methods.request.Transaction; -import io.zksync.protocol.ZkSync; -import io.zksync.protocol.core.Token; -import io.zksync.protocol.core.ZkBlockParameterName; -import io.zksync.transaction.fee.DefaultTransactionFeeProvider; -import io.zksync.transaction.fee.ZkTransactionFeeProvider; -import io.zksync.transaction.type.Transaction712; -import io.zksync.transaction.response.ZkSyncTransactionReceiptProcessor; - -import org.web3j.abi.FunctionEncoder; -import org.web3j.abi.datatypes.Function; -import org.web3j.abi.datatypes.generated.Uint256; -import org.web3j.protocol.core.methods.response.TransactionReceipt; -import org.web3j.protocol.core.methods.response.EthSendTransaction; -import org.web3j.protocol.exceptions.TransactionException; -import org.web3j.utils.Numeric; - -import java.io.IOException; -import java.math.BigInteger; -import java.util.Collections; - -import static io.zksync.transaction.manager.ZkSyncTransactionManager.DEFAULT_POLLING_ATTEMPTS_PER_TX_HASH; -import static io.zksync.transaction.manager.ZkSyncTransactionManager.DEFAULT_POLLING_FREQUENCY; - -public class Main { - public static void main(String... args) throws IOException, TransactionException { - ZkSync zksync; // Initialize client - EthSigner signer; // Initialize signer - ZkSyncTransactionReceiptProcessor processor = new ZkSyncTransactionReceiptProcessor(zksync, DEFAULT_POLLING_FREQUENCY, DEFAULT_POLLING_ATTEMPTS_PER_TX_HASH); - - BigInteger chainId = zksync.ethChainId().send().getChainId(); - - BigInteger nonce = zksync - .ethGetTransactionCount(signer.getAddress(), ZkBlockParameterName.COMMITTED).send() - .getTransactionCount(); - - String contractAddress = "0x"; - - Function contractFunction = new Function( - "increment", - Collections.singletonList(new Uint256(BigInteger.ONE)), - Collections.emptyList()); - - String calldata = FunctionEncoder.encode(function); - - Transaction estimate = Transaction.createFunctionCallTransaction( - signer.getAddress(), - contractAddress, - BigInteger.ZERO, - BigInteger.ZERO, - calldata - ); - - ZkTransactionFeeProvider feeProvider = new DefaultTransactionFeeProvider(zksync, Token.ETH); - - Transaction712 transaction = new Transaction712( - chainId.longValue(), - nonce, - feeProvider.getGasLimit(estimate), - estimate.getTo(), - estimate.getValueNumber(), - estimate.getData(), - BigInteger.valueOf(100000000L), - feeProvider.getGasPrice(), - signer.getAddress(), - estimate.getEip712Meta() - ); - - String signature = signer.getDomain().thenCompose(domain -> signer.signTypedData(domain, transaction)).join(); - byte[] message = TransactionEncoder.encode(transaction, TransactionEncoder.getSignatureData(signature)); - - EthSendTransaction sent = zksync.ethSendRawTransaction(Numeric.toHexString(message)).send(); - TransactionReceipt receipt = processor.waitForTransactionReceipt(sent.getResult()); - } -} -``` - -#### Execute contact via ZkSyncWallet - -```java -import io.zksync.ZkSyncWallet; -import org.web3j.abi.datatypes.Function; -import org.web3j.abi.datatypes.generated.Uint256; -import org.web3j.protocol.core.methods.response.TransactionReceipt; - -import java.math.BigInteger; -import java.util.Collections; - -public class Main { - public static void main(String... args) { - ZkSyncWallet wallet; // Initialize wallet - - String contractAddress = "0x"; - - // Example contract function - Function contractFunction = new Function( - "increment", - Collections.singletonList(new Uint256(BigInteger.ONE)), - Collections.emptyList()); - - TransactionReceipt receipt = wallet.execute(contractAddress, contractFunction).send(); - } -} -``` - -#### Execute contract via Web3j generic contract - -```java -import io.zksync.crypto.signer.EthSigner; -import io.zksync.protocol.ZkSync; -import io.zksync.protocol.core.Token; -import io.zksync.transaction.fee.DefaultTransactionFeeProvider; -import io.zksync.transaction.fee.ZkTransactionFeeProvider; -import io.zksync.transaction.manager.ZkSyncTransactionManager; -import org.web3j.protocol.core.methods.response.TransactionReceipt; -import org.web3j.tx.gas.DefaultGasProvider; - -import java.math.BigInteger; - -public class Main { - public static void main(String... args) { - ZkSync zksync; // Initialize client - EthSigner signer; // Initialize signer - - ZkTransactionFeeProvider feeProvider = new DefaultTransactionFeeProvider(zksync, Token.ETH); - ZkSyncTransactionManager transactionManager = new ZkSyncTransactionManager(zksync, signer, feeProvider); - - // Wrapper class of a contract generated by Web3j or Epirus ClI - SomeContract contract = SomeContract.load("0x", zksync, transactionManager, new DefaultGasProvider()).send(); - - // Generated method in wrapper - TransactionReceipt receipt = contract.increment(BigInteger.ONE).send(); - - //The same way you can call read function - - BigInteger result = contract.get().send(); - } -} -``` - -### Estimate transaction fee - -#### Get fee via TransactionFeeProvider - -```java -import io.zksync.methods.request.Transaction; -import io.zksync.protocol.ZkSync; -import io.zksync.protocol.core.Token; -import io.zksync.transaction.fee.DefaultTransactionFeeProvider; -import io.zksync.transaction.fee.Fee; -import io.zksync.transaction.fee.ZkTransactionFeeProvider; - -public class Main { - public static void main(String ...args) { - ZkSync zksync; // Initialize client - - ZkTransactionFeeProvider feeProvider = new DefaultTransactionFeeProvider(zksync, Token.ETH); - - Transaction forEstimate; // Create transaction as described above - - Fee fee = feeProvider.getFee(forEstimate); - } -} -``` - -#### Get price of the transaction execution (currently not working properly) - -::: warning Feature currently unsupported. Under development ::: - -```java -import io.zksync.methods.request.Transaction; -import io.zksync.protocol.ZkSync; -import io.zksync.transaction.fee.Fee; - -import java.io.IOException; -import java.math.BigInteger; - -public class Main { - public static void main(String... args) throws IOException { - ZkSync zksync; // Initialize client - - Transaction forEstimate; // Create transaction as described above - - Fee fee = zksync.zksEstimateFee(forEstimate).send().getResult(); - - // Also possible to use eth_estimateGas - BigInteger gasUsed = zksync.ethEstimateGas(forEstimate).send().getAmountUsed(); - } -} -``` diff --git a/content/20.build/sdks/java/providers.md b/content/20.build/sdks/java/providers.md deleted file mode 100644 index 893509e3..00000000 --- a/content/20.build/sdks/java/providers.md +++ /dev/null @@ -1,357 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Java SDK Providers | zkSync Docs ---- - -# Providers - -Providers are objects that wrap interactions with the zkSync Era node. If you are new to the concept of providers in -`web3`, check out the [Web3j docs](https://docs.web3j.io/4.9.8/getting_started/interacting_with_node/). - -zkSync Era fully supports the Ethereum Web3 JSON-RPC API, so you can use the provider objects from `web3j`. However, -zkSync API provides some additional JSON-RPC methods, which allow: - -- Easy tracking of L1<->L2 transactions. -- Different stages of finality for transactions. By default, the RPC returns information about the last state processed - by the server, but some use cases may require tracking "finalized" transactions only. - -### `Initialize` - -```java -import io.zksync.protocol.ZkSync; -import org.web3j.protocol.http.HttpService; - -public class Main { - public static void main(String ...args) { - ZkSync zksync = ZkSync.build(new HttpService("https://sepolia.era.zksync.dev")); - } -} -``` - -#### Inputs and outputs - -| Name | Description | -| ------------ | ------------------------------------ | -| web3jService | URL of the zkSync Era operator node. | -| returns | `Provider` object. | - -### `zksGetAllAccountBalances` - -Get all known balances for a given account. - -Example: - -```java -import io.zksync.protocol.ZkSync; -import org.web3j.protocol.http.HttpService; - -public class Main { - public static void main(String ...args) { - ZkSync zksync = ZkSync.build(new HttpService("https://sepolia.era.zksync.dev")); - ZksAccountBalances response = zksync.zksGetAllAccountBalances("ADDRESS").send(); - } -} -``` - -#### Inputs and outputs - -| Name | Description | -| ------- | ---------------------------------------------------------------------------- | -| address | The user address with balances to check. | -| returns | 'ZksAccountBalances': List of all balances where account has non-zero value. | - -### `zksGetConfirmedTokens` - -Get list of the tokens supported by ZkSync Era. The tokens are returned in alphabetical order by their symbol. This -means that the token id is its position in an alphabetically sorted array of tokens. - -Example: - -```java -import io.zksync.protocol.ZkSync; -import org.web3j.protocol.http.HttpService; - -public class Main { - public static void main(String ...args) { - ZksTokens response = zksync.zksGetConfirmedTokens(offset, limit).send(); } -} -``` - -#### Inputs and outputs - -| Name | Description | -| ------- | -------------------------------------- | -| from | Offset of tokens. | -| list | Limit of amount of tokens to return. | -| returns | Prepared get confirmed tokens request. | - -### `zksGetBridgeContracts` - -Get default bridges addresses deployed on L1 and L2. - -Example: - -```java -import io.zksync.protocol.ZkSync; -import org.web3j.protocol.http.HttpService; -import io.zksync.protocol.core.BridgeAddresses; - -public class Main { - public static void main(String ...args) { - BridgeAddresses bridgeAddresses = zksync.zksGetBridgeContracts().sendAsync().join().getResult(); -} -``` - -#### Inputs and outputs - -| Name | Description | -| ------- | ------------------------------------- | -| from | Offset of tokens. | -| list | Limit of amount of tokens to return. | -| returns | Prepared get bridge contract request. | - -### `zksMainContract` - -Get address of main contract for current network chain. - -Example: - -```java -import io.zksync.protocol.ZkSync; -import org.web3j.protocol.http.HttpService; - -public class Main { - public static void main(String ...args) { - String mainContract = zksync.zksMainContract().sendAsync().join().getResult(); -} -``` - -#### Inputs and outputs - -| Name | Description | -| ------- | ------------------------------- | -| returns | Prepared main contract request. | - -### `zksGetTestnetPaymaster` - -Get the address of the testnet paymaster; i.e. the paymaster that is available on testnets and enables paying fees in -ERC-20 compatible tokens. - -Example: - -```java -import io.zksync.protocol.ZkSync; -import org.web3j.protocol.http.HttpService; -import io.zksync.methods.response.ZksTestnetPaymasterAddress; - -public class Main { - public static void main(String ...args) { - ZksTestnetPaymasterAddress response = zksync.zksGetTestnetPaymaster().send(); -} -``` - -#### Inputs and outputs - -| Name | Description | -| ------- | ------------------------------- | -| returns | Prepared get paymaster request. | - -### `zksGetTransactionReceipt` - -Get transaction receipt. The same as `eth_getTransactionReceipt` but with additional fields belong to L2toL1Log - -Example: - -```java -import io.zksync.protocol.ZkSync; -import org.web3j.protocol.http.HttpService; -import io.zksync.methods.response.ZkTransactionReceipt; - -public class Main { - public static void main(String ...args) { - ZkTransactionReceipt zkReceipt = wallet.getZksync().zksGetTransactionReceipt("TRANSACTION_HASH").send().getTransactionReceipt().get(); -} -``` - -#### Inputs and outputs - -| Name | Description | -| --------------- | ----------------------------------------------------- | -| transactionHash | Hash of the sent message's executed transaction hash. | -| returns | Prepared get transaction receipt request. | - -### `zksGetTransactionDetails` - -Get transaction details. - -Example: - -```java -import io.zksync.protocol.ZkSync; -import org.web3j.protocol.http.HttpService; -import io.zksync.methods.response.ZkTransactionReceipt; - -public class Main { - public static void main(String ...args) { - ZksGetTransactionDetails response = zksync.zksGetTransactionDetails("TRANSACTION_HASH").send(); -} -``` - -#### Inputs and outputs - -| Name | Description | -| --------------- | ----------------------------------------------------- | -| transactionHash | Hash of the sent message's executed transaction hash. | -| returns | Prepared get transaction details request. | - -### `zksGetTransactionByHash` - -Get transaction details. - -Example: - -```java -import io.zksync.protocol.ZkSync; -import org.web3j.protocol.http.HttpService; -import io.zksync.methods.response.ZkTransactionReceipt; - -public class Main { - public static void main(String ...args) { - ZksGetTransactionDetails response = zksync.zksGetTransactionDetails("TRANSACTION_HASH").send(); -} -``` - -#### Inputs and outputs - -| Name | Description | -| --------------- | ----------------------------------------------------- | -| transactionHash | Hash of the sent message's executed transaction hash. | -| returns | Prepared get transaction details request. | - -### `zksEstimateFee` - -Estimate fee for the given transaction at the latest committed block time. - -Example: - -```java -import io.zksync.protocol.ZkSync; -import org.web3j.protocol.http.HttpService; -import io.zksync.methods.response.ZkTransactionReceipt; - -public class Main { - public static void main(String ...args) { - Transaction forEstimate; - - Fee fee = zksync.zksEstimateFee(forEstimate).send().getResult(); - } -``` - -#### Inputs and outputs - -| Name | Description | -| ----------- | -------------------------------- | -| transaction | Transaction data for estimation. | -| returns | Prepared estimate fee request. | - -### `zksL1ChainId` - -Get chain identifier of the L1 chain. - -Example: - -```java -import io.zksync.protocol.ZkSync; -import org.web3j.protocol.http.HttpService; - -public class Main { - public static void main(String ...args) { - ZksL1ChainId response = zksync.zksL1ChainId().send(); - } -``` - -#### Inputs and outputs - -| Name | Description | -| ------- | ----------------------------- | -| returns | Prepared L1 chain id request. | - -### `zksGetL2ToL1MsgProof` - -Get the proof for the message sent via the L1Messenger system contract. - -Example: - -```java -import io.zksync.protocol.ZkSync; -import org.web3j.protocol.http.HttpService; - -public class Main { - public static void main(String ...args) { - ZksL1ChainId response = zksync.zksL1ChainId().send(); - } -``` - -#### Inputs and outputs - -| Name | Description | -| ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| block | The number of the block where the message was emitted. | -| sender | The sender of the message (i.e. the account that called the L1Messenger system contract). | -| message | The keccak256 hash of the message that was sent. | -| l2LogPosition | The index in the block of the event that was emitted by the L1Messenger when submitting this message. If it is omitted, the proof for the first message with such content will be returned. | -| returns | Prepared L1 chain id request. | - -### `ethEstimateGas` - -Generates and returns an estimate of how much gas is required to allow the transaction to complete. The transaction will -not be added to the blockchain. - -Example: - -```java -import io.zksync.protocol.ZkSync; -import org.web3j.protocol.http.HttpService; -import io.zksync.methods.response.ZkTransactionReceipt; - -public class Main { - public static void main(String ...args) { - Transaction forEstimate; - - BigInteger gasUsed = zksync.ethEstimateGas(forEstimate).send().getAmountUsed(); - } -``` - -#### Inputs and outputs - -| Name | Description | -| ----------- | -------------------------------- | -| transaction | Transaction data for estimation. | -| returns | Prepared estimate gas request. | - -### `zksGetBlockByHash` - -Get block by hash. - -Example: - -```java -import io.zksync.protocol.ZkSync; -import org.web3j.protocol.http.HttpService; - -public class Main { - public static void main(String... args) { - ZksBlock response = zksync.zksGetBlockByHash("BLOCK_HASH", true).send(); - } -} -``` - -#### Inputs and outputs - -| Name | Description | -| ---------------------------- | ---------------------------------------------------------------------------------------------- | -| blockHash | Hash of a block. | -| returnFullTransactionObjects | If true it returns the full transaction objects. If false only the hashes of the transactions. | -| returns | Prepared get transaction receipt request. | diff --git a/content/20.build/sdks/js/accounts-l1-l2.md b/content/20.build/sdks/js/accounts-l1-l2.md deleted file mode 100644 index e561971e..00000000 --- a/content/20.build/sdks/js/accounts-l1-l2.md +++ /dev/null @@ -1,50 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: JS SDK L1/L2 Transactions | zkSync Docs ---- - -# Accounts: L1<->L2 Transactions - -This section explores the methods which allow the [account](./accounts.md) to send transactions among both L1 to L2 -networks. - -If you want some background on how L1<->L2 interaction works on zkSync, go through the -[introduction](../../developer-reference/l1-l2-interop.md). - -## Deposit - -`Wallet` and `L1Signer` objects provide a deposit workflow. For more information, please refer to the method -specification [`Deposit`](accounts.md#deposit). - -For a complete example of how to execute the deposit workflow, take a look at the following: -[Deposit ETH and ERC20 token](https://github.com/zksync-sdk/zksync2-examples/blob/main/js/src/01_deposit.ts). - -## Request execute - -`Wallet` and `L1Signer` objects provide an option to request execution of L2 transaction from L1. For more information, -please refer to the method specification [`requestExecute`](accounts.md#requestexecute). - -## Base cost - -`Wallet` and `L1Signer` objects provide an option to calculate base cost for L2 transaction. For more information, -please refer to the method specification [`getBaseCost`](accounts.md#getbasecost). - -## Claim failed deposit - -`Wallet` and `L1Signer` objects provide a claim fail deposit workflow. For more information, please refer to the method -specification [`claimFailedDeposit`](accounts.md#claimfaileddeposit). - -## Finalize withdraw - -`Wallet` and `L1Signer` objects provide a finalize withdraw workflow. For more information, please refer to the method -specification [`finalizeWithdrawal`](accounts.md#finalizewithdrawal). - -## Withdrawal - -`Wallet` and `Signer` objects provide a withdrawal workflow. For more information, please refer to the method -specification [`Deposit`](accounts.md#deposit). - -For a complete example of how to execute the deposit workflow, take a look at the following: -[Withdraw ETH and ERC20 token](https://github.com/zksync-sdk/zksync2-examples/blob/main/js/src/03_withdraw.ts). diff --git a/content/20.build/sdks/js/accounts.md b/content/20.build/sdks/js/accounts.md deleted file mode 100644 index a32c8c00..00000000 --- a/content/20.build/sdks/js/accounts.md +++ /dev/null @@ -1,2548 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: JS SDK Accounts | zkSync Docs ---- - -# Accounts - -## Overview - -`zksync-ethers` exports the following classes that can sign transactions on zkSync: - -- `Wallet` class is an extension of the `ethers.Wallet` with additional zkSync features. -- `EIP712Signer` class that is used to sign `EIP712`_-typed_ zkSync transactions. -- `Signer` and `L1Signer` classes, which should be used for browser integration. - -## `Wallet` - -### `constructor` - -#### Inputs - -| Parameter | Type | Description | -| ------------- | --------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------- | -| `privateKey` | `BytesLike` or [`ethers.utils.SigningKey`](https://docs.ethers.org/v6/api/crypto/#SigningKey) | The private key of the Ethereum account. | -| `providerL2?` | [`Provider`](./providers.md#provider) | A zkSync node provider. Needed for interaction with zkSync (optional). | -| `providerL1?` | [`ethers.providers.Provider`](https://docs.ethers.org/v5/api/providers/provider/#Provider) | An Ethereum node provider. Needed for interaction with L1 (optional). | - -```ts - constructor (privateKey: ethers.utils.BytesLike | ethers.utils.SigningKey, - providerL2?: Provider, - providerL1?: ethers.providers.Provider) -``` - -#### Example - -```ts -import { Wallet, Provider, utils } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const PRIVATE_KEY = ''; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const ethProvider = ethers.getDefaultProvider('sepolia'); -const wallet = new Wallet(PRIVATE_KEY, provider, ethProvider); -``` - -### `fromMnemonic` - -Creates a `Wallet` with the `provider` as L1 provider and a private key that is built from the `mnemonic` passphrase. - -#### Inputs - -| Parameter | Type | Description | -| ----------- | ------------------ | ----------------------------------------------------------------------- | -| `mnemonic` | `string` | The mnemonic of the private key. | -| `path?` | `string` | If path is not specified, the Ethereum default path is used (optional). | -| `wordlist?` | `ethers.Worldlist` | If wordlist is not specified, the English Wordlist is used (optional). | - -```ts -static fromMnemonic(mnemonic: string, path?: string, wordlist?: ethers.Wordlist) -``` - -#### Example - -```ts -import { Wallet } from 'zksync-ethers'; - -const MNEMONIC = 'stuff slice staff easily soup parent arm payment cotton hammer scatter struggle'; - -const wallet = Wallet.fromMnemonic(MNEMONIC); -``` - -### `fromEncryptedJson` - -Creates a `Wallet` from encrypted `json` file using provided `password`. - -#### Inputs - -| Parameter | Type | Description | -| ----------- | -------------------------- | -------------------------------------------------------------------------------------------------------------- | -| `json` | `string` | Encrypted json file. | -| `password` | `string` or `ethers.Bytes` | Password for encrypted json file. | -| `callback?` | `ProgressCallback` | If callback is provided, it is called periodically during decryption so that any UI can be updated (optional). | - -```ts -static async fromEncryptedJsonSync(json: string, password?: string | ethers.Bytes) -``` - -#### Example - -```ts -import { Wallet, Provider, utils } from 'zksync-ethers'; -import * as fs from 'fs'; - -const wallet = await Wallet.fromEncryptedJson(fs.readFileSync('wallet.json', 'utf8'), 'password'); -``` - -### `fromEncryptedJsonSync` - -Creates a `Wallet` from encrypted `json` file using provided `password`. - -#### Inputs - -| Parameter | Type | Description | -| ---------- | -------------------------- | --------------------------------- | -| `json` | `string` | Encrypted json file. | -| `password` | `string` or `ethers.Bytes` | Password for encrypted json file. | - -```ts -static fromEncryptedJsonSync(json: string, password?: string | ethers.Bytes) -``` - -#### Example - -```ts -import { Wallet } from 'zksync-ethers'; -import * as fs from 'fs'; - -const wallet = Wallet.fromEncryptedJsonSync(fs.readFileSync('tests/files/wallet.json', 'utf8'), 'password'); -``` - -### `connect` - -To interact with the zkSync network, the `Wallet` object should be connected to a `Provider` by either passing it to the -constructor or with the `connect` method. - -#### Inputs - -| Parameter | Type | Description | -| ---------- | ------------------------------------- | ----------------------- | -| `provider` | [`Provider`](./providers.md#provider) | A zkSync node provider. | - -```ts -Wallet.connect(provider:Provider): Wallet -``` - -#### Example - -```ts -import { Wallet, Provider, types } from 'zksync-ethers'; - -const PRIVATE_KEY = ''; -const unconnectedWallet = new Wallet(PRIVATE_KEY); - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const wallet = unconnectedWallet.connect(provider); -``` - -It is possible to chain `connect` and `connectToL1` methods: - -```ts -const wallet = unconnectedWallet.connect(zkSyncProvider).connectToL1(ethProvider); -``` - -### `connectToL1` - -To perform L1 operations, the `Wallet` object needs to be connected to an `ethers.Provider` object. - -#### Inputs - -| Parameter | Type | Description | -| ---------- | ------------------------------------------------------------------------------------------ | -------------------------- | -| `provider` | [`ethers.providers.Provider`](https://docs.ethers.org/v5/api/providers/provider/#Provider) | An Ethereum node provider. | - -```ts -Wallet.connectToL1(provider: ethers.Provider): Wallet -``` - -#### Example - -```ts -import { Wallet } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const PRIVATE_KEY = ''; -const unconnectedWallet = new Wallet(PRIVATE_KEY); - -const ethProvider = ethers.getDefaultProvider('sepolia'); -const wallet = unconnectedWallet.connectToL1(ethProvider); -``` - -It is possible to chain `connect` and `connectToL1` methods: - -```ts -const wallet = unconnectedWallet.connect(zkSyncProvider).connectToL1(ethProvider); -``` - -### `getMainContract` - -Returns `Contract` wrapper of the zkSync smart contract. - -```ts -async getMainContract(): Promise -``` - -#### Example - -```ts -import { Wallet, Provider, utils } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const PRIVATE_KEY = ''; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const ethProvider = ethers.getDefaultProvider('sepolia'); -const wallet = new Wallet(PRIVATE_KEY, provider, ethProvider); - -console.log(`Main contract: ${await wallet.getMainContract()}`); -``` - -### `getL1BridgeContracts` - -Returns L1 bridge contracts. - -```ts -async getL1BridgeContracts(): Promise<{ erc20: IL1Bridge; weth: IL1Bridge }> -``` - -:::note - -There is no separate Ether bridge contract, [Main contract](./accounts.md#getmaincontract) is used instead. - -::: - -#### Example - -```ts -import { Wallet, Provider, utils } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const PRIVATE_KEY = ''; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const ethProvider = ethers.getDefaultProvider('sepolia'); -const wallet = new Wallet(PRIVATE_KEY, provider, ethProvider); - -const l1BridgeContracts = await wallet.getL1BridgeContracts(); -``` - -### `getL2BridgeContracts` - -Returns L2 bridge contracts. - -```ts -async getL2BridgeContracts(): Promise<{ erc20: IL2Bridge; weth: IL2Bridge }> -``` - -#### Example - -```ts -import { Wallet, Provider, utils } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const PRIVATE_KEY = ''; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const ethProvider = ethers.getDefaultProvider('sepolia'); -const wallet = new Wallet(PRIVATE_KEY, provider, ethProvider); - -const l2BridgeContracts = await wallet.getL2BridgeContracts(); -``` - -### `getAddress` - -Returns the wallet address. - -```ts -async getAddress(): Promise
; -``` - -### Example - -```ts -import { Wallet, Provider, utils } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const PRIVATE_KEY = ''; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const ethProvider = ethers.getDefaultProvider('sepolia'); -const wallet = new Wallet(PRIVATE_KEY, provider, ethProvider); - -console.log(`Address: ${await wallet.getAddress()}`); -``` - -### `getBalance` - -Returns the amount of the token the `Wallet` has. - -#### Inputs - -| Parameter | Type | Description | -| ---------- | ---------- | ---------------------------------------------------------------------------------------------------------------- | -| `token?` | `Address` | The address of the token. ETH by default (optional). | -| `blockTag` | `BlockTag` | In which block a balance should be checked on. `committed`, i.e. the latest processed one is the default option. | - -```ts -async getBalance(token?: Address, blockTag: BlockTag = 'committed'): Promise -``` - -#### Example - -```ts -import { Wallet, Provider, utils } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const PRIVATE_KEY = ''; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const ethProvider = ethers.getDefaultProvider('sepolia'); -const wallet = new Wallet(PRIVATE_KEY, provider, ethProvider); - -const tokenL2 = '0x6a4Fb925583F7D4dF82de62d98107468aE846FD1'; - -console.log(`Token balance: ${await wallet.getBalance(tokenL2)}`); -``` - -### `getBalanceL1` - -Returns the amount of the token the `Wallet` has on Ethereum. - -#### Inputs - -| Parameter | Type | Description | -| ----------- | ---------- | --------------------------------------------------------------------------------------------------------------------------- | -| `token?` | `Address` | The address of the token. ETH by default (optional). | -| `blockTag?` | `BlockTag` | In which block a balance should be checked on. `committed`, i.e. the latest processed one is the default option (optional). | - -```ts -async getBalanceL1(token?: Address, blockTag?: BlockTag): Promise -``` - -#### Example - -```ts -import { Wallet, Provider, utils } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const PRIVATE_KEY = ''; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const ethProvider = ethers.getDefaultProvider('sepolia'); -const wallet = new Wallet(PRIVATE_KEY, provider, ethProvider); - -const tokenL1 = '0x56E69Fa1BB0d1402c89E3A4E3417882DeA6B14Be'; - -console.log(`Token balance: ${await wallet.getBalanceL1(tokenL1)}`); -``` - -### `getAllBalances` - -Returns all balances for confirmed tokens given by an account address. - -```ts -async getAllBalances(): Promise -``` - -#### Example - -```ts -import { Wallet, Provider, utils } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const PRIVATE_KEY = ''; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const ethProvider = ethers.getDefaultProvider('sepolia'); -const wallet = new Wallet(PRIVATE_KEY, provider, ethProvider); - -const allBalances = await wallet.getAllBalances(); -``` - -### `getNonce` - -Returns account's nonce number. - -#### Inputs - -| Parameter | Type | Description | -| ----------- | ---------- | --------------------------------------------------------------------------------------------------------------------------- | -| `blockTag?` | `BlockTag` | In which block a balance should be checked on. `committed`, i.e. the latest processed one is the default option (optional). | - -```ts -async getNonce(blockTag?: BlockTag): Promise -``` - -#### Example - -```ts -import { Wallet, Provider, utils } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const PRIVATE_KEY = ''; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const ethProvider = ethers.getDefaultProvider('sepolia'); -const wallet = new Wallet(PRIVATE_KEY, provider, ethProvider); - -console.log(`Nonce: ${await wallet.getNonce()}`); -``` - -### `getDeploymentNonce` - -Returns account's deployment nonce number. - -```ts -async getDeploymentNonce(): Promise -``` - -#### Example - -```ts -import { Wallet, Provider, utils } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const PRIVATE_KEY = ''; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const ethProvider = ethers.getDefaultProvider('sepolia'); -const wallet = new Wallet(PRIVATE_KEY, provider, ethProvider); - -console.log(`Nonce: ${await wallet.getDeploymentNonce()}`); -``` - -### `ethWallet` - -You can get an `ethers.Wallet` object with the same private key with `ethWallet()` method. - -```ts -ethWallet(): ethers.Wallet -``` - -#### Example - -```ts -import { Wallet, Provider, utils } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const PRIVATE_KEY = ''; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const ethProvider = ethers.getDefaultProvider('sepolia'); -const wallet = new Wallet(PRIVATE_KEY, provider, ethProvider); - -const ethWallet = wallet.ethWallet(); -``` - -### `l2TokenAddress` - -Returns the L2 token address equivalent for a L1 token address as they are not equal. ETH's address is set to zero -address. - -:::warning Only works for tokens bridged on default zkSync Era bridges. ::: - -#### Inputs - -| Parameter | Type | Description | -| --------- | --------- | ------------------------------- | -| `token` | `Address` | The address of the token on L1. | - -```ts -async l2TokenAddress(token: Address): Promise -``` - -#### Example - -```ts -import { Wallet, Provider, utils } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const PRIVATE_KEY = ''; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const ethProvider = ethers.getDefaultProvider('sepolia'); -const wallet = new Wallet(PRIVATE_KEY, provider, ethProvider); - -const tokenL1 = '0x5C221E77624690fff6dd741493D735a17716c26B'; - -console.log(`Token L2 address: ${await wallet.l2TokenAddress(tokenL1)}`); -``` - -### `populateTransaction` - -Designed for users who prefer a simplified approach by providing only the necessary data to create a valid transaction. -The only required fields are `transaction.to` and either `transaction.data` or `transaction.value` (or both, if the -method is payable). Any other fields that are not set will be prepared by this method. - -| Parameter | Type | Description | -| ------------- | ----------------------------------------------------- | -------------------- | -| `transaction` | [`TransactionRequest`](./types.md#transactionrequest) | Transaction request. | - -```ts -override async populateTransaction(transaction: TransactionRequest): Promise -``` - -#### Example - -```ts -import { Wallet, Provider, utils } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const PRIVATE_KEY = ''; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const ethProvider = ethers.getDefaultProvider('sepolia'); -const wallet = new Wallet(PRIVATE_KEY, provider, ethProvider); - -const recipient = Wallet.createRandom(); - -const tx = wallet.populateTransaction({ - to: recipient.address, - amount: ethers.utils.parseEther('0.01'), -}); -``` - -### `signTransaction` - -Signs the transaction and serializes it to be ready to be broadcast to the network. Throws an error when -`transaction.from` is mismatched from the private key. - -#### Inputs - -| Parameter | Type | Description | -| ------------- | ----------------------------------------------------- | -------------------- | -| `transaction` | [`TransactionRequest`](./types.md#transactionrequest) | Transaction request. | - -```ts -async signTransaction(transaction: TransactionRequest): Promise -``` - -#### Example - -```ts -import { Wallet, Provider, utils } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const PRIVATE_KEY = ''; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const ethProvider = ethers.getDefaultProvider('sepolia'); -const wallet = new Wallet(PRIVATE_KEY, provider); - -const recipient = Wallet.createRandom(); - -const tx = await wallet.signTransaction({ - type: utils.EIP712_TX_TYPE, - to: recipient.address, - value: ethers.utils.parseEther('1'), -}); -``` - -### `sendTransaction` - -Broadcast the transaction to the network. Throws an error when `tx.from` is mismatched from the private key. - -#### Inputs - -| Parameter | Type | Description | -| --------- | ------------------------------------- | -------------------- | -| `tx` | `ethers.providers.TransactionRequest` | Transaction request. | - -```ts -async sendTransaction(tx: ethers.providers.TransactionRequest): Promise -``` - -#### Example - -```ts -import { Wallet, Provider, utils } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const PRIVATE_KEY = ''; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const ethProvider = ethers.getDefaultProvider('sepolia'); -const wallet = new Wallet(PRIVATE_KEY, provider); - -const recipient = Wallet.createRandom(); - -const tx = await wallet.sendTransaction({ - type: utils.EIP712_TX_TYPE, - to: recipient.address, - value: ethers.utils.parseEther('1'), -}); -``` - -### `transfer` - -For convenience, the `Wallet` class has `transfer` method, which can transfer `ETH` or any `ERC20` token within the same -interface. - -#### Inputs - -| Parameter | Type | Description | -| ------------------------------ | ----------------------------------------------- | ----------------------------------------------------------------------------------------------------- | -| `transaction.to` | `Address` | The address of the recipient. | -| `transaction.amount` | `BigNumberish` | The amount of the token to transfer (optional). | -| `transaction.token?` | `Address` | The address of the token. `ETH` by default (optional). | -| `transaction.paymasterParams?` | [`PaymasterParams`](./types.md#paymasterparams) | Paymaster parameters (optional). | -| `transaction.overrides?` | `ethers.CallOverrides` | Transaction's overrides which may be used to pass l2 `gasLimit`, `gasPrice`, `value`, etc (optional). | - -```ts -async transfer(transaction: { - to: Address; - amount: BigNumberish; - token?: Address; - overrides?: ethers.CallOverrides; -}): Promise -``` - -#### Examples - -Transfer ETH. - -```ts -import { Wallet, Provider, utils } from 'zksync-ethers'; - -const PRIVATE_KEY = ''; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const wallet = new Wallet(PRIVATE_KEY, provider); - -const recipient = Wallet.createRandom(); - -const transferHandle = await wallet.transfer({ - to: recipient.address, - amount: ethers.parseEther('0.01'), -}); - -const tx = await transferHandle.wait(); - -console.log(`The sum of ${tx.value} ETH was transferred to ${tx.to}`); -``` - -Transfer ETH using paymaster to facilitate fee payment with an ERC20 token. - -```ts -import { Wallet, Provider, utils } from 'zksync-ethers'; - -const PRIVATE_KEY = ''; -const token = '0x927488F48ffbc32112F1fF721759649A89721F8F'; // Crown token which can be minted for free -const paymaster = '0x13D0D8550769f59aa241a41897D4859c87f7Dd46'; // Paymaster for Crown token - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const wallet = new Wallet(PRIVATE_KEY, provider); - -const recipient = Wallet.createRandom(); - -const transferHandle = await wallet.transfer({ - to: recipient.address, - amount: ethers.parseEther('0.01'), - paymasterParams: utils.getPaymasterParams(paymaster, { - type: 'ApprovalBased', - token: token, - minimalAllowance: 1, - innerInput: new Uint8Array(), - }), -}); - -const tx = await transferHandle.wait(); - -console.log(`The sum of ${tx.value} ETH was transferred to ${tx.to}`); -``` - -### `getAllowanceL1` - -Returns the amount of approved tokens for a specific L1 bridge. - -#### Inputs - -| Parameter | Type | Description | -| ---------------- | ---------- | ----------------------------------------------------------------------------------------------------------------------------------------- | -| `token` | `Address` | The Ethereum address of the token. | -| `bridgeAddress?` | `Address` | The address of the bridge contract to be used. Defaults to the default zkSync bridge, either `L1EthBridge` or `L1Erc20Bridge` (optional). | -| `blockTag?` | `BlockTag` | In which block an allowance should be checked on. `committed`, i.e. the latest processed one is the default option (optional). | - -```ts -async getAllowanceL1( - token: Address, - bridgeAddress?: Address, - blockTag?: ethers.BlockTag -): Promise -``` - -#### Example - -```ts -import { Wallet, Provider, utils } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const PRIVATE_KEY = ''; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const ethProvider = ethers.getDefaultProvider('sepolia'); -const wallet = new Wallet(PRIVATE_KEY, provider, ethProvider); - -const tokenL1 = '0x5C221E77624690fff6dd741493D735a17716c26B'; -console.log(`Token allowance: ${await wallet.getAllowanceL1(tokenL1)}`); -``` - -### `approveERC20` - -Bridging ERC20 tokens from Ethereum requires approving the tokens to the zkSync Ethereum smart contract. - -#### Inputs - -| Parameter | Type | Description | -| ------------ | ------------------- | ----------------------------------------------------------------------------------------------------- | -| `token` | `Address` | The Ethereum address of the token. | -| `amount` | `BigNumberish` | The amount of the token to be approved. | -| `overrides?` | `ethers.Overrides?` | Transaction's overrides which may be used to pass l2 `gasLimit`, `gasPrice`, `value`, etc (optional). | - -```ts -async approveERC20( - token: Address, - amount: BigNumberish, - overrides?: ethers.Overrides & { bridgeAddress?: Address } -): Promise -``` - -#### Example - -```ts -import { Wallet, Provider, utils } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const PRIVATE_KEY = ''; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const ethProvider = ethers.getDefaultProvider('sepolia'); -const wallet = new Wallet(PRIVATE_KEY, provider, ethProvider); - -const tokenL1 = '0x56E69Fa1BB0d1402c89E3A4E3417882DeA6B14Be'; -const txHandle = await wallet.approveERC20(tokenL1, '10000000'); - -await txHandle.wait(); -``` - -### `getBaseCost` - -Returns base cost for L2 transaction. - -#### Inputs - -| Name | Type | Description | -| --------------------------- | -------------- | ------------------------------------------------------------------------------------------------- | -| `params.gasLimit` | `BigNumberish` | The `gasLimit` for the L2 contract call. | -| `params.gasPerPubdataByte?` | `BigNumberish` | The L2 gas price for each published L1 calldata byte (optional). | -| `params.gasPrice?` | `BigNumberish` | The L1 gas price of the L1 transaction that will send the request for an execute call (optional). | - -```ts -async getBaseCost(params: { - gasLimit: BigNumberish; - gasPerPubdataByte?: BigNumberish; - gasPrice?: BigNumberish; -}): Promise -``` - -#### Example - -```ts -import { Wallet, Provider, utils } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const PRIVATE_KEY = ''; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const ethProvider = ethers.getDefaultProvider('sepolia'); -const wallet = new Wallet(PRIVATE_KEY, provider, ethProvider); - -console.log(`Base cost: ${await wallet.getBaseCost({ gasLimit: 100_000 })}`); -``` - -### `deposit` - -Transfers the specified token from the associated account on the L1 network to the target account on the L2 network. The -token can be either ETH or any ERC20 token. For ERC20 tokens, enough approved tokens must be associated with the -specified L1 bridge (default one or the one defined in `transaction.bridgeAddress`). In this case, -`transaction.approveERC20` can be enabled to perform token approval. If there are already enough approved tokens for the -L1 bridge, token approval will be skipped. To check the amount of approved tokens for a specific bridge, use the -[`allowanceL1`](#getallowancel1) method. - -#### Inputs - -| Parameter | Type | Description | -| -------------------------------- | ------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `transaction.token` | `Address` | The address of the token to deposit. `ETH` by default. | -| `transaction.amount` | `BigNumberish` | The amount of the token to withdraw. | -| `transaction.to?` | `Address` | The address that will receive the deposited tokens on L2 (optional). | -| `transaction.operatorTip?` | `BigNumberish` | (_currently is not used_) If the ETH value passed with the transaction is not explicitly stated in the overrides, this field will be equal to the tip the operator will receive on top of the base cost of the transaction (optional). | -| `transaction.bridgeAddress?` | `Address` | The address of the bridge contract to be used. Defaults to the default zkSync bridge (either `L1EthBridge` or `L1Erc20Bridge`) (optional). | -| `transaction.approveERC20?` | `boolean` | Whether or not should the token approval be performed under the hood. Set this flag to `true` if you bridge an ERC20 token and didn't call the `approveERC20` function beforehand (optional). | -| `transaction.l2GasLimit?` | `BigNumberish` | Maximum amount of L2 gas that transaction can consume during execution on L2 (optional). | -| `transaction.gasPerPubdataByte?` | `BigNumberish` | Whether or not should the token approval be performed under the hood. Set this flag to `true` if you bridge an ERC20 token and didn't call the `approveERC20` function beforehand (optional). | -| `transaction.refundRecipient?` | `Address` | The address on L2 that will receive the refund for the transaction. If the transaction fails, it will also be the address to receive l2Value (optional). | -| `transaction.overrides?` | `ethers.PayableOverrides` | Transaction's overrides which may be used to pass l2 `gasLimit`, `gasPrice`, `value`, etc (optional). | -| `transaction.approveOverrides?` | `ethers.Overrides` | Transaction's overrides which may be used to pass l2 `gasLimit`, `gasPrice`, `value`, etc (optional). | -| `transaction.customBridgeData?` | `BytesLike` | Additional data that can be sent to a bridge (optional). | - -```ts -async deposit(transaction: { - token: Address; - amount: BigNumberish; - to?: Address; - operatorTip?: BigNumberish; - bridgeAddress?: Address; - approveERC20?: boolean; - l2GasLimit?: BigNumberish; - gasPerPubdataByte?: BigNumberish; - refundRecipient?: Address; - overrides?: ethers.PayableOverrides; - approveOverrides?: ethers.Overrides; - customBridgeData?: BytesLike; -}): Promise -``` - -#### Example - -```ts -import { Wallet, Provider, utils } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const PRIVATE_KEY = ''; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const ethProvider = ethers.getDefaultProvider('sepolia'); -const wallet = new Wallet(PRIVATE_KEY, provider, ethProvider); - -const tokenL1 = '0x56E69Fa1BB0d1402c89E3A4E3417882DeA6B14Be'; -const tokenDepositHandle = await wallet.deposit({ - token: tokenL1, - amount: '10000000', - approveERC20: true, -}); -// Note that we wait not only for the L1 transaction to complete but also for it to be -// processed by zkSync. If we want to wait only for the transaction to be processed on L1, -// we can use `await tokenDepositHandle.waitL1Commit()` -await tokenDepositHandle.wait(); - -const ethDepositHandle = await wallet.deposit({ - token: utils.ETH_ADDRESS, - amount: '10000000', -}); -// Note that we wait not only for the L1 transaction to complete but also for it to be -// processed by zkSync. If we want to wait only for the transaction to be processed on L1, -// we can use `await ethDepositHandle.waitL1Commit()` -await ethDepositHandle.wait(); -``` - -### `getDepositTx` - -Returns populated deposit transaction. - -#### Inputs - -| Parameter | Type | Description | -| -------------------------------- | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `transaction.token` | `Address` | The address of the token to deposit. `ETH` by default. | -| `transaction.amount` | `BigNumberish` | The amount of the token to withdraw. | -| `transaction.to?` | `Address` | The address that will receive the deposited tokens on L2 (optional). | -| `transaction.operatorTip?` | `BigNumberish` | (_currently is not used_) If the ETH value passed with the transaction is not explicitly stated in the overrides,
this field will be equal to the tip the operator will receive on top of the base cost of the transaction (optional). | -| `transaction.bridgeAddress?` | `Address` | The address of the bridge contract to be used. Defaults to the default zkSync bridge (either `L1EthBridge` or `L1Erc20Bridge`) (optional). | -| `transaction.l2GasLimit?` | `BigNumberish` | Maximum amount of L2 gas that transaction can consume during execution on L2 (optional). | -| `transaction.gasPerPubdataByte?` | `BigNumberish` | Whether or not should the token approval be performed under the hood. Set this flag to `true` if you bridge an ERC20 token and didn't call the `approveERC20` function beforehand (optional). | -| `transaction.customBridgeData?` | `BytesLike` | Additional data that can be sent to a bridge (optional). | -| `transaction.refundRecipient?` | `Address` | The address on L2 that will receive the refund for the transaction. If the transaction fails, it will also be the address to receive l2Value (optional). | -| `transaction.overrides?` | `ethers.PayableOverrides` | Transaction's overrides which may be used to pass l2 `gasLimit`, `gasPrice`, `value`, etc (optional). | - -```ts -async getDepositTx(transaction: { - token: Address; - amount: BigNumberish; - to?: Address; - operatorTip?: BigNumberish; - bridgeAddress?: Address; - l2GasLimit?: BigNumberish; - gasPerPubdataByte?: BigNumberish; - customBridgeData?: BytesLike; - refundRecipient?: Address; - overrides?: ethers.PayableOverrides; -}): Promise -``` - -#### Example - -```ts -import { Wallet, Provider, utils } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const PRIVATE_KEY = ''; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const ethProvider = ethers.getDefaultProvider('sepolia'); -const wallet = new Wallet(PRIVATE_KEY, provider, ethProvider); - -const tokenL1 = '0x56E69Fa1BB0d1402c89E3A4E3417882DeA6B14Be'; -const tx = await wallet.getDepositTx({ - token: tokenL1, - amount: '10000000', -}); -``` - -### `estimateGasDeposit` - -Estimates the amount of gas required for a deposit transaction on L1 network. Gas of approving ERC20 token is not -included in estimation. - -#### Inputs - -| Parameter | Type | Description | -| -------------------------------- | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `transaction.token` | `Address` | The address of the token to deposit. `ETH` by default. | -| `transaction.amount` | `BigNumberish` | The amount of the token to withdraw. | -| `transaction.to?` | `Address` | The address that will receive the deposited tokens on L2 (optional). | -| `transaction.operatorTip?` | `BigNumberish` | (_currently is not used_) If the ETH value passed with the transaction is not explicitly stated in the overrides,
this field will be equal to the tip the operator will receive on top of the base cost of the transaction (optional). | -| `transaction.bridgeAddress?` | `Address` | The address of the bridge contract to be used. Defaults to the default zkSync bridge (either `L1EthBridge` or `L1Erc20Bridge`) (optional). | -| `transaction.l2GasLimit?` | `BigNumberish` | Maximum amount of L2 gas that transaction can consume during execution on L2 (optional). | -| `transaction.gasPerPubdataByte?` | `BigNumberish` | Whether or not should the token approval be performed under the hood. Set this flag to `true` if you bridge an ERC20 token and didn't call the `approveERC20` function beforehand (optional). | -| `transaction.customBridgeData?` | `BytesLike` | Additional data that can be sent to a bridge (optional). | -| `transaction.refundRecipient?` | `Address` | The address on L2 that will receive the refund for the transaction. If the transaction fails, it will also be the address to receive l2Value (optional). | -| `transaction.overrides?` | `ethers.PayableOverrides` | Transaction's overrides which may be used to pass l2 `gasLimit`, `gasPrice`, `value`, etc (optional). | - -```ts -async estimateGasDeposit(transaction: - token: Address; - amount: BigNumberish; - to?: Address; - operatorTip?: BigNumberish; - bridgeAddress?: Address; - customBridgeData?: BytesLike; - l2GasLimit?: BigNumberish; - gasPerPubdataByte?: BigNumberish; - refundRecipient?: Address; - overrides?: ethers.PayableOverrides; - }): Promise -``` - -#### Example - -```ts -import { Wallet, Provider, utils } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const PRIVATE_KEY = ''; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const ethProvider = ethers.getDefaultProvider('sepolia'); -const wallet = new Wallet(PRIVATE_KEY, provider, ethProvider); - -const tokenL1 = '0x5C221E77624690fff6dd741493D735a17716c26B'; -const gas = await wallet.estimateGasDeposit({ - token: tokenL1, - amount: '10000000', -}); -console.log(`Gas: ${gas}`); -``` - -### `getFullRequiredDepositFee` - -Retrieves the full needed ETH fee for the deposit. Returns the L1 fee and the L2 fee -[`FullDepositFee`](./types.md#fulldepositfee). - -#### Inputs - -| Parameter | Type | Description | -| -------------------------------- | ------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `transaction.token` | `Address` | The address of the token to deposit. `ETH` by default. | -| `transaction.to?` | `Address` | The address that will receive the deposited tokens on L2 (optional). | -| `transaction.bridgeAddress?` | `Address` | The address of the bridge contract to be used. Defaults to the default zkSync bridge (either `L1EthBridge` or `L1Erc20Bridge`) (optional). | -| `transaction.customBridgeData?` | `BytesLike` | Additional data that can be sent to a bridge (optional). | -| `transaction.gasPerPubdataByte?` | `BigNumberish` | Whether or not should the token approval be performed under the hood. Set this flag to `true` if you bridge an ERC20 token and didn't call the `approveERC20` function beforehand (optional). | -| `transaction.overrides?` | `ethers.PayableOverrides` | Transaction's overrides which may be used to pass l2 `gasLimit`, `gasPrice`, `value`, etc (optional). | - -```ts -async getFullRequiredDepositFee(transaction: { - token: Address; - to?: Address; - bridgeAddress?: Address; - customBridgeData?: BytesLike; - gasPerPubdataByte?: BigNumberish; - overrides?: ethers.PayableOverrides; -}): Promise -``` - -#### Example - -```ts -import { Wallet, Provider, utils } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const PRIVATE_KEY = ''; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const ethProvider = ethers.getDefaultProvider('sepolia'); -const wallet = new Wallet(PRIVATE_KEY, provider, ethProvider); - -const tokenL1 = '0x56E69Fa1BB0d1402c89E3A4E3417882DeA6B14Be'; -const fee = await wallet.getFullRequiredDepositFee({ - token: tokenL1, - to: await wallet.getAddress(), -}); -console.log(`Fee: ${fee}`); -``` - -### `claimFailedDeposit` - -The `claimFailedDeposit` method withdraws funds from the initiated deposit, which failed when finalizing on L2. -If the deposit L2 transaction has failed, it sends an L1 transaction calling `claimFailedDeposit` method of the L1 -bridge, which results in returning L1 tokens back to the depositor, otherwise throws the error. - -#### Inputs - -| Parameter | Type | Description | -| ----------- | --------- | ---------------------------------------------- | -| depositHash | `bytes32` | The L2 transaction hash of the failed deposit. | - -```ts -async claimFailedDeposit(depositHash: BytesLike): Promise -``` - -#### Example - -```ts -import { Wallet, Provider, utils } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const PRIVATE_KEY = ''; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const ethProvider = ethers.getDefaultProvider('sepolia'); -const wallet = new Wallet(PRIVATE_KEY, provider, ethProvider); - -const FAILED_DEPOSIT_HASH = ''; -const claimFailedDepositHandle = await wallet.claimFailedDeposit(FAILED_DEPOSIT_HASH); -``` - -### `withdraw` - -Initiates the withdrawal process which withdraws ETH or any ERC20 token from the associated account on L2 network to the -target account on L1 network. - -#### Inputs - -| Parameter | Type | Description | -| ------------------------------ | ----------------------------------------------- | ----------------------------------------------------------------------------------------------------- | -| `transaction.token` | `Address` | The address of the token. `ETH` by default. | -| `transaction.amount` | `BigNumberish` | The amount of the token to withdraw. | -| `transaction.to?` | `Address` | The address of the recipient on L1 (optional). | -| `transaction.bridgeAddress?` | `Address` | The address of the bridge contract to be used (optional). | -| `transaction.paymasterParams?` | [`PaymasterParams`](./types.md#paymasterparams) | Paymaster parameters (optional). | -| `transaction.overrides?` | `ethers.CallOverrides` | Transaction's overrides which may be used to pass l2 `gasLimit`, `gasPrice`, `value`, etc (optional). | - -```ts -async withdraw(transaction: { - token: Address; - amount: BigNumberish; - to?: Address; - bridgeAddress?: Address; - paymasterParams?: PaymasterParams; - overrides?: ethers.CallOverrides; -}): Promise -``` - -#### Examples - -Withdraw ETH. - -```ts -import { Wallet, Provider, utils } from 'zksync-ethers'; - -const PRIVATE_KEY = ''; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const wallet = new Wallet(PRIVATE_KEY, provider); - -const tokenL2 = '0x6a4Fb925583F7D4dF82de62d98107468aE846FD1'; -const tokenWithdrawHandle = await wallet.withdraw({ - token: tokenL2, - amount: 10_000_000, -}); -``` - -Withdraw ETH using paymaster to facilitate fee payment with an ERC20 token. - -```ts -import { Wallet, Provider, utils } from 'zksync-ethers'; - -const PRIVATE_KEY = ''; -const token = '0x927488F48ffbc32112F1fF721759649A89721F8F'; // Crown token which can be minted for free -const paymaster = '0x13D0D8550769f59aa241a41897D4859c87f7Dd46'; // Paymaster for Crown token - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const wallet = new Wallet(PRIVATE_KEY, provider); - -const tokenL2 = '0x6a4Fb925583F7D4dF82de62d98107468aE846FD1'; -const tokenWithdrawHandle = await wallet.withdraw({ - token: tokenL2, - amount: 10_000_000, - paymasterParams: utils.getPaymasterParams(paymaster, { - type: 'ApprovalBased', - token: token, - minimalAllowance: 1, - innerInput: new Uint8Array(), - }), -}); -``` - -### `finalizeWithdrawal` - -Proves the inclusion of the L2 -> L1 withdrawal message. - -#### Inputs - -| Name | Type | Description | -| ---------------- | ----------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | -| `withdrawalHash` | `BytesLike` | Hash of the L2 transaction where the withdrawal was initiated. | -| `index?` | `number` | In case there were multiple withdrawals in one transaction, you may pass an index of the withdrawal you want to finalize. Defaults to 0 (optional). | - -```ts -async finalizeWithdrawal(withdrawalHash: BytesLike, index: number = 0): Promise -``` - -#### Example - -```ts -import { Wallet, Provider, utils } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const PRIVATE_KEY = ''; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const ethProvider = ethers.getDefaultProvider('sepolia'); -const wallet = new Wallet(PRIVATE_KEY, provider, ethProvider); - -const WITHDRAWAL_HASH = ''; -const finalizeWithdrawHandle = await wallet.finalizeWithdrawal(WITHDRAWAL_HASH); -``` - -### `isWithdrawalFinalized` - -Returns weather the withdrawal transaction is finalized on the L1 network. - -#### Inputs - -| Name | Type | Description | -| ---------------- | ----------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | -| `withdrawalHash` | `BytesLike` | Hash of the L2 transaction where the withdrawal was initiated. | -| `index?` | `number` | In case there were multiple withdrawals in one transaction, you may pass an index of the withdrawal you want to finalize. Defaults to 0 (optional). | - -```ts -async isWithdrawalFinalized(withdrawalHash: BytesLike, index: number = 0): Promise -``` - -#### Example - -```ts -import { Wallet, Provider, utils } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const PRIVATE_KEY = ''; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const ethProvider = ethers.getDefaultProvider('sepolia'); -const wallet = new Wallet(PRIVATE_KEY, provider, ethProvider); - -const WITHDRAWAL_HASH = ''; -const isFinalized = await wallet.isWithdrawalFinalized(WITHDRAWAL_HASH); -``` - -### `finalizeWithdrawalParams` - -Returns the [parameters](./types.md#finalizewithdrawalparams) required for finalizing a withdrawal from the withdrawal -transaction's log on the L1 network. - -#### Inputs - -| Name | Type | Description | -| ---------------- | ----------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | -| `withdrawalHash` | `BytesLike` | Hash of the L2 transaction where the withdrawal was initiated. | -| `index?` | `number` | In case there were multiple withdrawals in one transaction, you may pass an index of the withdrawal you want to finalize. Defaults to 0 (optional). | - -```ts -async finalizeWithdrawalParams(withdrawalHash: BytesLike, index: number = 0): Promise -``` - -#### Example - -```ts -import { Wallet, Provider, utils } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const PRIVATE_KEY = ''; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const ethProvider = ethers.getDefaultProvider('sepolia'); -const wallet = new Wallet(PRIVATE_KEY, provider, ethProvider); - -const WITHDRAWAL_HASH = ''; -const params = await wallet.finalizeWithdrawalParams(WITHDRAWAL_HASH); -``` - -### `requestExecute` - -Request execution of L2 transaction from L1. - -#### Inputs - -| Name | Type | Description | -| -------------------------------- | ------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `transaction.contractAddress` | `Address` | The L2 contract to be called (optional). | -| `transaction.calldata` | `BytesLike` | The input of the L2 transaction (optional). | -| `transaction.l2GasLimit` | `BigNumberish` | Maximum amount of L2 gas that transaction can consume during execution on L2 (optional). | -| `transaction.l2Value?` | `BigNumberish` | `msg.value` of L2 transaction (optional). | -| `transaction.factoryDeps?` | `ethers.BytesLike[]` | An array of L2 bytecodes that will be marked as known on L2 (optional). | -| `transaction.operatorTip?` | `BigNumberish` | (_currently is not used_) If the ETH value passed with the transaction is not explicitly stated in the overrides, this field will be equal to the tip the operator will receive on top of the base cost of the transaction (optional). | -| `transaction.gasPerPubdataByte?` | `BigNumberish` | The L2 gas price for each published L1 calldata byte (optional). | -| `transaction.refundRecipient?` | `Address` | The address on L2 that will receive the refund for the transaction. If the transaction fails, it will also be the address to receive `l2Value` (optional). | -| `transaction.overrides?` | `ethers.PayableOverrides` | Transaction's overrides which may be used to pass l2 `gasLimit`, `gasPrice`, `value`, etc (optional). | - -```ts -async requestExecute(transaction: { - contractAddress: Address; - calldata: string; - l2GasLimit: BigNumberish; - l2Value?: BigNumberish; - factoryDeps?: ethers.BytesLike[]; - operatorTip?: BigNumberish; - gasPerPubdataByte?: BigNumberish; - refundRecipient?: Address; - overrides?: ethers.PayableOverrides; -}): Promise -``` - -#### Example - -```ts -import { Wallet, Provider, utils } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const PRIVATE_KEY = ''; -const CONTRACT_ADDRESS = ''; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const ethProvider = ethers.getDefaultProvider('sepolia'); -const wallet = new Wallet(PRIVATE_KEY, provider, ethProvider); - -const gasPrice = await wallet.providerL1.getGasPrice(); - -// The calldata can be encoded the same way as for Ethereum. -// Here is an example of how to get the calldata from an ABI: -const abi = [ - { - inputs: [], - name: 'increment', - outputs: [], - stateMutability: 'nonpayable', - type: 'function', - }, -]; -const contractInterface = new ethers.utils.Interface(abi); -const calldata = contractInterface.encodeFunctionData('increment', []); -const l2GasLimit = BigNumber.from(1000); - -const txCostPrice = await wallet.getBaseCost({ - gasPrice, - calldataLength: ethers.utils.arrayify(calldata).length, - l2GasLimit, -}); - -console.log(`Executing the transaction will cost ${ethers.utils.formatEther(txCostPrice)} ETH`); - -const executeTx = await wallet.requestExecute({ - contractAddress: CONTRACT_ADDRESS, - calldata, - l2Value: 1, - l2GasLimit, - overrides: { - gasPrice, - value: txCostPrice, - }, -}); - -await executeTx.wait(); -``` - -### `getRequestExecuteTx` - -Returns populated deposit transaction. - -#### Inputs - -| Name | Type | Description | -| -------------------------------- | ------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `transaction.contractAddress` | `Address` | The L2 contract to be called (optional). | -| `transaction.calldata` | `BytesLike` | The input of the L2 transaction (optional). | -| `transaction.l2GasLimit` | `BigNumberish` | Maximum amount of L2 gas that transaction can consume during execution on L2 (optional). | -| `transaction.l2Value?` | `BigNumberish` | `msg.value` of L2 transaction (optional). | -| `transaction.factoryDeps?` | `ethers.BytesLike[]` | An array of L2 bytecodes that will be marked as known on L2 (optional). | -| `transaction.operatorTip?` | `BigNumberish` | (_currently is not used_) If the ETH value passed with the transaction is not explicitly stated in the overrides, this field will be equal to the tip the operator will receive on top of the base cost of the transaction (optional). | -| `transaction.gasPerPubdataByte?` | `BigNumberish` | The L2 gas price for each published L1 calldata byte (optional). | -| `transaction.refundRecipient?` | `Address` | The address on L2 that will receive the refund for the transaction. If the transaction fails, it will also be the address to receive `l2Value` (optional). | -| `transaction.overrides?` | `ethers.PayableOverrides` | Transaction's overrides which may be used to pass l2 `gasLimit`, `gasPrice`, `value`, etc (optional). | - -```ts -async getRequestExecuteTx(transaction: { - contractAddress: Address; - calldata: string; - l2GasLimit?: BigNumberish; - l2Value?: BigNumberish; - factoryDeps?: ethers.BytesLike[]; - operatorTip?: BigNumberish; - gasPerPubdataByte?: BigNumberish; - refundRecipient?: Address; - overrides?: ethers.PayableOverrides; -}): Promise -``` - -#### Example - -```ts -import { Wallet, Provider, utils } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const PRIVATE_KEY = ''; -const CONTRACT_ADDRESS = ''; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const ethProvider = ethers.getDefaultProvider('sepolia'); -const wallet = new Wallet(PRIVATE_KEY, provider, ethProvider); - -const gasPrice = await wallet.providerL1.getGasPrice(); - -// The calldata can be encoded the same way as for Ethereum. -// Here is an example of how to get the calldata from an ABI: -const abi = [ - { - inputs: [], - name: 'increment', - outputs: [], - stateMutability: 'nonpayable', - type: 'function', - }, -]; -const contractInterface = new ethers.utils.Interface(abi); -const calldata = contractInterface.encodeFunctionData('increment', []); -const l2GasLimit = BigNumber.from(1000); - -const txCostPrice = await wallet.getBaseCost({ - gasPrice, - calldataLength: ethers.utils.arrayify(calldata).length, - l2GasLimit, -}); - -console.log(`Executing the transaction will cost ${ethers.utils.formatEther(txCostPrice)} ETH`); - -const executeTx = await wallet.getRequestExecuteTx({ - contractAddress: CONTRACT_ADDRESS, - calldata, - l2Value: 1, - l2GasLimit, - overrides: { - gasPrice, - value: txCostPrice, - }, -}); -``` - -### `estimateGasRequestExecute` - -Estimates the amount of gas required for a request execute transaction. - -#### Inputs - -| Name | Type | Description | -| -------------------------------- | ------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `transaction.contractAddress` | `Address` | The L2 contract to be called (optional). | -| `transaction.calldata` | `BytesLike` | The input of the L2 transaction (optional). | -| `transaction.l2GasLimit` | `BigNumberish` | Maximum amount of L2 gas that transaction can consume during execution on L2 (optional). | -| `transaction.l2Value?` | `BigNumberish` | `msg.value` of L2 transaction (optional). | -| `transaction.factoryDeps?` | `ethers.BytesLike[]` | An array of L2 bytecodes that will be marked as known on L2 (optional). | -| `transaction.operatorTip?` | `BigNumberish` | (_currently is not used_) If the ETH value passed with the transaction is not explicitly stated in the overrides, this field will be equal to the tip the operator will receive on top of the base cost of the transaction (optional). | -| `transaction.gasPerPubdataByte?` | `BigNumberish` | The L2 gas price for each published L1 calldata byte (optional). | -| `transaction.refundRecipient?` | `Address` | The address on L2 that will receive the refund for the transaction. If the transaction fails, it will also be the address to receive `l2Value` (optional). | -| `transaction.overrides?` | `ethers.PayableOverrides` | Transaction's overrides which may be used to pass l2 `gasLimit`, `gasPrice`, `value`, etc (optional). | - -```ts -async estimateGasRequestExecute(transaction: { - contractAddress: Address; - calldata: string; - l2GasLimit?: BigNumberish; - l2Value?: BigNumberish; - factoryDeps?: ethers.BytesLike[]; - operatorTip?: BigNumberish; - gasPerPubdataByte?: BigNumberish; - refundRecipient?: Address; - overrides?: ethers.PayableOverrides; -}): Promise -``` - -#### Example - -```ts -import { Wallet, Provider, utils } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const PRIVATE_KEY = ''; -const CONTRACT_ADDRESS = ''; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const ethProvider = ethers.getDefaultProvider('sepolia'); -const wallet = new Wallet(PRIVATE_KEY, provider, ethProvider); - -const gasPrice = await wallet.providerL1.getGasPrice(); - -// The calldata can be encoded the same way as for Ethereum. -// Here is an example of how to get the calldata from an ABI: -const abi = [ - { - inputs: [], - name: 'increment', - outputs: [], - stateMutability: 'nonpayable', - type: 'function', - }, -]; -const contractInterface = new ethers.utils.Interface(abi); -const calldata = contractInterface.encodeFunctionData('increment', []); -const l2GasLimit = BigNumber.from(1000); - -const txCostPrice = await wallet.getBaseCost({ - gasPrice, - calldataLength: ethers.utils.arrayify(calldata).length, - l2GasLimit, -}); - -console.log(`Executing the transaction will cost ${ethers.utils.formatEther(txCostPrice)} ETH`); - -const executeTx = await wallet.getRequestExecuteTx({ - contractAddress: CONTRACT_ADDRESS, - calldata, - l2Value: 1, - l2GasLimit, - overrides: { - gasPrice, - value: txCostPrice, - }, -}); -``` - -## `EIP712Signer` - -Provides support for an EIP712 transaction. The methods of this class are mostly used internally. - -### `getSignInput` - -Generates the EIP-712 typed data from provided transaction. Optional fields are populated by zero values. - -#### Inputs - -| Parameter | Type | Description | -| ------------- | ----------------------------------------------------- | -------------------- | -| `transaction` | [`TransactionRequest`](./types.md#transactionrequest) | Transaction request. | - -```ts -static getSignInput(transaction: TransactionRequest) -``` - -#### Example - -```ts -const tx = EIP712Signer.getSignInput({ - type: utils.EIP712_TX_TYPE, - to: '0xa61464658AfeAf65CccaaFD3a512b69A83B77618', - value: BigNumber.from(7_000_000), - from: '0x36615Cf349d7F6344891B1e7CA7C72883F5dc049', - nonce: 0, - chainId: BigNumber.from(270), - gasPrice: BigNumber.from(250_000_000), - gasLimit: BigNumber.from(21_000), - customData: {}, -}); -``` - -### `sign` - -Signs an Ethereum transaction using EIP-712. - -#### Inputs - -| Parameter | Type | Description | -| ------------- | ----------------------------------------------------- | -------------------- | -| `transaction` | [`TransactionRequest`](./types.md#transactionrequest) | Transaction request. | - -```ts -async sign(transaction: TransactionRequest): Promise -``` - -### `getSignedDigest` - -Generates the signed digest of an Ethereum transaction using EIP-712. - -#### Inputs - -| Parameter | Type | Description | -| ------------- | ----------------------------------------------------- | -------------------- | -| `transaction` | [`TransactionRequest`](./types.md#transactionrequest) | Transaction request. | - -```ts -static getSignedDigest(transaction: TransactionRequest): ethers.BytesLike -``` - -### `getDomain` - -Returns the EIP712 domain. - -```ts -async getDomain(): Promise -``` - -## `Signer` - -This class is to be used in a browser environment. The easiest way to construct it is to use the `getSigner` method of -the `Web3Provider`. This structure extends `ethers.providers.JsonRpcSigner` and so supports all the methods available -for it. - -```typescript -import { Web3Provider } from 'zksync-ethers'; - -const provider = new Web3Provider(window.ethereum); -const signer = provider.getSigner(); -``` - -### `getBalance` - -Returns the amount of the token the `Signer` has. - -#### Inputs - -| Parameter | Type | Description | -| ---------- | ---------- | ---------------------------------------------------------------------------------------------------------------- | -| `token?` | `Address` | The address of the token. ETH by default. | -| `blockTag` | `BlockTag` | In which block a balance should be checked on. `committed`, i.e. the latest processed one is the default option. | - -```ts -async getBalance(token?: Address, blockTag: BlockTag = 'committed'): Promise -``` - -#### Example - -```ts -import { Web3Provider } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const provider = new Web3Provider(window.ethereum); -const signer = provider.getSigner(); - -const tokenL2 = '0x6a4Fb925583F7D4dF82de62d98107468aE846FD1'; -// Getting token balance -console.log(await signer.getBalance(tokenL2)); - -// Getting ETH balance -console.log(await signer.getBalance()); -``` - -### `getNonce` - -Returns account's nonce number. - -#### Inputs - -| Parameter | Type | Description | -| ----------- | ---------- | ---------------------------------------------------------------------------------------------------------------- | -| `blockTag?` | `BlockTag` | In which block a balance should be checked on. `committed`, i.e. the latest processed one is the default option. | - -```ts -async getNonce(blockTag?: BlockTag): Promise -``` - -#### Example - -```ts -import { Web3Provider } from 'zksync-ethers'; - -const provider = new Web3Provider(window.ethereum); -const signer = provider.getSigner(); - -console.log(await signer.getNonce()); -``` - -### `transfer` - -Please note that for now, unlike Ethereum, zkSync does not support native transfers, i.e. the `value` field of all -transactions is equal to `0`. All the token transfers are done through ERC20 `transfer` function calls. - -But for convenience, the `Wallet` class has `transfer` method, which can transfer any `ERC20` tokens. - -#### Inputs - -| Parameter | Type | Description | -| ------------------------------ | ----------------------------------------------- | ----------------------------------------------------------------------------------------------------- | -| `transaction.to` | `Address` | The address of the recipient. | -| `transaction.amount` | `BigNumberish` | The amount of the token to transfer. | -| `transaction.token?` | `Address` | The address of the token. `ETH` by default. | -| `transaction.paymasterParams?` | [`PaymasterParams`](./types.md#paymasterparams) | Paymaster parameters (optional). | -| `transaction.overrides?` | `ethers.CallOverrides` | Transaction's overrides which may be used to pass l2 `gasLimit`, `gasPrice`, `value`, etc (optional). | - -```ts -async transfer(transaction: { - to: Address; - amount: BigNumberish; - token?: Address; - paymasterParams?: PaymasterParams; - overrides?: ethers.CallOverrides; -}): Promise -``` - -#### Examples - -Transfer ETH. - -```ts -import { Wallet, Web3Provider } from 'zksync-ethers'; - -const provider = new Web3Provider(window.ethereum); -const signer = provider.getSigner(); - -const recipient = Wallet.createRandom(); - -const transferHandle = signer.transfer({ - to: recipient.address, - amount: ethers.utils.parseEther('0.01'), -}); -``` - -Transfer ETH using paymaster to facilitate fee payment with an ERC20 token. - -```ts -import { Wallet, Web3Provider } from 'zksync-ethers'; - -const token = '0x927488F48ffbc32112F1fF721759649A89721F8F'; // Crown token which can be minted for free -const paymaster = '0x13D0D8550769f59aa241a41897D4859c87f7Dd46'; // Paymaster for Crown token - -const provider = new Web3Provider(window.ethereum); -const signer = provider.getSigner(); - -const recipient = Wallet.createRandom(); - -const transferHandle = signer.transfer({ - to: recipient.address, - amount: ethers.utils.parseEther('0.01'), - paymasterParams: utils.getPaymasterParams(paymaster, { - type: 'ApprovalBased', - token: token, - minimalAllowance: 1, - innerInput: new Uint8Array(), - }), -}); -``` - -### `withdraw` - -Initiates the withdrawal process which withdraws ETH or any ERC20 token from the associated account on L2 network to the -target account on L1 network. - -#### Inputs - -| Parameter | Type | Description | -| ------------------------------ | ----------------------------------------------- | ----------------------------------------------------------------------------------------------------- | -| `transaction.token` | `Address` | The address of the token. `ETH` by default. | -| `transaction.amount` | `BigNumberish` | The amount of the token to withdraw. | -| `transaction.to?` | `Address` | The address of the recipient on L1 (optional). | -| `transaction.bridgeAddress?` | `Address` | The address of the bridge contract to be used (optional). | -| `transaction.paymasterParams?` | [`PaymasterParams`](./types.md#paymasterparams) | Paymaster parameters (optional). | -| `transaction.overrides?` | `ethers.CallOverrides` | Transaction's overrides which may be used to pass l2 `gasLimit`, `gasPrice`, `value`, etc (optional). | - -```ts -async withdraw(transaction: { - token: Address; - amount: BigNumberish; - to?: Address; - bridgeAddress?: Address; - paymasterParams?: PaymasterParams; - overrides?: ethers.CallOverrides; -}): Promise -``` - -#### Examples - -Withdraw ETH. - -```ts -import { Web3Provider } from 'zksync-ethers'; - -const provider = new Web3Provider(window.ethereum); -const signer = provider.getSigner(); - -const tokenL2 = '0x6a4Fb925583F7D4dF82de62d98107468aE846FD1'; -const tokenWithdrawHandle = await signer.withdraw({ - token: tokenL2, - amount: 10_000_000, -}); -``` - -Withdraw ETH using paymaster to facilitate fee payment with an ERC20 token. - -```ts -import { Web3Provider } from 'zksync-ethers'; - -const token = '0x927488F48ffbc32112F1fF721759649A89721F8F'; // Crown token which can be minted for free -const paymaster = '0x13D0D8550769f59aa241a41897D4859c87f7Dd46'; // Paymaster for Crown token - -const provider = new Web3Provider(window.ethereum); -const signer = provider.getSigner(); - -const tokenL2 = '0x6a4Fb925583F7D4dF82de62d98107468aE846FD1'; -const tokenWithdrawHandle = await signer.withdraw({ - token: tokenL2, - amount: 10_000_000, - paymasterParams: utils.getPaymasterParams(paymaster, { - type: 'ApprovalBased', - token: token, - minimalAllowance: 1, - innerInput: new Uint8Array(), - }), -}); -``` - -## `L1Signer` - -This class is to be used in a browser environment to do zkSync-related operations on layer 1. This class extends -`ethers.providers.JsonRpcSigner` and so supports all the methods available for it. - -The easiest way to construct it is from an `Web3Provider` object. - -```ts -import { Provider, L1Signer, types } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const provider = new ethers.providers.Web3Provider(window.ethereum); -const zksyncProvider = Provider.getDefaultProvider(types.Network.Sepolia); -const signer = L1Signer.from(provider.getSigner(), zksyncProvider); -``` - -### `getMainContract` - -Returns the main zkSync Era smart contract address. - -```ts -async getMainContract(): Promise -``` - -#### Example - -```ts -import { Provider, L1Signer, types } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const provider = new ethers.providers.Web3Provider(window.ethereum); -const zksyncProvider = Provider.getDefaultProvider(types.Network.Sepolia); -const signer = L1Signer.from(provider.getSigner(), zksyncProvider); - -const mainContract = await signer.getMainContract(); -console.log(mainContract.address); -``` - -### `getL1BridgeContracts` - -Returns L1 bridge contracts. - -```ts -async getL1BridgeContracts(): Promise<{ erc20: IL1Bridge; weth: IL1Bridge }> -``` - -:::note - -there is no separate Ether bridge contract, [Main contract](./accounts.md#getmaincontract) is used instead. - -::: - -### Example - -```ts -import { Provider, L1Signer, types } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const provider = new ethers.providers.Web3Provider(window.ethereum); -const zksyncProvider = Provider.getDefaultProvider(types.Network.Sepolia); -const signer = L1Signer.from(provider.getSigner(), zksyncProvider); - -const l1BridgeContracts = await signer.getL1BridgeContracts(); -``` - -### `getBalanceL1` - -Returns the amount of the token the `L1Signer` has on Ethereum. - -#### Inputs - -| Parameter | Type | Description | -| ----------- | ---------- | ---------------------------------------------------------------------------------------------------------------- | -| `token?` | `Address` | The address of the token. ETH by default. | -| `blockTag?` | `BlockTag` | In which block a balance should be checked on. `committed`, i.e. the latest processed one is the default option. | - -```ts -async getBalanceL1(token?: Address, blockTag?: BlockTag): Promise -``` - -#### Example - -```ts -import { Provider, L1Signer, types } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const provider = new ethers.providers.Web3Provider(window.ethereum); -const zksyncProvider = Provider.getDefaultProvider(types.Network.Sepolia); -const signer = L1Signer.from(provider.getSigner(), zksyncProvider); - -const tokenL1 = '0x56E69Fa1BB0d1402c89E3A4E3417882DeA6B14Be'; - -// Getting token balance -console.log(await signer.getBalanceL1(tokenL1)); - -// Getting ETH balance -console.log(await signer.getBalanceL1()); -``` - -### `l2TokenAddress` - -Returns the L2 token address equivalent for a L1 token address as they are not equal. ETH's address is set to zero -address. - -:::warning Only works for tokens bridged on default zkSync Era bridges. ::: - -#### Inputs - -| Parameter | Type | Description | -| --------- | --------- | ------------------------------- | -| `token` | `Address` | The address of the token on L1. | - -```ts -async l2TokenAddress(token: Address): Promise -``` - -#### Example - -```ts -import { Provider, L1Signer, types } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const provider = new ethers.providers.Web3Provider(window.ethereum); -const zksyncProvider = Provider.getDefaultProvider(types.Network.Sepolia); -const signer = L1Signer.from(provider.getSigner(), zksyncProvider); - -const tokenL1 = '0x5C221E77624690fff6dd741493D735a17716c26B'; - -console.log(`Token L2 address: ${await signer.l2TokenAddress(tokenL1)}`); -``` - -### `getAllowanceL1` - -Returns the amount of approved tokens for a specific L1 bridge. - -#### Inputs - -| Parameter | Type | Description | -| ---------------- | ---------- | ----------------------------------------------------------------------------------------------------------------------------------------- | -| `token` | `Address` | The Ethereum address of the token. | -| `bridgeAddress?` | `Address` | The address of the bridge contract to be used. Defaults to the default zkSync bridge, either `L1EthBridge` or `L1Erc20Bridge` (optional). | -| `blockTag?` | `BlockTag` | In which block an allowance should be checked on. `committed`, i.e. the latest processed one is the default option (optional). | - -```ts -async getAllowanceL1( - token: Address, - bridgeAddress?: Address, - blockTag?: ethers.BlockTag -): Promise -``` - -#### Example - -```ts -import { Provider, L1Signer, types } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const provider = new ethers.providers.Web3Provider(window.ethereum); -const zksyncProvider = Provider.getDefaultProvider(types.Network.Sepolia); -const signer = L1Signer.from(provider.getSigner(), zksyncProvider); - -const tokenL1 = '0x5C221E77624690fff6dd741493D735a17716c26B'; -console.log(`Token allowance: ${await signer.getAllowanceL1(tokenL1)}`); -``` - -### `approveERC20` - -Bridging ERC20 tokens from Ethereum requires approving the tokens to the zkSync Ethereum smart contract. - -#### Inputs - -| Parameter | Type | Description | -| ------------ | ------------------- | ----------------------------------------------------------------------------------------------------- | -| `token` | `Address` | The Ethereum address of the token. | -| `amount` | `BigNumberish` | The amount of the token to be approved. | -| `overrides?` | `ethers.Overrides?` | Transaction's overrides which may be used to pass l2 `gasLimit`, `gasPrice`, `value`, etc (optional). | - -```ts -async approveERC20( - token: Address, - amount: BigNumberish, - overrides?: ethers.Overrides & { bridgeAddress?: Address } -): Promise -``` - -#### Example - -```ts -import { Provider, L1Signer, types } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const provider = new ethers.providers.Web3Provider(window.ethereum); -const zksyncProvider = Provider.getDefaultProvider(types.Network.Sepolia); -const signer = L1Signer.from(provider.getSigner(), zksyncProvider); - -const tokenL1 = '0x56E69Fa1BB0d1402c89E3A4E3417882DeA6B14Be'; -const txHandle = await signer.approveERC20(tokenL1, '10000000'); - -await txHandle.wait(); -``` - -### `getBaseCost` - -Returns base cost for L2 transaction. - -#### Inputs - -| Name | Type | Description | -| --------------------------- | -------------- | ------------------------------------------------------------------------------------------------- | -| `params.gasLimit` | `BigNumberish` | The `gasLimit` for the L2 contract call. | -| `params.gasPerPubdataByte?` | `BigNumberish` | The L2 gas price for each published L1 calldata byte (optional). | -| `params.gasPrice?` | `BigNumberish` | The L1 gas price of the L1 transaction that will send the request for an execute call (optional). | - -```ts -async getBaseCost(params: { - gasLimit: BigNumberish; - gasPerPubdataByte?: BigNumberish; - gasPrice?: BigNumberish; -}): Promise -``` - -#### Example - -```ts -import { Provider, L1Signer, types } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const provider = new ethers.providers.Web3Provider(window.ethereum); -const zksyncProvider = Provider.getDefaultProvider(types.Network.Sepolia); -const signer = L1Signer.from(provider.getSigner(), zksyncProvider); - -console.log(`Base cost: ${await signer.getBaseCost({ gasLimit: 100_000 })}`); -``` - -### `deposit` - -Transfers the specified token from the associated account on the L1 network to the target account on the L2 network. The -token can be either ETH or any ERC20 token. For ERC20 tokens, enough approved tokens must be associated with the -specified L1 bridge (default one or the one defined in `transaction.bridgeAddress`). In this case, -`transaction.approveERC20` can be enabled to perform token approval. If there are already enough approved tokens for the -L1 bridge, token approval will be skipped. To check the amount of approved tokens for a specific bridge, use the -[`allowanceL1`](#getallowancel1) method. - -#### Inputs - -| Parameter | Type | Description | -| -------------------------------- | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `transaction.token` | `Address` | The address of the token to deposit. `ETH` by default. | -| `transaction.amount` | `BigNumberish` | The amount of the token to withdraw. | -| `transaction.to?` | `Address` | The address that will receive the deposited tokens on L2 (optional). | -| `transaction.operatorTip?` | `BigNumberish` | (_currently is not used_) If the ETH value passed with the transaction is not explicitly stated in the overrides,
this field will be equal to the tip the operator will receive on top of the base cost of the transaction (optional). | -| `transaction.bridgeAddress?` | `Address` | The address of the bridge contract to be used. Defaults to the default zkSync bridge (either `L1EthBridge` or `L1Erc20Bridge`) (optional). | -| `transaction.approveERC20?` | `boolean` | Whether or not should the token approval be performed under the hood. Set this flag to `true` if you bridge an ERC20 token and didn't call the `approveERC20` function beforehand (optional). | -| `transaction.l2GasLimit?` | `BigNumberish` | Maximum amount of L2 gas that transaction can consume during execution on L2 (optional). | -| `transaction.gasPerPubdataByte?` | `BigNumberish` | Whether or not should the token approval be performed under the hood. Set this flag to `true` if you bridge an ERC20 token and didn't call the `approveERC20` function beforehand (optional). | -| `transaction.refundRecipient?` | `Address` | The address on L2 that will receive the refund for the transaction. If the transaction fails, it will also be the address to receive l2Value (optional). | -| `transaction.overrides?` | `ethers.PayableOverrides` | Transaction's overrides which may be used to pass l2 `gasLimit`, `gasPrice`, `value`, etc (optional). | -| `transaction.approveOverrides?` | `ethers.Overrides` | Transaction's overrides which may be used to pass l2 `gasLimit`, `gasPrice`, `value`, etc (optional). | -| `transaction.customBridgeData?` | `BytesLike` | Additional data that can be sent to a bridge (optional). | - -```ts -async deposit(transaction: { - token: Address; - amount: BigNumberish; - to?: Address; - operatorTip?: BigNumberish; - bridgeAddress?: Address; - approveERC20?: boolean; - l2GasLimit?: BigNumberish; - gasPerPubdataByte?: BigNumberish; - refundRecipient?: Address; - overrides?: ethers.PayableOverrides; - approveOverrides?: ethers.Overrides; - customBridgeData?: BytesLike; -}): Promise -``` - -#### Example - -```ts -import { Provider, L1Signer, types } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const provider = new ethers.providers.Web3Provider(window.ethereum); -const zksyncProvider = Provider.getDefaultProvider(types.Network.Sepolia); -const signer = L1Signer.from(provider.getSigner(), zksyncProvider); - -const tokenL1 = '0x56E69Fa1BB0d1402c89E3A4E3417882DeA6B14Be'; -const tokenDepositHandle = await signer.deposit({ - token: tokenL1, - amount: '10000000', - approveERC20: true, -}); -// Note that we wait not only for the L1 transaction to complete but also for it to be -// processed by zkSync. If we want to wait only for the transaction to be processed on L1, -// we can use `await tokenDepositHandle.waitL1Commit()` -await tokenDepositHandle.wait(); - -const ethDepositHandle = await signer.deposit({ - token: utils.ETH_ADDRESS, - amount: '10000000', -}); -// Note that we wait not only for the L1 transaction to complete but also for it to be -// processed by zkSync. If we want to wait only for the transaction to be processed on L1, -// we can use `await ethDepositHandle.waitL1Commit()` -await ethDepositHandle.wait(); -``` - -### `getDepositTx` - -Returns populated deposit transaction. - -#### Inputs - -| Parameter | Type | Description | -| -------------------------------- | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `transaction.token` | `Address` | The address of the token to deposit. `ETH` by default. | -| `transaction.amount` | `BigNumberish` | The amount of the token to withdraw. | -| `transaction.to?` | `Address` | The address that will receive the deposited tokens on L2 (optional). | -| `transaction.operatorTip?` | `BigNumberish` | (_currently is not used_) If the ETH value passed with the transaction is not explicitly stated in the overrides,
this field will be equal to the tip the operator will receive on top of the base cost of the transaction (optional). | -| `transaction.bridgeAddress?` | `Address` | The address of the bridge contract to be used. Defaults to the default zkSync bridge (either `L1EthBridge` or `L1Erc20Bridge`) (optional). | -| `transaction.l2GasLimit?` | `BigNumberish` | Maximum amount of L2 gas that transaction can consume during execution on L2 (optional). | -| `transaction.gasPerPubdataByte?` | `BigNumberish` | Whether or not should the token approval be performed under the hood. Set this flag to `true` if you bridge an ERC20 token and didn't call the `approveERC20` function beforehand (optional). | -| `transaction.customBridgeData?` | `BytesLike` | Additional data that can be sent to a bridge (optional). | -| `transaction.refundRecipient?` | `Address` | The address on L2 that will receive the refund for the transaction. If the transaction fails, it will also be the address to receive l2Value (optional). | -| `transaction.overrides?` | `ethers.PayableOverrides` | Transaction's overrides which may be used to pass l2 `gasLimit`, `gasPrice`, `value`, etc (optional). | - -```ts -async getDepositTx(transaction: { - token: Address; - amount: BigNumberish; - to?: Address; - operatorTip?: BigNumberish; - bridgeAddress?: Address; - l2GasLimit?: BigNumberish; - gasPerPubdataByte?: BigNumberish; - customBridgeData?: BytesLike; - refundRecipient?: Address; - overrides?: ethers.PayableOverrides; -}): Promise -``` - -#### Example - -```ts -import { Provider, L1Signer, types } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const provider = new ethers.providers.Web3Provider(window.ethereum); -const zksyncProvider = Provider.getDefaultProvider(types.Network.Sepolia); -const signer = L1Signer.from(provider.getSigner(), zksyncProvider); - -const tokenL1 = '0x56E69Fa1BB0d1402c89E3A4E3417882DeA6B14Be'; -const tx = await signer.getDepositTx({ - token: tokenL1, - amount: '10000000', -}); -``` - -### `estimateGasDeposit` - -Estimates the amount of gas required for a deposit transaction on L1 network. Gas of approving ERC20 token is not -included in estimation. - -#### Inputs - -| Parameter | Type | Description | -| -------------------------------- | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `transaction.token` | `Address` | The address of the token to deposit. `ETH` by default. | -| `transaction.amount` | `BigNumberish` | The amount of the token to withdraw. | -| `transaction.to?` | `Address` | The address that will receive the deposited tokens on L2 (optional). | -| `transaction.operatorTip?` | `BigNumberish` | (_currently is not used_) If the ETH value passed with the transaction is not explicitly stated in the overrides,
this field will be equal to the tip the operator will receive on top of the base cost of the transaction (optional). | -| `transaction.bridgeAddress?` | `Address` | The address of the bridge contract to be used. Defaults to the default zkSync bridge (either `L1EthBridge` or `L1Erc20Bridge`) (optional). | -| `transaction.l2GasLimit?` | `BigNumberish` | Maximum amount of L2 gas that transaction can consume during execution on L2 (optional). | -| `transaction.gasPerPubdataByte?` | `BigNumberish` | Whether or not should the token approval be performed under the hood. Set this flag to `true` if you bridge an ERC20 token and didn't call the `approveERC20` function beforehand (optional). | -| `transaction.customBridgeData?` | `BytesLike` | Additional data that can be sent to a bridge (optional). | -| `transaction.refundRecipient?` | `Address` | The address on L2 that will receive the refund for the transaction. If the transaction fails, it will also be the address to receive l2Value (optional). | -| `transaction.overrides?` | `ethers.PayableOverrides` | Transaction's overrides which may be used to pass l2 `gasLimit`, `gasPrice`, `value`, etc (optional). | - -```ts -async estimateGasDeposit(transaction: - token: Address; - amount: BigNumberish; - to?: Address; - operatorTip?: BigNumberish; - bridgeAddress?: Address; - customBridgeData?: BytesLike; - l2GasLimit?: BigNumberish; - gasPerPubdataByte?: BigNumberish; - refundRecipient?: Address; - overrides?: ethers.PayableOverrides; - }): Promise -``` - -#### Example - -```ts -import { Provider, L1Signer, types } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const provider = new ethers.providers.Web3Provider(window.ethereum); -const zksyncProvider = Provider.getDefaultProvider(types.Network.Sepolia); -const signer = L1Signer.from(provider.getSigner(), zksyncProvider); - -const tokenL1 = '0x5C221E77624690fff6dd741493D735a17716c26B'; -const gas = await signer.estimateGasDeposit({ - token: tokenL1, - amount: '10000000', -}); -console.log(`Gas: ${gas}`); -``` - -### `getFullRequiredDepositFee` - -Retrieves the full needed ETH fee for the deposit. Returns the L1 fee and the L2 fee -[`FullDepositFee`](./types.md#fulldepositfee). - -#### Inputs - -| Parameter | Type | Description | -| -------------------------------- | ------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `transaction.token` | `Address` | The address of the token to deposit. `ETH` by default. | -| `transaction.to?` | `Address` | The address that will receive the deposited tokens on L2 (optional). | -| `transaction.bridgeAddress?` | `Address` | The address of the bridge contract to be used. Defaults to the default zkSync bridge (either `L1EthBridge` or `L1Erc20Bridge`) (optional). | -| `transaction.customBridgeData?` | `BytesLike` | Additional data that can be sent to a bridge (optional). | -| `transaction.gasPerPubdataByte?` | `BigNumberish` | Whether or not should the token approval be performed under the hood. Set this flag to `true` if you bridge an ERC20 token and didn't call the `approveERC20` function beforehand (optional). | -| `transaction.overrides?` | `ethers.PayableOverrides` | Transaction's overrides which may be used to pass l2 `gasLimit`, `gasPrice`, `value`, etc (optional). | - -```ts -async getFullRequiredDepositFee(transaction: { - token: Address; - to?: Address; - bridgeAddress?: Address; - customBridgeData?: BytesLike; - gasPerPubdataByte?: BigNumberish; - overrides?: ethers.PayableOverrides; -}): Promise -``` - -#### Example - -```ts -import { Provider, L1Signer, types } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const provider = new ethers.providers.Web3Provider(window.ethereum); -const zksyncProvider = Provider.getDefaultProvider(types.Network.Sepolia); -const signer = L1Signer.from(provider.getSigner(), zksyncProvider); - -const tokenL1 = '0x56E69Fa1BB0d1402c89E3A4E3417882DeA6B14Be'; -const fee = await signer.getFullRequiredDepositFee({ - token: tokenL1, - to: await wallet.getAddress(), -}); -console.log(`Fee: ${fee}`); -``` - -### `claimFailedDeposit` - -The `claimFailedDeposit` method withdraws funds from the initiated deposit, which failed when finalizing on L2. -If the deposit L2 transaction has failed, it sends an L1 transaction calling `claimFailedDeposit` method of the L1 -bridge, which results in returning L1 tokens back to the depositor, otherwise throws the error. - -#### Inputs - -| Parameter | Type | Description | -| ----------- | --------- | ---------------------------------------------- | -| depositHash | `bytes32` | The L2 transaction hash of the failed deposit. | - -```ts -async claimFailedDeposit(depositHash: BytesLike): Promise -``` - -#### Example - -```ts -import { Provider, L1Signer, types } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const provider = new ethers.providers.Web3Provider(window.ethereum); -const zksyncProvider = Provider.getDefaultProvider(types.Network.Sepolia); -const signer = L1Signer.from(provider.getSigner(), zksyncProvider); - -const FAILED_DEPOSIT_HASH = ''; -const claimFailedDepositHandle = await signer.claimFailedDeposit(FAILED_DEPOSIT_HASH); -``` - -### `finalizeWithdrawal` - -Proves the inclusion of the L2 -> L1 withdrawal message. - -#### Inputs - -| Name | Type | Description | -| ---------------- | ----------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | -| `withdrawalHash` | `BytesLike` | Hash of the L2 transaction where the withdrawal was initiated. | -| `index?` | `number` | In case there were multiple withdrawals in one transaction, you may pass an index of the withdrawal you want to finalize. Defaults to 0 (optional). | - -```ts -async finalizeWithdrawal(withdrawalHash: BytesLike, index: number = 0): Promise -``` - -#### Example - -```ts -import { Provider, L1Signer, types } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const provider = new ethers.providers.Web3Provider(window.ethereum); -const zksyncProvider = Provider.getDefaultProvider(types.Network.Sepolia); -const signer = L1Signer.from(provider.getSigner(), zksyncProvider); - -const WITHDRAWAL_HASH = ''; -const finalizeWithdrawHandle = await signer.finalizeWithdrawal(WITHDRAWAL_HASH); -``` - -### `isWithdrawalFinalized` - -Returns weather the withdrawal transaction is finalized on the L1 network. - -#### Inputs - -| Name | Type | Description | -| ---------------- | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | -| `withdrawalHash` | `BytesLike` | Hash of the L2 transaction where the withdrawal was initiated. | -| `index?` | `number` | In case there were multiple withdrawals in one transaction, you may pass an index of the withdrawal you want to finalize. Defaults to 0) (optional). | - -```ts -async isWithdrawalFinalized(withdrawalHash: BytesLike, index: number = 0): Promise -``` - -#### Example - -```ts -import { Provider, L1Signer, types } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const provider = new ethers.providers.Web3Provider(window.ethereum); -const zksyncProvider = Provider.getDefaultProvider(types.Network.Sepolia); -const signer = L1Signer.from(provider.getSigner(), zksyncProvider); - -const WITHDRAWAL_HASH = ''; -const isFinalized = await signer.isWithdrawalFinalized(WITHDRAWAL_HASH); -``` - -### `finalizeWithdrawalParams` - -Returns the [parameters](./types.md#finalizewithdrawalparams) required for finalizing a withdrawal from the withdrawal -transaction's log on the L1 network. - -#### Inputs - -| Name | Type | Description | -| ---------------- | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | -| `withdrawalHash` | `BytesLike` | Hash of the L2 transaction where the withdrawal was initiated. | -| `index?` | `number` | In case there were multiple withdrawals in one transaction, you may pass an index of the withdrawal you want to finalize. Defaults to 0) (optional). | - -```ts -async finalizeWithdrawalParams(withdrawalHash: BytesLike, index: number = 0): Promise -``` - -#### Example - -```ts -import { Provider, L1Signer, types } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const provider = new ethers.providers.Web3Provider(window.ethereum); -const zksyncProvider = Provider.getDefaultProvider(types.Network.Sepolia); -const signer = L1Signer.from(provider.getSigner(), zksyncProvider); - -const WITHDRAWAL_HASH = ''; -const params = await signer.finalizeWithdrawalParams(WITHDRAWAL_HASH); -``` - -### `requestExecute` - -Request execution of L2 transaction from L1. - -#### Inputs - -| Name | Type | Description | -| -------------------------------- | ------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `transaction.contractAddress` | `Address` | The L2 contract to be called (optional). | -| `transaction.calldata` | `BytesLike` | The input of the L2 transaction (optional). | -| `transaction.l2GasLimit` | `BigNumberish` | Maximum amount of L2 gas that transaction can consume during execution on L2 (optional). | -| `transaction.l2Value?` | `BigNumberish` | `msg.value` of L2 transaction (optional). | -| `transaction.factoryDeps?` | `ethers.BytesLike[]` | An array of L2 bytecodes that will be marked as known on L2 (optional). | -| `transaction.operatorTip?` | `BigNumberish` | (_currently is not used_) If the ETH value passed with the transaction is not explicitly stated in the overrides, this field will be equal to the tip the operator will receive on top of the base cost of the transaction (optional). | -| `transaction.gasPerPubdataByte?` | `BigNumberish` | The L2 gas price for each published L1 calldata byte (optional). | -| `transaction.refundRecipient?` | `Address` | The address on L2 that will receive the refund for the transaction. If the transaction fails, it will also be the address to receive `l2Value` (optional). | -| `transaction.overrides?` | `ethers.PayableOverrides` | Transaction's overrides which may be used to pass l2 `gasLimit`, `gasPrice`, `value`, etc (optional). | - -```ts -async requestExecute(transaction: { - contractAddress: Address; - calldata: string; - l2GasLimit: BigNumberish; - l2Value?: BigNumberish; - factoryDeps?: ethers.BytesLike[]; - operatorTip?: BigNumberish; - gasPerPubdataByte?: BigNumberish; - refundRecipient?: Address; - overrides?: ethers.PayableOverrides; -}): Promise -``` - -#### Example - -```ts -import { Provider, L1Signer, types } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const CONTRACT_ADDRESS = ''; - -const provider = new ethers.providers.Web3Provider(window.ethereum); -const zksyncProvider = Provider.getDefaultProvider(types.Network.Sepolia); -const signer = L1Signer.from(provider.getSigner(), zksyncProvider); - -const gasPrice = await signer.providerL1.getGasPrice(); - -// The calldata can be encoded the same way as for Ethereum. -// Here is an example of how to get the calldata from an ABI: -const abi = [ - { - inputs: [], - name: 'increment', - outputs: [], - stateMutability: 'nonpayable', - type: 'function', - }, -]; -const contractInterface = new ethers.utils.Interface(abi); -const calldata = contractInterface.encodeFunctionData('increment', []); -const l2GasLimit = BigNumber.from(1000); - -const txCostPrice = await signer.getBaseCost({ - gasPrice, - calldataLength: ethers.utils.arrayify(calldata).length, - l2GasLimit, -}); - -console.log(`Executing the transaction will cost ${ethers.utils.formatEther(txCostPrice)} ETH`); - -const executeTx = await signer.requestExecute({ - contractAddress: CONTRACT_ADDRESS, - calldata, - l2Value: 1, - l2GasLimit, - overrides: { - gasPrice, - value: txCostPrice, - }, -}); - -await executeTx.wait(); -``` - -### `getRequestExecuteTx` - -Returns populated deposit transaction. - -#### Inputs - -| Name | Type | Description | -| -------------------------------- | ------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `transaction.contractAddress` | `Address` | The L2 contract to be called (optional). | -| `transaction.calldata` | `BytesLike` | The input of the L2 transaction (optional). | -| `transaction.l2GasLimit` | `BigNumberish` | Maximum amount of L2 gas that transaction can consume during execution on L2 (optional). | -| `transaction.l2Value?` | `BigNumberish` | `msg.value` of L2 transaction (optional). | -| `transaction.factoryDeps?` | `ethers.BytesLike[]` | An array of L2 bytecodes that will be marked as known on L2 (optional). | -| `transaction.operatorTip?` | `BigNumberish` | (_currently is not used_) If the ETH value passed with the transaction is not explicitly stated in the overrides, this field will be equal to the tip the operator will receive on top of the base cost of the transaction (optional). | -| `transaction.gasPerPubdataByte?` | `BigNumberish` | The L2 gas price for each published L1 calldata byte (optional). | -| `transaction.refundRecipient?` | `Address` | The address on L2 that will receive the refund for the transaction. If the transaction fails, it will also be the address to receive `l2Value` (optional). | -| `transaction.overrides?` | `ethers.PayableOverrides` | Transaction's overrides which may be used to pass l2 `gasLimit`, `gasPrice`, `value`, etc (optional). | - -```ts -async getRequestExecuteTx(transaction: { - contractAddress: Address; - calldata: string; - l2GasLimit?: BigNumberish; - l2Value?: BigNumberish; - factoryDeps?: ethers.BytesLike[]; - operatorTip?: BigNumberish; - gasPerPubdataByte?: BigNumberish; - refundRecipient?: Address; - overrides?: ethers.PayableOverrides; -}): Promise -``` - -#### Example - -```ts -import { Provider, L1Signer, types } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const CONTRACT_ADDRESS = ''; - -const provider = new ethers.providers.Web3Provider(window.ethereum); -const zksyncProvider = Provider.getDefaultProvider(types.Network.Sepolia); -const signer = L1Signer.from(provider.getSigner(), zksyncProvider); - -const gasPrice = await signer.providerL1.getGasPrice(); - -// The calldata can be encoded the same way as for Ethereum. -// Here is an example of how to get the calldata from an ABI: -const abi = [ - { - inputs: [], - name: 'increment', - outputs: [], - stateMutability: 'nonpayable', - type: 'function', - }, -]; -const contractInterface = new ethers.utils.Interface(abi); -const calldata = contractInterface.encodeFunctionData('increment', []); -const l2GasLimit = BigNumber.from(1000); - -const txCostPrice = await signer.getBaseCost({ - gasPrice, - calldataLength: ethers.utils.arrayify(calldata).length, - l2GasLimit, -}); - -console.log(`Executing the transaction will cost ${ethers.utils.formatEther(txCostPrice)} ETH`); - -const executeTx = await signer.getRequestExecuteTx({ - contractAddress: CONTRACT_ADDRESS, - calldata, - l2Value: 1, - l2GasLimit, - overrides: { - gasPrice, - value: txCostPrice, - }, -}); -``` - -### `estimateGasRequestExecute` - -Estimates the amount of gas required for a request execute transaction. - -#### Inputs - -| Name | Type | Description | -| -------------------------------- | ------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `transaction.contractAddress` | `Address` | The L2 contract to be called (optional). | -| `transaction.calldata` | `BytesLike` | The input of the L2 transaction (optional). | -| `transaction.l2GasLimit` | `BigNumberish` | Maximum amount of L2 gas that transaction can consume during execution on L2 (optional). | -| `transaction.l2Value?` | `BigNumberish` | `msg.value` of L2 transaction (optional). | -| `transaction.factoryDeps?` | `ethers.BytesLike[]` | An array of L2 bytecodes that will be marked as known on L2 (optional). | -| `transaction.operatorTip?` | `BigNumberish` | (_currently is not used_) If the ETH value passed with the transaction is not explicitly stated in the overrides, this field will be equal to the tip the operator will receive on top of the base cost of the transaction (optional). | -| `transaction.gasPerPubdataByte?` | `BigNumberish` | The L2 gas price for each published L1 calldata byte (optional). | -| `transaction.refundRecipient?` | `Address` | The address on L2 that will receive the refund for the transaction. If the transaction fails, it will also be the address to receive `l2Value` (optional). | -| `transaction.overrides?` | `ethers.PayableOverrides` | Transaction's overrides which may be used to pass l2 `gasLimit`, `gasPrice`, `value`, etc (optional). | - -```ts -async estimateGasRequestExecute(transaction: { - contractAddress: Address; - calldata: string; - l2GasLimit?: BigNumberish; - l2Value?: BigNumberish; - factoryDeps?: ethers.BytesLike[]; - operatorTip?: BigNumberish; - gasPerPubdataByte?: BigNumberish; - refundRecipient?: Address; - overrides?: ethers.PayableOverrides; -}): Promise -``` - -#### Example - -```ts -import { Provider, L1Signer, types } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const CONTRACT_ADDRESS = ''; - -const provider = new ethers.providers.Web3Provider(window.ethereum); -const zksyncProvider = Provider.getDefaultProvider(types.Network.Sepolia); -const signer = L1Signer.from(provider.getSigner(), zksyncProvider); - -const gasPrice = await wallet.providerL1.getGasPrice(); - -// The calldata can be encoded the same way as for Ethereum. -// Here is an example of how to get the calldata from an ABI: -const abi = [ - { - inputs: [], - name: 'increment', - outputs: [], - stateMutability: 'nonpayable', - type: 'function', - }, -]; -const contractInterface = new ethers.utils.Interface(abi); -const calldata = contractInterface.encodeFunctionData('increment', []); -const l2GasLimit = BigNumber.from(1000); - -const txCostPrice = await signer.getBaseCost({ - gasPrice, - calldataLength: ethers.utils.arrayify(calldata).length, - l2GasLimit, -}); - -console.log(`Executing the transaction will cost ${ethers.utils.formatEther(txCostPrice)} ETH`); - -const executeTx = await signer.getRequestExecuteTx({ - contractAddress: CONTRACT_ADDRESS, - calldata, - l2Value: 1, - l2GasLimit, - overrides: { - gasPrice, - value: txCostPrice, - }, -}); -``` diff --git a/content/20.build/sdks/js/contracts.md b/content/20.build/sdks/js/contracts.md deleted file mode 100644 index fee5eca4..00000000 --- a/content/20.build/sdks/js/contracts.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: JS SDK Contracts | zkSync Docs ---- - -# Contracts - -`zksync-ethers` does not implement any new `Contract` class, since `ethers.Contract` fully works out of the box. -However, for convenience, the library still re-exports this class. - -Since deploying smart contracts on zkSync has some differences from deploying on Ethereum, there is a need for a -specific `ContractFactory` method. It supports the same interface as `ethers.ContractFactory`. - -In order to pay for smart contract interactions in ERC20 tokens, `customData` override should be used. You can read more -about accessing zkSync features in [the next chapter](./features.md). diff --git a/content/20.build/sdks/js/features.md b/content/20.build/sdks/js/features.md deleted file mode 100644 index 19a49bfa..00000000 --- a/content/20.build/sdks/js/features.md +++ /dev/null @@ -1,126 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: JS SDK Features | zkSync Docs ---- - -# zkSync Era Features - -While zkSync is mostly Web3-compatible, it has some differences compared to Ethereum. The major of those are: - -- Account abstraction support (accounts may have near-arbitrary validation logic, and also paymaster support is - enabled). -- Deployment transactions require the contracts' bytecode to be passed in a separate field. -- The fee system is somewhat different. - -These require us to extend standard Ethereum transactions with new custom fields. Such extended transactions are called -EIP712 transactions since [EIP712](https://eips.ethereum.org/EIPS/eip-712) is used to sign them. You can look at the -internal structure of the EIP712 transactions [here](../../../zk-stack/concepts/transaction-lifecycle.md#eip-712-0x71). - -This document will focus solely on how to pass these arguments to the SDK. - -## Overrides - -`ethers.js` has a notion of overrides. For any on-chain transaction, `ethers.js` finds the optimal `gasPrice`, -`gasLimit`, `nonce`, and other important fields under the hood. But sometimes, you may have a need to explicitly provide -these values (you want to set a smaller `gasPrice` for instance, or sign a transaction with future `nonce`). - -In this case, you can provide an `Overrides` object as the last parameter. There you can supply fields like `gasPrice`, -`gasLimit`, `nonce` etc. - -In order to make the SDK as flexible as possible, `zksync-ethers` uses `customData` object in the overrides to supply -zkSync-specific fields. To supply zkSync-specific fields, you need to pass the following override: - -```typescript -{ - overrides: { - customData: { - gasPerPubdata?: BigNumberish; - factoryDeps?: BytesLike[]; - customSignature?: BytesLike; - paymasterParams?: { - paymaster: Address; - paymasterInput: BytesLike; - }; - } - } -} -``` - -Please note once again: everything that is inside `customData` in `overrides` is related to zkSync(L2 gas, etc). - -Examples: - -Override to deploy a contract with bytecode `0xcde...12` and enforce that the operator will not charge more than `100` -L2 gas per published bytes on Layer 1: - -```typescript -{ - customData: { - gasPerPubdata: "100", - factoryDeps: ["0xcde...12"], - } -} -``` - -Use custom signature `0x123456` for account, while using paymaster with address -`0x8e1DC7E4Bb15927E76a854a92Bf8053761501fdC` and paymaster input `0x8c5a3445`: - -```typescript -{ - customData: { - customSignature: "0x123456", - paymasterParams: { - paymaster: "0x8e1DC7E4Bb15927E76a854a92Bf8053761501fdC", - paymasterInput: "0x8c5a3445" - } - } -} -``` - -## Encoding paymaster params - -While the paymaster feature by itself does not impose any limitations on values of the `paymasterInput`, the Matter Labs -team endorses certain types of -[paymaster flows](../../developer-reference/account-abstraction.md#built-in-paymaster-flows) that are processable by -EOAs. - -zkSync SDK provides a utility method that can be used to get the correctly formed `paymasterParams` object: -[getPaymasterParams](./paymaster-utils.md#getpaymasterparams). - -## See in action - -If you want to call the method `setGreeting` of an ethers `Contract` object called `greeter`, this would look the -following way, while paying fees with the -[testnet paymaster](../../developer-reference/account-abstraction.md#testnet-paymaster): - -```ts -// The `setGreeting` method has a single parameter -- new greeting -// We will set its value as `a new greeting`. -const greeting = 'a new greeting'; -const tx = await greeter.populateTransaction.setGreeting(greeting); -const gasPrice = await sender.provider.getGasPrice(); -const gasLimit = await greeter.estimateGas.setGreeting(greeting); -const fee = gasPrice.mul(gasLimit); - -const paymasterParams = utils.getPaymasterParams(testnetPaymaster, { - type: 'ApprovalBased', - token, - minimalAllowance: fee, - innerInput: new Uint8Array(), -}); -const sentTx = await sender.sendTransaction({ - ...tx, - maxFeePerGas: gasPrice, - maxPriorityFeePerGas: BigNumber.from(0), - gasLimit, - customData: { - gasPerPubdata: utils.DEFAULT_GAS_PER_PUBDATA_LIMIT, - paymasterParams, - }, -}); -``` - -You can also check out our [tutorial](../../quick-start/hello-world.md) on the full-fledged mini-dApp, where users can -choose token to pay the fee. diff --git a/content/20.build/sdks/js/front-end.md b/content/20.build/sdks/js/front-end.md deleted file mode 100644 index 659b9562..00000000 --- a/content/20.build/sdks/js/front-end.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: JS SDK Front-end Integration | zkSync Docs ---- - -# Front-end Integration - -This section describes how to make the most of zkSync to provide the best UX. - -## Going to production right away - -If your front-end code does not deploy new smart contracts, then no changes to the codebase are required! All the -existing SDKs/infrastructure will work out-of-box. - -## Enabling zkSync features - -If you want to deploy smart contracts or enable advanced zkSync features, like account abstraction, then you need to use -the `zksync-ethers` library. You can read about the basics [here](./features.md). - -If you want to see some code, check out our basic [tutorial](../../quick-start/hello-world.md) for full mini-dApp. diff --git a/content/20.build/sdks/js/getting-started.md b/content/20.build/sdks/js/getting-started.md deleted file mode 100644 index 8297619a..00000000 --- a/content/20.build/sdks/js/getting-started.md +++ /dev/null @@ -1,84 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: JS SDK Getting Started | zkSync Docs ---- - -# Getting Started - -This is a short introduction to `zksync-ethers` SDK, but covers many of the most common operations that developers -require and provides a starting point for those newer to zkSync Era. - -## Getting zksync-ethers - -### Prerequisites - -- Node: >=v18 ([installation guide](https://nodejs.org/en/download/package-manager)) - -In order to install SDK for zkSync Era, run the command below in your terminal. - -```bash -yarn add zksync-ethers@5 -yarn add ethers@5 # ethers is a peer dependency of zksync-ethers -``` - -## Overview - -While most of the existing SDKs should work out of the box, deploying smart contracts or using unique zkSync features, -like account abstraction, requires providing additional fields to those that Ethereum transactions have by default. - -To begin, it is useful to have a basic understanding of the types of objects available and what they are responsible -for, at a high level: - -- `Provider` provides connection to the zkSync Era blockchain, which allows querying the blockchain state, such as - account, block or transaction details, querying event logs or evaluating read-only code using call. Additionally, the - client facilitates writing to the blockchain by sending transactions. -- `Wallet` wraps all operations that interact with an account. An account generally has a private key, which can be used - to sign a variety of types of payloads. It provides easy usage of the most common features. - -## Examples - -The following examples could be easily run by writing the code snippets in a file and executing them as follows: - -```shell -npx ts-node src/zksync.ts -``` - -Connect to the zkSync Era network: - -```ts -import { Provider, utils, types } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const ethProvider = ethers.getDefaultProvider('sepolia'); -``` - -Get the network (helper function [toJSON](./providers.md#tojson)): - -```ts -console.log(`Network: ${toJSON(await provider.getNetwork())}`); -``` - -Get the latest block number: - -```ts -console.log(`Block number: ${await provider.getBlockNumber()}`); -``` - -Get the block by hash (helper function [toJSON](./providers.md#tojson)): - -```ts -console.log( - `Block: ${toJSON(await provider.getBlock('b472c070c9e121ba42702f6c322b7b266e287a4d8b5fa426ed265b105430c397', true))}` -); -``` - -Get the transaction by hash (helper function [toJSON](./providers.md#tojson)): - -```ts -console.log( - `Block: ${toJSON(await provider.getTransaction('0x9af27afed9a4dd018c0625ea1368afb8ba08e4cfb69b3e76dfb8521c8a87ecfc'))}` -); -``` diff --git a/content/20.build/sdks/js/paymaster-utils.md b/content/20.build/sdks/js/paymaster-utils.md deleted file mode 100644 index 3bcdddb5..00000000 --- a/content/20.build/sdks/js/paymaster-utils.md +++ /dev/null @@ -1,91 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: JS SDK Paymaster Utilities | zkSync Docs ---- - -# Paymaster Utilities - -The [paymaster utilities library](https://github.com/zksync-sdk/zksync-ethers/blob/main/src/paymaster-utils.ts) contains -essential utilities for using paymasters on zkSync Era. - -## Contract interfaces - -Constant ABI definition for the -[Paymaster Flow Interface](https://github.com/matter-labs/era-contracts/blob/583cb674a2b942dda34e9f46edb5a9f5b696b90a/l2-contracts/contracts/interfaces/IPaymasterFlow.sol). - -```typescript -export const PAYMASTER_FLOW_ABI = new ethers.Interface(require('../abi/IPaymasterFlow.json')); -``` - -## Functions - -### `getApprovalBasedPaymasterInput` - -Returns encoded input for an approval-based paymaster. - -#### Inputs - -| Parameter | Type | Description | -| ---------------- | ----------------------------------------------------------------------- | -------------------------------- | -| `paymasterInput` | [`ApprovalBasedPaymasterInput`](./types.md#approvalbasedpaymasterinput) | The input data to the paymaster. | - -```ts -export function getApprovalBasedPaymasterInput(paymasterInput: ApprovalBasedPaymasterInput): BytesLike; -``` - -### `getGeneralPaymasterInput` - -As above but for general-based paymaster. - -#### Inputs - -| Parameter | Type | Description | -| ---------------- | ----------------------------------------------------------- | -------------------------------- | -| `paymasterInput` | [`GeneralPaymasterInput`](./types.md#generalpaymasterinput) | The input data to the paymaster. | - -```ts -export function getGeneralPaymasterInput(paymasterInput: GeneralPaymasterInput): BytesLike; -``` - -### `getPaymasterParams` - -Returns a correctly-formed `paymasterParams` object for common -[paymaster flows](../../developer-reference/account-abstraction.md#built-in-paymaster-flows). - -#### Inputs - -| Parameter | Type | Description | -| ------------------ | --------------------------------------------- | --------------------------------- | -| `paymasterAddress` | `Address` | The non-zero `paymaster` address. | -| `paymasterInput` | [`PaymasterInput`](./types.md#paymasterinput) | The input data to the paymaster. | - -```typescript -export function getPaymasterParams(paymasterAddress: Address, paymasterInput: PaymasterInput): PaymasterParams; -``` - -Find out more about the [`PaymasterInput` type](./types.md). - -#### Examples - -Creating `General` paymaster parameters. - -```ts -const paymasterAddress = '0x0a67078A35745947A37A552174aFe724D8180c25'; -const paymasterParams = utils.getPaymasterParams(paymasterAddress, { - type: 'General', - innerInput: new Uint8Array(), -}); -``` - -Creating `ApprovalBased` paymaster parameters. - -```ts -const result = utils.getPaymasterParams('0x0a67078A35745947A37A552174aFe724D8180c25', { - type: 'ApprovalBased', - token: '0x65C899B5fb8Eb9ae4da51D67E1fc417c7CB7e964', - minimalAllowance: BigInt(1), - innerInput: new Uint8Array(), -}); -``` diff --git a/content/20.build/sdks/js/providers.md b/content/20.build/sdks/js/providers.md deleted file mode 100644 index d91e48d0..00000000 --- a/content/20.build/sdks/js/providers.md +++ /dev/null @@ -1,1416 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: JS SDK Providers | zkSync Docs ---- - -# Providers - -A Web3 Provider object provides application-layer access to underlying blockchain networks. - -The [`zksync-ethers`](https://www.npmjs.com/package/zksync-ethers/v/5.0.0) library supports provider methods from the -[`ethers.js`](https://docs.ethers.io/v5/api/providers) library and supplies additional functionality. - -Two providers are available: - -- [`Provider`](#provider): Supplies the same functionality as - [`ethers.providers.JsonRpcProvider`](https://docs.ethers.org/v5/api/providers/jsonrpc-provider/#JsonRpcProvider) and - extends it with zkSync-specific methods. -- [`Web3Provider`](#web3provider): Extends the zkSync Era [`Provider`](#provider) class to make it more compatible with - Web3 wallets. - -:::tip - -- Use the [`Web3Provider`](#web3provider) for browser integrations. -- Access the latest [provider.ts code](https://github.com/zksync-sdk/zksync-ethers/blob/ethers-v5/src/provider.ts) in - the zkSync Era GitHub repo. ::: - -## `Provider` - -:::info - -- This doc details zkSync Era specific methods. -- Ethers implementations link to the [Ethers Providers documentation](https://docs.ethers.org/v5/api/providers/). ::: - -### `constructor` - -Returns a zkSync Era `Provider` object. - -#### Inputs - -| Parameter | Type | Description | -| ---------- | -------------------------------------------------------------------------------------- | -------------------------- | -| `url?` | string or [`ConnectionInfo`](https://docs.ethers.org/v5/api/utils/web/#ConnectionInfo) | Network RPC URL (optional) | -| `network?` | `ethers.providers.Networkish` | Network name (optional) | - -```ts -constructor(url?: ConnectionInfo | string, network?: ethers.providers.Networkish) -``` - -#### Example - -```ts -import { Provider } from 'zksync-ethers'; - -const provider = new Provider('https://sepolia.era.zksync.dev'); -``` - -### `estimateFee` - -Returns an estimated [`Fee`](./types.md#fee) for requested transaction. - -#### Inputs - -| Parameter | Type | Description | -| ------------- | ---------------------------------------------------------------------------------------------------- | -------------------- | -| `transaction` | [`TransactionRequest`](https://docs.ethers.org/v5/api/providers/types/#providers-TransactionRequest) | Transaction request. | - -```ts -async estimateFee(transaction: TransactionRequest): Promise -``` - -Helper function: [toJSON](#tojson). - -```ts -import { Provider, types } from 'zksync-ethers'; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const fee = await provider.estimateFee({ - from: '0x36615Cf349d7F6344891B1e7CA7C72883F5dc049', - to: '0xa61464658AfeAf65CccaaFD3a512b69A83B77618', - value: `0x${BigNumber.from(7_000_000_000).toString(16)}`, -}); -console.log(`Fee: ${toJSON(fee)}`); -``` - -### `estimateGas` - -Returns an estimate of the amount of gas required to submit a transaction to the network. - -| Parameter | Type | Description | -| ------------- | -------------------- | -------------------- | -| `transaction` | `TransactionRequest` | Transaction request. | - -```ts -async estimateGas(transaction: utils.Deferrable): Promise -``` - -#### Example - -```ts -import { Provider, types, utils } from 'zksync-ethers'; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const gasTokenApprove = await provider.estimateGas({ - from: '0x36615Cf349d7F6344891B1e7CA7C72883F5dc049', - to: '0x765F5AF819D818a8e8ee6ff63D8d0e8056DBE150', - data: utils.IERC20.encodeFunctionData('approve', [RECEIVER, 1]), -}); -console.log(`Gas for token approval tx: ${gasTokenApprove}`); -``` - -```ts -import { Provider, types, utils } from 'zksync-ethers'; -import { ethers, BigNumber } from 'ethers'; - -const ADDRESS = '0x36615Cf349d7F6344891B1e7CA7C72883F5dc049'; -const RECEIVER = '0xa61464658AfeAf65CccaaFD3a512b69A83B77618'; -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const tokenAddress = '0x927488F48ffbc32112F1fF721759649A89721F8F'; // Crown token which can be minted for free -const paymasterAddress = '0x13D0D8550769f59aa241a41897D4859c87f7Dd46'; // Paymaster for Crown token - -const paymasterParams = utils.getPaymasterParams(paymasterAddress, { - type: 'ApprovalBased', - token: tokenAddress, - minimalAllowance: BigNumber.from(1), - innerInput: new Uint8Array(), -}); - -const tokenApprove = await provider.estimateGas({ - from: ADDRESS, - to: tokenAddress, - data: utils.IERC20.encodeFunctionData('approve', [RECEIVER, 1]), - customData: { - gasPerPubdata: utils.DEFAULT_GAS_PER_PUBDATA_LIMIT, - paymasterParams, - }, -}); -console.log(`Gas for token approval using EIP-712 tx: ${tokenApprove}`); -``` - -### `estimateGasL1` - -Returns an estimate of the amount of gas required to submit a transaction from L1 to L2 as a `BigNumber` object. - -Calls the [`zks_estimateL1ToL2`](../../api.md#zks-estimategasl1tol2) JSON-RPC method. - -#### Inputs - -| Parameter | Type | Description | -| ------------- | ----------------------------------------------------- | -------------------- | -| `transaction` | [`TransactionRequest`](./types.md#transactionrequest) | Transaction request. | - -```ts -async estimateGasL1(transaction: TransactionRequest): Promise -``` - -#### Example - -```ts -import { Provider, types } from 'zksync-ethers'; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const gasL1 = await provider.estimateGasL1({ - from: '0x36615Cf349d7F6344891B1e7CA7C72883F5dc049', - to: await provider.getMainContractAddress(), - value: 7_000_000_000, - customData: { - gasPerPubdata: 800, - }, -}); -console.log(`L1 gas: ${BigNumber.from(gasL1)}`); -``` - -### `estimateGasTransfer` - -Returns the gas estimation for a transfer transaction. - -Calls internal method [`getTransferTx`](https://github.com/zksync-sdk/zksync-ethers/blob/ethers-v5/src/utils.ts) to get -the transfer transaction and sends it to the [`estimateGas`](#estimategas) method. - -#### Inputs - -| Parameter | Type | Description | -| ------------------ | ----------------------------------------------- | ----------------------------------------------------------------------------------------------------- | -| `token` | `Address` | Token address. | -| `amount` | `BigNumberish` | Amount of token. | -| `from?` | `Address` | From address (optional). | -| `to?` | `Address` | To address (optional). | -| `paymasterParams?` | [`PaymasterParams`](./types.md#paymasterparams) | Paymaster parameters (optional). | -| `overrides?` | `ethers.CallOverrides` | Transaction's overrides which may be used to pass l2 `gasLimit`, `gasPrice`, `value`, etc (optional). | - -```ts -async estimateGasTransfer(transaction: { - to: Address; - amount: BigNumberish; - from?: Address; - token?: Address; - paymasterParams ?: PaymasterParams; - overrides?: ethers.CallOverrides; -}): Promise -``` - -#### Example - -```ts -import { Provider, types, utils } from 'zksync-ethers'; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const gasTransfer = await provider.estimateGasTransfer({ - token: utils.ETH_ADDRESS, - amount: 7_000_000_000, - to: '0xa61464658AfeAf65CccaaFD3a512b69A83B77618', - from: '0x36615Cf349d7F6344891B1e7CA7C72883F5dc049', -}); -console.log(`Gas for transfer tx: ${gasTransfer}`); -``` - -### `estimateGasWithdraw` - -Returns the gas estimation for a withdrawal transaction. - -Calls internal method [`getWithdrawTx`](#getwithdrawtx) to get the withdrawal transaction and sends it to the -[`estimateGas`](#estimategas) method. - -#### Inputs - -| Parameter | Type | Description | -| ------------------ | ----------------------------------------------- | ----------------------------------------------------------------------------------------------------- | -| `token` | `Address` | Token address. | -| `amount` | `BigNumberish` | Amount of token. | -| `from?` | `Address` | From address (optional). | -| `to?` | `Address` | To address (optional). | -| `bridgeAddress?` | `Address` | Bridge address (optional). | -| `paymasterParams?` | [`PaymasterParams`](./types.md#paymasterparams) | Paymaster parameters (optional). | -| `overrides?` | `ethers.CallOverrides` | Transaction's overrides which may be used to pass l2 `gasLimit`, `gasPrice`, `value`, etc (optional). | - -```ts -async estimateGasWithdraw(transaction: { - token: Address; - amount: BigNumberish; - from?: Address; - to?: Address; - bridgeAddress?: Address; - paymasterParams ?: PaymasterParams; - overrides?: ethers.CallOverrides; -}): Promise -``` - -#### Example - -```ts -import { Provider, types, utils } from 'zksync-ethers'; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const gasWithdraw = await provider.estimateGasWithdraw({ - token: utils.ETH_ADDRESS, - amount: 7_000_000, - to: '0x36615Cf349d7F6344891B1e7CA7C72883F5dc049', - from: '0x36615Cf349d7F6344891B1e7CA7C72883F5dc049', -}); -console.log(`Gas for withdrawal tx: ${gasWithdraw}`); -``` - -### `estimateL1ToL2Execute` - -Returns gas estimation for an L1 to L2 execute operation. - -#### Inputs - -| Parameter | Type | Description | -| -------------------- | ------------------------- | ----------------------------------------------------------------------------------------------------- | -| `contractAddress` | `Address` | Address of contract. | -| `calldata` | `BytesLike` | The transaction call data. | -| `caller?` | `Address` | Caller address (optional). | -| `l2Value?` | `BigNumberish` | Current L2 gas value (optional). | -| `factoryDeps?` | `BytesLike[]` | Byte array containing contract bytecode. | -| `gasPerPubdataByte?` | `BigNumberish` | Constant representing current amount of gas per byte (optional). | -| `overrides?` | `ethers.PayableOverrides` | Transaction's overrides which may be used to pass l2 `gasLimit`, `gasPrice`, `value`, etc (optional). | - -```ts -async estimateL1ToL2Execute(transaction: { - contractAddress: Address; - calldata: BytesLike; - caller?: Address; - l2Value?: BigNumberish; - factoryDeps?: ethers.BytesLike[]; - gasPerPubdataByte?: BigNumberish; - overrides?: ethers.PayableOverrides; -}): Promise -``` - -#### Example - -```ts -import { Provider, types } from 'zksync-ethers'; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const gasL1ToL2 = await provider.estimateL1ToL2Execute({ - contractAddress: await provider.getMainContractAddress(), - calldata: '0x', - caller: '0x36615Cf349d7F6344891B1e7CA7C72883F5dc049', - l2Value: 7_000_000_000, -}); -console.log(`Gas L1 to L2: ${BigNumber.from(gasL1ToL2)}`); -``` - -### `getAllAccountBalances` - -Returns all balances for confirmed tokens given by an account address. - -Calls the [`zks_getAllAccountBalances`](../../api.md#zks-getallaccountbalances) JSON-RPC method. - -#### Inputs - -| Parameter | Type | Description | -| --------- | --------- | ---------------- | -| `address` | `Address` | Account address. | - -```ts -async getAllAccountBalances(address: Address): Promise -``` - -#### Example - -Helper function: [toJSON](#tojson). - -```ts -import { Provider, types } from 'zksync-ethers'; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const balances = await provider.getAllAccountBalances('0x36615Cf349d7F6344891B1e7CA7C72883F5dc049'); -console.log(`All balances: ${toJSON(balances)}`); -``` - -### `getBalance` - -Returns the user's balance as a `BigNumber` object for an (optional) block tag and (optional) token. - -When block and token are not supplied, `committed` and `ETH` are the default values. - -#### Inputs - -| Parameter | Type | Description | -| --------------- | ---------- | ------------------------------------------------------------------------------------- | -| `address` | `Address` | Account address. | -| `blockTag?` | `BlockTag` | Block tag for getting the balance on. Latest `committed` block is default (optional). | -| `tokenAddress?` | `Address` | Token address. ETH is default (optional). | - -```ts -async getBalance(address: Address, blockTag?: BlockTag, tokenAddress?: Address) -``` - -#### Example - -```ts -import { Provider, types } from 'zksync-ethers'; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const account = '0x36615Cf349d7F6344891B1e7CA7C72883F5dc049'; -const tokenAddress = '0x927488F48ffbc32112F1fF721759649A89721F8F'; // Crown token which can be minted for free -console.log(`ETH balance: ${await provider.getBalance(account)}`); -console.log(`Token balance: ${await provider.getBalance(account, 'latest', tokenAddres)}`); -``` - -### `getBlock` - -Returns block from the network, or false if there is no block. - -```ts -async getBlock(blockHashOrBlockTag: BlockTag | string | Promise): Promise -``` - -#### Example - -Helper function: [toJSON](#tojson). - -```ts -import { Provider, types } from 'zksync-ethers'; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -console.log(`Block: ${toJSON(await provider.getBlock('latest', true))}`); -``` - -### `getBlockDetails` - -Returns additional zkSync-specific information about the L2 block. - -Calls the [`zks_getBlockDetails`](../../api.md#zks-getblockdetails) JSON-RPC method. - -#### Inputs - -| Parameter | Type | Description | -| --------- | -------- | ------------- | -| `number` | `number` | Block number. | - -```ts -async getBlockDetails(number:number): Promise -``` - -#### Example - -Helper function: [toJSON](#tojson). - -```ts -import { Provider, types } from 'zksync-ethers'; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -console.log(`Block details: ${toJSON(await provider.getBlockDetails(90_000))}`); -``` - -### `getBytecodeByHash` - -Returns bytecode of a contract given by its hash. - -Calls the [`zks_getBytecodeByHash`](../../api.md#zks-getbytecodebyhash) JSON-RPC method. - -#### Inputs - -| Parameter | Type | Description | -| -------------- | ----------- | -------------- | -| `bytecodeHash` | `BytesLike` | Bytecode hash. | - -```ts -async getBytecodeByHash(bytecodeHash: BytesLike): Promise -``` - -#### Example - -```ts -import { Provider, types } from 'zksync-ethers'; - -// Bytecode hash can be computed by following these steps: -// const testnetPaymasterBytecode = await provider.getCode(await provider.getTestnetPaymasterAddress()); -// const testnetPaymasterBytecodeHash = ethers.utils.hexlify(utils.hashBytecode(testnetPaymasterBytecode)); - -const testnetPaymasterBytecodeHash = '0x010000f16d2b10ddeb1c32f2c9d222eb1aea0f638ec94a81d4e916c627720e30'; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -console.log(`Bytecode: ${await provider.getBytecodeByHash(testnetPaymasterBytecodeHash)}`); -``` - -### `getContractAccountInfo` - -Returns the version of the supported account abstraction and nonce ordering from a given contract address. - -#### Inputs - -| Parameter | Type | Description | -| --------- | --------- | ----------------- | -| `address` | `Address` | Contract address. | - -```ts -async getContractAccountInfo(address:Address): Promise -``` - -#### Example - -Helper function: [toJSON](#tojson). - -```ts -import { Provider, types } from 'zksync-ethers'; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const tokenAddress = '0x927488F48ffbc32112F1fF721759649A89721F8F'; // Crown token which can be minted for free -console.log(`Contract account info: ${toJSON(await provider.getContractAccountInfo(tokenAddress))}`); -``` - -### `getDefaultBridgeAddresses` - -Returns the addresses of the default zkSync Era bridge contracts on both L1 and L2. - -```ts -async getDefaultBridgeAddresses(): Promise<{erc20L1: string, erc20L2: string, wethL1: string, wethL2: string}>; -``` - -#### Example - -Helper function: [toJSON](#tojson). - -```ts -import { Provider, types } from 'zksync-ethers'; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -console.log(`Default bridges: ${toJSON(await provider.getDefaultBridgeAddresses())}`); -``` - -### `getDefaultProvider` - -Static method which returns a Provider object from the RPC URL or localhost. - -#### Inputs - -| Parameter | Type | Description | -| --------------- | ------------------------------------- | ------------------------------------------------- | -| `zksyncNetwork` | [`ZkSyncNetwork`](./types.md#network) | Type of zkSync network. `Localhost` _by default_. | - -```ts -static getDefaultProvider(zksyncNetwork: ZkSyncNetwork = ZkSyncNetwork.Localhost) -``` - -#### Example - -```ts -import { Provider, types } from 'zksync-ethers'; - -const providerMainnet = Provider.getDefaultProvider(types.Network.Mainnet); -const providerTestnet = Provider.getDefaultProvider(types.Network.Sepolia); -const providerLocalnet = Provider.getDefaultProvider(types.Network.Localhost); -``` - -### `getFilterChanges` - -Returns an array of logs by calling Ethereum method -[`eth_getFilterChanges`.](https://ethereum.github.io/execution-apis/api-documentation/) - -#### Inputs - -| Parameter | Type | Description | -| --------- | ----------- | ------------- | -| `idx` | `BigNumber` | Filter index. | - -```ts -async getFilterChanges(idx: BigNumber): Promise> -``` - -#### Example - -```ts -import { Provider, types, utils } from 'zksync-ethers'; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const filter = await provider.newFilter({ - address: utils.L2_ETH_TOKEN_ADDRESS, - topics: [ethers.id('Transfer(address,address,uint256)')], -}); -const result = await provider.getFilterChanges(filter); -``` - -### `getFormatter` - -Static utility method that returns a `Formatter` object for processing readable block data. - -```ts -static override getFormatter(): Formatter -``` - -#### Example - -```ts -import { Provider, types } from 'zksync-ethers'; - -const formatter = Provider.getFormatter(); -``` - -### `getGasPrice` - -Returns an estimate (best guess) of the gas price to use in a transaction. - -```ts -async getGasPrice(): Promise -``` - -#### Example - -```ts -import { Provider, types } from 'zksync-ethers'; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -console.log(`Gas price: ${await provider.getGasPrice()}`); -``` - -### `getL1BatchBlockRange` - -Returns the range of blocks contained within a batch given by batch number. - -Calls the [`zks_getL1BatchBlockRange`](../../api.md#zks-getl1batchblockrange) JSON-RPC method. - -#### Inputs - -| Parameter | Type | Description | -| --------------- | -------- | ---------------- | -| `l1BatchNumber` | `number` | L1 batch number. | - -```ts -async getL1BatchBlockRange(l1BatchNumber: number): Promise<[number, number] | null> -``` - -#### Example - -Helper function: [toJSON](#tojson). - -```ts -import { Provider, types } from 'zksync-ethers'; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const l1BatchNumber = await provider.getL1BatchNumber(); -console.log(`L1 batch block range: ${toJSON(await provider.getL1BatchBlockRange(l1BatchNumber))}`); -``` - -### `getL1BatchDetails` - -Returns data pertaining to a given batch. - -Calls the [`zks_getL1BatchDetails`](../../api.md#zks-getl1batchdetails) JSON-RPC method. - -#### Inputs - -| Parameter | Type | Description | -| --------- | -------- | ---------------- | -| `number` | `number` | L1 batch number. | - -```ts -async getL1BatchDetails(number: number): Promise -``` - -#### Example - -Helper function: [toJSON](#tojson). - -```ts -import { Provider, types } from 'zksync-ethers'; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const l1BatchNumber = await provider.getL1BatchNumber(); -console.log(`L1 batch details: ${toJSON(await provider.getL1BatchDetails(l1BatchNumber))}`); -``` - -### `getL1BatchNumber` - -Returns the latest L1 batch number. - -Calls the [`zks_getL1BatchNumber`](../../api.md#zks-l1batchnumber) JSON-RPC method. - -```ts -async getL1BatchNumber(): Promise -``` - -#### Example - -```ts -import { Provider, types } from 'zksync-ethers'; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -console.log(`L1 batch number: ${await provider.getL1BatchNumber()}`); -``` - -### `getL2TransactionFromPriorityOp` - -Returns a L2 transaction from L1 transaction response. - -#### Inputs - -| Parameter | Type | Description | -| -------------- | ------------------------------------------------------------------------------------------------------ | ------------------------ | -| `l1TxResponse` | [`TransactionResponse`](https://docs.ethers.org/v5/api/providers/types/#providers-TransactionResponse) | L1 transaction response. | - -```ts -async getL2TransactionFromPriorityOp(l1TxResponse: ethers.TransactionResponse): Promise -``` - -#### Example - -Helper function: [toJSON](#tojson). - -```ts -import { Provider, types } from 'zksync-ethers'; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const ethProvider = ethers.getDefaultProvider('sepolia'); -const l1Tx = '0xcca5411f3e514052f4a4ae1c2020badec6e0998adb52c09959c5f5ff15fba3a8'; -const l1TxResponse = await ethProvider.getTransaction(l1Tx); -if (l1TxResponse) { - console.log(`Tx: ${toJSON(await provider.getL2TransactionFromPriorityOp(l1TxResponse))}`); -} -``` - -### `getLogProof` - -Returns the proof for a transaction's L2 to L1 log sent via the L1Messenger system contract. - -Calls the [`zks_getL2ToL1LogProof`](../../api.md#zks-getl2tol1logproof) JSON-RPC method. - -#### Inputs - -| Parameter | Type | Description | -| --------- | ----------- | ---------------------------------------------------------------- | -| `txHash` | `BytesLike` | Hash of the L2 transaction the L2 to L1 log was produced within. | -| `index?` | `number` | The index of the L2 to L1 log in the transaction (optional). | - -```ts -async getLogProof(txHash: BytesLike, index ? : number): Promise -``` - -#### Example - -Helper function: [toJSON](#tojson). - -```ts -import { Provider, types } from 'zksync-ethers'; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -// Any L2 -> L1 transaction can be used. -// In this case, withdrawal transaction is used. -const tx = '0x2a1c6c74b184965c0cb015aae9ea134fd96215d2e4f4979cfec12563295f610e'; -console.log(`Log ${toJSON(await provider.getLogProof(tx, 0))}`); -``` - -### `getLogs` - -Returns an array of all logs that match a filter with a given id by calling Ethereum method -[`eth_getLogs.`](https://ethereum.github.io/execution-apis/api-documentation/) - -#### Inputs - -| Parameter | Type | Description | -| --------- | --------------------------------------------------------------------------- | ------------- | -| `filter` | [`Filter`] or [`FilterByBlockHash`] or `Promise` | Filter query. | - -```ts -getLogs(filter: Filter | FilterByBlockHash | Promise): Promise> -``` - -#### Example - -Helper function: [toJSON](#tojson). - -```ts -import { Provider, types } from 'zksync-ethers'; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -console.log( - `Logs: ${toJSON(await provider.getLogs({ fromBlock: 0, toBlock: 5, address: utils.L2_ETH_TOKEN_ADDRESS }))}` -); -``` - -### `getMainContractAddress` - -Returns the main zkSync Era smart contract address. - -Calls the [`zks_getMainContract`](../../api.md#zks-getmaincontract) JSON-RPC method. - -```ts -async getMainContractAddress(): Promise
-``` - -#### Example - -Helper function: [toJSON](#tojson). - -```ts -import { Provider, types } from 'zksync-ethers'; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -console.log(`Main contract: ${await provider.getMainContractAddress()}`); -``` - -### `getPriorityOpResponse` - -Returns a [`TransactionResponse`](https://docs.ethers.org/v5/api/providers/types/#providers-TransactionResponse) as a -`PriorityOpResponse` object. - -#### Inputs - -| Parameter | Type | Description | -| -------------- | ------------------------------------------------------------------------------------------------------ | ------------------------ | -| `l1TxResponse` | [`TransactionResponse`](https://docs.ethers.org/v5/api/providers/types/#providers-TransactionResponse) | L1 transaction response. | - -```ts -async getPriorityOpResponse(l1TxResponse: ethers.TransactionResponse): Promise -``` - -#### Example - -Helper function: [toJSON](#tojson). - -```ts -import { Provider, types } from 'zksync-ethers'; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const ethProvider = ethers.getDefaultProvider('sepolia'); -const l1Tx = '0xcca5411f3e514052f4a4ae1c2020badec6e0998adb52c09959c5f5ff15fba3a8'; -const l1TxResponse = await ethProvider.getTransaction(l1Tx); -if (l1TxResponse) { - console.log(`Tx: ${toJSON(await provider.getPriorityOpResponse(l1TxResponse))}`); -} -``` - -### `getProof` - -Returns Merkle [`proofs`](./types.md#storageproof) for one or more storage values at the specified account along with a -Merkle proof of their authenticity. - -Calls the [`zks_getProof`](../../api.md#zks-getproof) JSON-RPC method. - -#### Inputs - -| Parameter | Type | Description | -| --------------- | ---------- | ----------------------------------------------------------------------------------------------- | -| `address` | `Address` | The account to fetch storage values and proofs for. | -| `keys` | `string[]` | Vector of storage keys in the account. | -| `l1BatchNumber` | `number` | Number of the L1 batch specifying the point in time at which the requested values are returned. | - -```ts -async getProof(address: Address, keys: string[], l1BatchNumber: number): Promise -``` - -#### Example - -Helper function: [toJSON](#tojson). - -```ts -import { Provider, types, utils } from 'zksync-ethers'; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const address = '0x082b1BB53fE43810f646dDd71AA2AB201b4C6b04'; - -// Fetching the storage proof for rawNonces storage slot in NonceHolder system contract. -// mapping(uint256 => uint256) internal rawNonces; - -// Ensure the address is a 256-bit number by padding it -// because rawNonces slot uses uint256 for mapping addresses and their nonces. -const addressPadded = ethers.utils.hexZeroPad(wallet.address, 32); - -// Convert the slot number to a hex string and pad it to 32 bytes. -const slotPadded = ethers.utils.hexZeroPad(ethers.utils.hexlify(0), 32); - -// Concatenate the padded address and slot number. -const concatenated = addressPadded + slotPadded.slice(2); // slice to remove '0x' from the slotPadded - -// Hash the concatenated string using Keccak-256. -const storageKey = ethers.utils.keccak256(concatenated); - -const l1BatchNumber = await provider.getL1BatchNumber(); -const storageProof = await provider.getProof(utils.NONCE_HOLDER_ADDRESS, [storageKey], l1BatchNumber); -console.log(`Storage proof: ${toJSON(storageProof)}`); -``` - -### `getRawBlockTransactions` - -Returns data of transactions in a block. - -Calls the [`zks_getRawBlockTransactions`](../../api.md#zks-getrawblocktransactions) JSON-RPC method. - -#### Inputs - -| Parameter | Type | Description | -| --------- | -------- | ------------- | -| `number` | `number` | Block number. | - -```ts -async getRawBlockTransactions(number: number): Promise -``` - -#### Example - -Helper function: [toJSON](#tojson). - -```ts -import { Provider, types } from 'zksync-ethers'; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -console.log(`Raw block transactions: ${toJSON(await provider.getRawBlockTransactions(90_000))}`); -``` - -### `getTestnetPaymasterAddress` - -Returns the [testnet paymaster](../../developer-reference/account-abstraction.md#paymasters) address if available, or -null. - -```ts -async getTestnetPaymasterAddress(): Promise
-``` - -#### Example - -```ts -import { Provider, types } from 'zksync-ethers'; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -console.log(`Testnet paymaster: ${await provider.getTestnetPaymasterAddress()}`); -``` - -### `getTransaction` - -Returns a specified L2 transaction response object by overriding the -[Ethers implementation](https://docs.ethers.org/v5/api/providers/provider/#Provider-getTransaction). - -#### Inputs - -| Parameter | Type | Description | -| --------- | -------- | ----------------- | -| `txHash` | `string` | Transaction hash. | - -```typescript -override async getTransaction(hash: string | Promise): Promise -``` - -#### Example - -```ts -import { Provider, types } from 'zksync-ethers'; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); - -const TX_HASH = ''; -const txHandle = await provider.getTransaction(TX_HASH); - -// Wait until the transaction is processed by the server. -await txHandle.wait(); -// Wait until the transaction is finalized. -await txHandle.waitFinalize(); -``` - -### `getTransactionDetails` - -Returns data from a specific transaction given by the transaction hash. - -Calls the [`getTransactionDetails`](../../api.md#zks-gettransactiondetails) JSON-RPC method. - -#### Inputs - -| Parameter | Type | Description | -| --------- | ----------- | ----------------- | -| `txHash` | `BytesLike` | Transaction hash. | - -```ts -async getTransactionDetails(txHash: BytesLike): Promise -``` - -#### Example - -Helper function: [toJSON](#tojson). - -```ts -import { Provider, types } from 'zksync-ethers'; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); - -const TX_HASH = ''; -console.log(`Transaction details: ${toJSON(await provider.getTransactionDetails(TX_HASH))}`); -``` - -### `getTransactionReceipt` - -Returns the transaction receipt from a given hash number. - -[Ethers implementation.](https://docs.ethers.org/v5/api/providers/provider/#Provider-getTransactionReceipt) - -#### Inputs - -| Parameter | Type | Description | -| --------- | -------- | ----------------- | -| `txHash` | `string` | Transaction hash. | - -```ts -async getTransactionReceipt(transactionHash: string | Promise): Promise -``` - -#### Example - -Helper function: [toJSON](#tojson). - -```ts -import { Provider, types } from 'zksync-ethers'; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const TX_HASH = ''; -console.log(`Transaction receipt: ${toJSON(await provider.getTransactionReceipt(TX_HASH))}`); -``` - -### `getTransactionStatus` - -Returns the status of a specified transaction. - -#### Inputs - -| Parameter | Type | Description | -| --------- | -------- | ----------------- | -| `txHash` | `string` | Transaction hash. | - -```ts -async getTransactionStatus(txHash: string): Promise -``` - -#### Example - -Helper function: [toJSON](#tojson). - -```ts -import { Provider, types } from 'zksync-ethers'; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); - -const TX_HASH = ''; -console.log(`Transaction status: ${toJSON(await provider.getTransactionStatus(TX_HASH))}`); -``` - -### `getTransferTx` - -Returns the populated transfer transaction. - -#### Inputs - -| Parameter | Type | Description | -| ------------------ | ----------------------------------------------- | ----------------------------------------------------------------------------------------------------- | -| `token` | `Address` | Token address. | -| `amount` | `BigNumberish` | Amount of token. | -| `from?` | `Address` | From address (optional). | -| `to?` | `Address` | To address (optional). | -| `paymasterParams?` | [`PaymasterParams`](./types.md#paymasterparams) | Paymaster parameters (optional). | -| `overrides?` | `ethers.CallOverrides` | Transaction's overrides which may be used to pass l2 `gasLimit`, `gasPrice`, `value`, etc (optional). | - -```ts -async getTransferTx(transaction: { - to: Address; - amount: BigNumberish; - from ? : Address; - token ? : Address; - paymasterParams?: PaymasterParams; - overrides?: ethers.CallOverrides; -}): Promise -``` - -#### Examples - -Retrieve populated ETH transfer transaction. - -```ts -import { Provider, types, utils } from 'zksync-ethers'; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); - -const tx = await provider.getTransferTx({ - token: utils.ETH_ADDRESS, - amount: 7_000_000_000, - to: '0xa61464658AfeAf65CccaaFD3a512b69A83B77618', - from: '0x36615Cf349d7F6344891B1e7CA7C72883F5dc049', -}); -console.log(`Transfer tx: ${tx}`); -``` - -Retrieve populated ETH transfer transaction using paymaster to facilitate fee payment with an ERC20 token. - -```ts -import { Provider, types, utils } from 'zksync-ethers'; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const token = '0x927488F48ffbc32112F1fF721759649A89721F8F'; // Crown token which can be minted for free -const paymaster = '0x13D0D8550769f59aa241a41897D4859c87f7Dd46'; // Paymaster for Crown token - -const tx = await provider.getTransferTx({ - token: utils.ETH_ADDRESS, - amount: 7_000_000_000, - to: '0xa61464658AfeAf65CccaaFD3a512b69A83B77618', - from: '0x36615Cf349d7F6344891B1e7CA7C72883F5dc049', - paymasterParams: utils.getPaymasterParams(paymaster, { - type: 'ApprovalBased', - token: token, - minimalAllowance: 1, - innerInput: new Uint8Array(), - }), -}); -console.log(`Transfer tx: ${tx}`); -``` - -### `getWithdrawTx` - -Returns the populated withdrawal transaction. - -#### Inputs - -| Parameter | Type | Description | -| ------------------ | ----------------------------------------------- | ----------------------------------------------------------------------------------------------------- | -| `token` | `Address` | Token address. | -| `amount` | `BigNumberish` | Amount of token. | -| `from?` | `Address` | From address (optional). | -| `to?` | `Address` | To address (optional). | -| `bridgeAddress?` | `Address` | Bridge address (optional). | -| `paymasterParams?` | [`PaymasterParams`](./types.md#paymasterparams) | Paymaster parameters (optional). | -| `overrides?` | `ethers.CallOverrides` | Transaction's overrides which may be used to pass l2 `gasLimit`, `gasPrice`, `value`, etc (optional). | - -```ts -async getWithdrawTx(transaction: { - token: Address; - amount: BigNumberish; - from ? : Address; - to ? : Address; - bridgeAddress ? : Address; - paymasterParams?: PaymasterParams; - overrides?: ethers.CallOverrides; -}): Promise -``` - -#### Examples - -Retrieve populated ETH withdrawal transactions. - -```ts -import { Provider, types, utils } from 'zksync-ethers'; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); - -const tx = await provider.getWithdrawTx({ - token: utils.ETH_ADDRESS, - amount: 7_000_000_000, - to: '0x36615Cf349d7F6344891B1e7CA7C72883F5dc049', - from: '0x36615Cf349d7F6344891B1e7CA7C72883F5dc049', -}); -console.log(`Withdrawal tx: ${tx}`); -``` - -Retrieve populated ETH withdrawal transaction using paymaster to facilitate fee payment with an ERC20 token. - -```ts -import { Provider, types, utils } from 'zksync-ethers'; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const token = '0x927488F48ffbc32112F1fF721759649A89721F8F'; // Crown token which can be minted for free -const paymaster = '0x13D0D8550769f59aa241a41897D4859c87f7Dd46'; // Paymaster for Crown token - -const tx = await provider.getWithdrawTx({ - token: utils.ETH_ADDRESS, - amount: 7_000_000_000, - to: '0x36615Cf349d7F6344891B1e7CA7C72883F5dc049', - from: '0x36615Cf349d7F6344891B1e7CA7C72883F5dc049', - paymasterParams: utils.getPaymasterParams(paymaster, { - type: 'ApprovalBased', - token: token, - minimalAllowance: 1, - innerInput: new Uint8Array(), - }), -}); -console.log(`Withdrawal tx: ${tx}`); -``` - -### `l1ChainId` - -Returns the chain id of the underlying L1. - -Calls the [`zks_L1ChainId`](../../api.md#zks-l1chainid) JSON-RPC method. - -```ts -async l1ChainId(): Promise -``` - -#### Example - -```ts -import { Provider, types } from 'zksync-ethers'; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -console.log(`L1 chain ID: ${await provider.l1ChainId()}`); -``` - -### `l1TokenAddress` - -Returns the L1 token address equivalent for a L2 token address as they are not equal. ETH's address is set to zero -address. - -:::warning Only works for tokens bridged on default zkSync Era bridges. ::: - -#### Inputs - -| Parameter | Type | Description | -| --------- | --------- | ------------------------------- | -| `token` | `Address` | The address of the token on L2. | - -```ts -async l1TokenAddress(token: Address): Promise -``` - -#### Example - -```ts -import { Provider, types } from 'zksync-ethers'; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -console.log(`L1 token address: ${await provider.l1TokenAddress('0x3e7676937A7E96CFB7616f255b9AD9FF47363D4b')}`); -``` - -### `l2TokenAddress` - -Returns the L2 token address equivalent for a L1 token address as they are not equal. ETH's address is set to zero -address. - -:::warning Only works for tokens bridged on default zkSync Era bridges. ::: - -#### Inputs - -| Parameter | Type | Description | -| --------- | --------- | ------------------------------- | -| `token` | `Address` | The address of the token on L1. | - -```ts -async l2TokenAddress(token: Address): Promise -``` - -#### Example - -```ts -import { Provider, types } from 'zksync-ethers'; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -console.log(`L2 token address: ${await provider.l2TokenAddress('0x5C221E77624690fff6dd741493D735a17716c26B')}`); -``` - -### `newBlockFilter` - -Returns a new block filter by calling Ethereum method -[`eth_newBlockFilter.`](https://ethereum.github.io/execution-apis/api-documentation/) - -```ts -async newBlockFilter(): Promise -``` - -#### Example - -```ts -import { Provider, types } from 'zksync-ethers'; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -console.log(`New block filter: ${await provider.newBlockFilter()}`); -``` - -### `newFilter` - -Returns a new filter by calling Ethereum method -[`eth_newFilter`](https://ethereum.github.io/execution-apis/api-documentation/) and passing a filter object. - -#### Inputs - -| Parameter | Type | Description | -| --------- | --------------------------------------------------------------- | ------------- | -| `filter` | [`EventFilter`](types.md#eventfilter) or `Promise` | Filter query. | - -```ts -async newFilter(filter: EventFilter | Promise): Promise -``` - -#### Example - -```ts -import { Provider, types, utils } from 'zksync-ethers'; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -console.log( - `New filter: ${await provider.newFilter({ - fromBlock: 0, - toBlock: 5, - address: utils.L2_ETH_TOKEN_ADDRESS, - })}` -); -``` - -### `newPendingTransactionFilter` - -Returns a new pending transaction filter by calling Ethereum method -[`eth_newPendingTransactionFilter`](https://ethereum.github.io/execution-apis/api-documentation/) and passing a filter -object. - -```ts -async newPendingTransactionsFilter(): Promise -``` - -#### Example - -```ts -import { Provider, types } from 'zksync-ethers'; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -console.log(`New pending transaction filter: ${await provider.newPendingTransactionsFilter()}`); -``` - -### `sendTransaction` - -Override of [Ethers implementation.](https://docs.ethers.org/v5/api/providers/provider/#Provider-sendTransaction) - -#### Inputs - -| Parameter | Type | Description | -| ------------- | ----------------------------- | ------------------- | -| `transaction` | `string` or `Promise` | Signed transaction. | - -```ts -async sendTransaction(transaction: string | Promise): Promise -``` - -#### Example - -```ts -import { Provider, types, Wallet, utils } from 'zksync-ethers'; - -const PRIVATE_KEY = ''; -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const wallet = new Wallet(PRIVATE_KEY, provider); - -const signedTx = await wallet.signTransaction({ - to: '0xa61464658AfeAf65CccaaFD3a512b69A83B77618', - value: ethers.utils.parseEther('0.01'), -}); - -const tx = await provider.sendTransaction(signedTx); -console.log(tx.hash); -``` - -## `Web3Provider` - -Use this provider for Web3 browser wallet integrations for easy compatibility with Metamask, WalletConnect, and other -popular browser wallets. - -### `constructor` - -Returns a provider object by extending the constructor of the `Provider` class and accepting an `ExternalProvider` -instead of a node URL. - -#### Inputs - -| Parameter | Type | Description | -| ---------- | ----------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- | -| `provider` | [`ExternalProvider`](https://docs.ethers.org/v5/api/providers/other/#Web3Provider--ExternalProvider)) | The `ethers.providers.ExternalProvider` class instance. For instance, Metamask is `window.ethereum`. | -| `network?` | `Networkish` | The description of the network (optional). | - -```typescript -constructor(provider: ExternalProvider, network?: ethers.providers.Networkish) -``` - -#### Example - -```ts -import { Web3Provider } from 'zksync-ethers'; - -const provider = new Web3Provider(window.ethereum); -``` - -### `estimateGas` - -Returns gas estimate by overriding the zkSync Era [`estimateGas`](#estimategas) method. - -#### Inputs - -| Parameter | Type | Description | -| ------------- | -------------------- | -------------------- | -| `transaction` | `TransactionRequest` | Transaction request. | - -```ts -override async estimateGas(transaction: ethers.utils.Deferrable) -``` - -#### Example - -```ts -import { Web3Provider } from 'zksync-ethers'; - -const provider = new Web3Provider(window.ethereum); -const gas = await provider.estimateGas({ - to: '', - amount: ethers.parseEther('0.01'), -}); -console.log(`Gas: ${gas}`); -``` - -### `getSigner` - -Override of -[Ethers implementation](https://docs.ethers.org/v5/api/providers/jsonrpc-provider/#JsonRpcProvider-getSigner). - -#### Inputs - -| Parameter | Type | Description | -| ----------------- | -------------------- | ------------------------------------ | -| `addressOrIndex?` | `number` or `string` | Account address or index (optional). | - -```ts -getSigner(addressOrIndex?: number | string): Signer -``` - -#### Example - -```ts -import { Web3Provider } from 'zksync-ethers'; - -const provider = new Web3Provider(window.ethereum); -const signer = provider.getSigner(); -``` - -### `send` - -Returns a provider request object by overriding the -[Ethers implementation](https://docs.ethers.org/v5/api/providers/jsonrpc-provider/#JsonRpcProvider-send). - -#### Inputs - -| Parameter | Type | Description | -| --------- | ------------ | ---------------------------------- | -| `method` | `Address` | Request method name as string. | -| `params?` | `Array` | Parameters of any type (optional). | - -```ts -async send(method: string, params?: Array): Promise -``` - -## Appendix - -### toJSON - -```ts -function toJSON(object: any): string { - return JSON.stringify(object, (key, value) => { - if (typeof value === 'bigint') { - return value.toString(); // Convert BigInt to string - } - return value; - }); -} -``` diff --git a/content/20.build/sdks/js/types.md b/content/20.build/sdks/js/types.md deleted file mode 100644 index 1d2529c8..00000000 --- a/content/20.build/sdks/js/types.md +++ /dev/null @@ -1,365 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: JS SDK Types | zkSync Docs ---- - -# Types and Interfaces - -## `AccountAbstractionVersion` - -Enumerated list of account abstraction versions. - -- None = `0` (Used for contracts that are not accounts.) -- Version1 = `1` - -## `AccountNonceOrdering` - -Enumerated list of account nonce ordering formats. - -- Sequential = `0` -- Arbitrary = `1` - -## `Address` - -0x-prefixed, hex-encoded, Ethereum account address as string. - -## `ApprovalBasedPaymasterInput` - -Interface representation of approval based paymaster input containing various fields including an `ApprovalBased` type. - -- `type`: `'ApprovalBased'`; -- `token`: `Address`; -- `minimalAllowance`: `BigNumber`; -- `innerInput`: `BytesLike`; - -## `BalancesMap` - -Type defining a map object containing accounts and their balances. - -- `{ [key: string]`: `BigNumber }` - -## `BatchDetails` - -Interface representation of batch information containing various optional and mandatory fields. - -- `number`: `number`; -- `timestamp`: `number`; -- `l1TxCount`: `number`; -- `l2TxCount`: `number`; -- `rootHash?`: `string`; -- `status`: `string`; -- `commitTxHash?`: `string`; -- `committedAt?`: `Date`; -- `proveTxHash?`: `string`; -- `provenAt?`: `Date`; -- `executeTxHash?`: `string`; -- `executedAt?`: `Date`; -- `l1GasPrice`: `number`; -- `l2FairGasPrice`: `number`; - -## `Block` - -Interface representation of a block that extends the Ethers -[`providers.Block`](https://docs.ethers.org/v5/api/providers/types/#providers-Block) definition with additional fields. - -- `l1BatchNumber`: `number`; -- `l1BatchTimestamp`: `number`; - -## `BlockDetails` - -Interface representation of block information containing various optional and mandatory fields. - -- `number`: `number`; -- `timestamp`: `number`; -- `l1BatchNumber`: `number`; -- `l1TxCount`: `number`; -- `l2TxCount`: `number`; -- `rootHash?`: `string`; -- `status`: `string`; -- `commitTxHash?`: `string`; -- `committedAt?`: `Date`; -- `proveTxHash?`: `string`; -- `provenAt?`: `Date`; -- `executeTxHash?`: `string`; -- `executedAt?`: `Date`; - -## `BlockTag` - -Pipe-delimited list of block labels that includes block number in denary and hex plus block statuses. - -- `number` -- `string` // hex representation of block number -- "committed" -- "finalized" -- "latest" -- "earliest" -- "pending" - -## `BlockWithTransaction` - -Interface representation of a block with transaction(s) that extends the Ethers `BlockWithTransactions` definition with -additional fields. - -- `l1BatchNumber`: `number`; -- `l1BatchTimestamp`: `number`; -- `transactions`: `Array`; - -## `ContractAccountInfo` - -Interface representation for contract account information containing information on account abstraction version and -nonce ordering format. - -- `supportedAAVersion`: `AccountAbstractionVersion`; -- `nonceOrdering`: `AccountNonceOrdering`; - -## `DeploymentInfo` - -Interface representation of deployment information with various fields. - -- `sender`: `Address`; -- `bytecodeHash`: `string`; -- `deployedAddress`: `Address`; - -## `DeploymentType` - -Pipe-delimited choice of two deployment types that support all `create2` variants. - -- `create` -- `createAccount` - -## `Eip712Meta` - -Type defining an EIP-712 transaction with optional parameters. - -- `gasPerPubdata?`: `BigNumberish`; -- `factoryDeps?`: `BytesLike[]`; -- `customSignature?`: `BytesLike`; -- `paymasterParams?`: `PaymasterParams`; - -## `EthereumSignature` - -Interface representation of an Ethereum signature. - -- `v`: `number`; -- `r`: `BytesLike`; -- `s`: `BytesLike`; - -## `EventFilter` - -Interface representation of event filter containing various fields. - -- `topics?`: `Array | null>`; -- `address?`: `Address | Array
`; -- `fromBlock?`: `BlockTag`; -- `toBlock?`: `BlockTag`; -- `blockHash?`: `string`; - -## `Fee` - -Interface representation of transaction fee. - -- `gasLimit`: `BigNumber`; -- `gasPerPubdataLimit`: `BigNumber`; -- `maxPriorityFeePerGas`: `BigNumber`; -- `maxFeePerGas`: `BigNumber`; - -## `FinalizeWithdrawalParams` - -Interface representation of finalize withdrawal parameters. - -- `l1BatchNumber`: `number | null`; -- `l2MessageIndex`: `number`; -- `l2TxNumberInBlock`: `number | null`; -- `message`: `any`; -- `sender`: `string`; -- `proof`: `string[]`; - -## `FullDepositFee` - -Interface representation of full deposit fee containing various mandatory and optional fields. - -- `maxFeePerGas?`: `BigNumber`; -- `maxPriorityFeePerGas?`: `BigNumber`; -- `gasPrice?`: `BigNumber`; -- `baseCost`: `BigNumber`; -- `l1GasLimit`: `BigNumber`; -- `l2GasLimit`: `BigNumber`; - -## `GeneralPaymasterInput` - -Interface representation of general paymaster input containing a couple of fields, including a `General` type. - -- `type`: `'General'`; -- `innerInput`: `BytesLike`; - -## `L2ToL1Log` - -Interface representation of a layer 2 to layer 1 transaction log containing various fields. - -- `blockNumber`: `number`; -- `blockHash`: `string`; -- `l1BatchNumber`: `number`; -- `transactionIndex`: `number`; -- `shardId`: `number`; -- `isService`: `boolean`; -- `sender`: `string`; -- `key`: `string`; -- `value`: `string`; -- `transactionHash`: `string`; -- `logIndex`: `number`; - -## `Log` - -Interface representation of log that extends Ethers -[`providers.Log`](https://docs.ethers.org/v5/api/providers/types/#providers-Log) and supplies the layer 1 batch number. - -- `l1BatchNumber`: `number`; - -## `MessageProof` - -Interface representation of message proof containing various fields. - -- `id`: `number`; -- `proof`: `string[]`; -- `root`: `string`; - -## `Network` - -Enumerated list of networks and their ids. - -- Mainnet = `1` -- Ropsten = `3` -- Rinkeby = `4` -- Sepolia = `6`, -- localhost = `9` - -## `PaymasterInput` - -Type definition for a paymaster input specified as either approval based or general. - -- `ApprovalBasedPaymasterInput` | `GeneralPaymasterInput` - -## `PaymasterParams` - -Type defining a paymaster by address and the bytestream input. - -- `paymaster`: `Address`; -- `paymasterInput`: `BytesLike`; - -## `PriorityOpResponse` - -Interface representation of priority op response that extends [`TransactionResponse`](#transactionresponse) and adds a -function that waits to commit a layer 1 transaction, including when given on optional confirmation number. - -- `waitL1Commit(confirmation?: number)`: `Promise`; - -## `RawBlockTransaction` - -Interface representation of raw block with transactions - -- `common_data`: - - `L2`: - - `nonce`: `number`; - - `fee`: - - `gas_limit`: `BigInt`; - - `max_fee_per_gas`: `BigInt`; - - `max_priority_fee_per_gas`: `BigInt`; - - `gas_per_pubdata_limit`: `BigInt`; - - `initiatorAddress`: `Address`; - - `signature`: `Uint8Array`; - - `transactionType`: `string`; - - `input` - - `hash`: `string`; - - `data`: `Uint8Array`; - - `paymasterParams`: - - `paymaster`: `Address`; - - `paymasterInput`: `Uint8Array`; -- `execute`: - - `calldata`: `string`; - - `contractAddress`: `Address`; - - `factoryDeps`: `BytesLike[]`; - - `value`: `BigInt`; -- `received_timestamp_ms`: `number`; -- `raw_bytes`: `string`; - -## `Signature` - -0x-prefixed, hex-encoded, ECDSA signature as string. - -## `StorageProof` - -Interace representation of Merkle proofs for storage values. - -- `address`: `string`; -- `storageProof` (Array): - - `key`: `string`; - - `value`: `string`; - - `index`: `number`; - - `proof`: `string[]`; - -## `Token` - -Interface representation of token containing various fields. - -- `l1Address`: `Address`; -- `l2Address`: `Address`; -- `address`: `Address`; // backward compatible field although @deprecated in favor of l2Address -- `name`: `string`; -- `symbol`: `string`; -- `decimals`: `number`; - -## `TransactionDetails` - -Interface representation of transaction details containing various mandatory and optional fields. - -- `isL1Originated`: `boolean`; -- `status`: `string`; -- `fee`: `BigNumberish`; -- `initiatorAddress`: `Address`; -- `receivedAt`: `Date`; -- `ethCommitTxHash?`: `string`; -- `ethProveTxHash?`: `string`; -- `ethExecuteTxHash?`: `string`; - -## `TransactionReceipt` - -Interface representation of transaction receipt that extends from Ethers -[`providers.TransactionReceipt`](https://docs.ethers.org/v5/api/providers/types/#providers-TransactionReceipt) with -additional fields. - -- `l1BatchNumber`: `number`; -- `l1BatchTxIndex`: `number`; -- `logs`: `Array`; -- `l2ToL1Logs`: `Array`; - -## `TransactionRequest` - -Interface representation of transaction request that extends from Ethers -[`providers.TransactionRequest`](https://docs.ethers.org/v5/api/providers/types/#providers-TransactionRequest) which -adds an optional field for EIP-712 transactions. - -- `customData?`: `Eip712Meta`; - -## `TransactionResponse` - -Interface representation of transaction response that extends from Ethers -[`providers.TransactionResponse`](https://docs.ethers.org/v5/api/providers/types/#providers-TransactionResponse) with -additional fields. - -- `l1BatchNumber`: `number`; -- `l1BatchTxIndex`: `number`; -- `waitFinalize()`: `Promise`; - -## `TransactionStatus` - -Non-enumerated enum list of transaction statuses. - -- NotFound = `not-found` -- Processing = `processing` -- Committed = `committed` -- Finalized = `finalized` - -:::tip More info Find the code definition of the types above on the -[zkSync Era Github repo.](https://github.com/zksync-sdk/zksync-ethers/blob/ethers-v5/src/utils.ts) ::: diff --git a/content/20.build/sdks/js/utils.md b/content/20.build/sdks/js/utils.md deleted file mode 100644 index d3f4cb2b..00000000 --- a/content/20.build/sdks/js/utils.md +++ /dev/null @@ -1,834 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: JS SDK Utilities | zkSync Docs ---- - -# Utilities - -The [utilities library](https://github.com/zksync-sdk/zksync-ethers/blob/ethers-v5/src/utils.ts) contains essential -utilities for building on zkSync Era. - -:::info - -- This document describes common functions and constants you may need. -- Functions used internally are not necessarily described. -- Check the code for the full list. ::: - -## Use the library - -Access the library by importing it into your scripts. - -```typescript -import { utils } from 'zksync-ethers'; -``` - -## Constants - -### Interfaces - -#### zkSync Era main contract - -```typescript -export const ZKSYNC_MAIN_ABI = new utils.Interface(require('../abi/IZkSync.json')); -``` - -#### IERC20 - -For interacting with native tokens. - -```typescript -export const IERC20 = new utils.Interface(require('../abi/IERC20.json')); -``` - -#### IERC1271 - -For interacting with contract which implements ERC1271. - -```ts -export const IERC1271 = new utils.Interface(require('../abi/IERC1271.json')); -``` - -#### Contract deployer - -Used for deploying smart contracts. - -```ts -export const CONTRACT_DEPLOYER = new utils.Interface(require('../abi/ContractDeployer.json')); -``` - -#### L1 messenger - -Used for sending messages from zkSync Era to Ethereum. - -```ts -export const L1_MESSENGER = new utils.Interface(require('../abi/IL1Messenger.json')); -``` - -#### L1 and L2 bridges - -Bridge interface ABIs for L1 and L2. - -```ts -export const L1_BRIDGE_ABI = new utils.Interface(require('../abi/IL1Bridge.json')); -export const L2_BRIDGE_ABI = new utils.Interface(require('../abi/IL2Bridge.json')); -``` - -#### NonceHolder - -Used for managing deployment nonce. - -```ts -export const NONCE_HOLDER_ABI = new ethers.Interface(require('../abi/INonceHolder.json')); -``` - -#### L1 to L2 alias offset - -Used for applying and undoing aliases on addresses during bridging from L1 to L2. - -```ts -export const L1_TO_L2_ALIAS_OFFSET = '0x1111000000000000000000000000000000001111'; -``` - -#### Magic value - -The value returned from `isEIP1271SignatureCorrect` to confirm signature correctness. - -```ts -export const EIP1271_MAGIC_VALUE = '0x1626ba7e'; -``` - -#### EIP712 transaction type - -Constant representing an EIP712 transaction type. - -```ts -export const EIP712_TX_TYPE = 0x71; -``` - -#### EIP712 structures - -Collection of EIP712 structures with their types. - -```ts -export const EIP712_TYPES = { - Transaction: [ - { name: 'txType', type: 'uint256' }, - { name: 'from', type: 'uint256' }, - { name: 'to', type: 'uint256' }, - { name: 'gasLimit', type: 'uint256' }, - { name: 'gasPerPubdataByteLimit', type: 'uint256' }, - { name: 'maxFeePerGas', type: 'uint256' }, - { name: 'maxPriorityFeePerGas', type: 'uint256' }, - { name: 'paymaster', type: 'uint256' }, - { name: 'nonce', type: 'uint256' }, - { name: 'value', type: 'uint256' }, - { name: 'data', type: 'bytes' }, - { name: 'factoryDeps', type: 'bytes32[]' }, - { name: 'paymasterInput', type: 'bytes' }, - ], -}; -``` - -#### Priority op transaction on L2 - -Constant representing a priority transaction operation on L2. - -```ts -export const PRIORITY_OPERATION_L2_TX_TYPE = 0xff; -``` - -#### Max bytecode length - -Used for ensuring bytecode length is not over the maximum allowed. - -```ts -export const MAX_BYTECODE_LEN_BYTES = ((1 << 16) - 1) * 32; -``` - -### Useful addresses - -#### ETH token layer 1 - -```typescript -export const ETH_ADDRESS = '0x0000000000000000000000000000000000000000'; -``` - -#### ETH token alias on ZkSync Era - -```typescript -export const L2_ETH_TOKEN_ADDRESS = '0x000000000000000000000000000000000000800a'; -``` - -#### Bootloader - -```ts -export const BOOTLOADER_FORMAL_ADDRESS = '0x0000000000000000000000000000000000008001'; -``` - -#### Contract deployer - -```ts -export const CONTRACT_DEPLOYER_ADDRESS = '0x0000000000000000000000000000000000008006'; -``` - -#### L1 messenger - -```ts -export const L1_MESSENGER_ADDRESS = '0x0000000000000000000000000000000000008008'; -``` - -#### Nonce holder - -```ts -export const NONCE_HOLDER_ADDRESS = '0x0000000000000000000000000000000000008003'; -``` - -### Gas - -#### `DEFAULT_GAS_PER_PUBDATA_LIMIT` - -- Use a large amount of gas per pubdata for signing on layer 2. -- The amount ensures any reasonable limit is accepted. - -:::info - -- The operator is NOT required to use the actual value and can use any value up to that signed by the user. ::: - -```typescript -export const DEFAULT_GAS_PER_PUBDATA_LIMIT = 50000; -``` - -#### `REQUIRED_L1_TO_L2_GAS_PER_PUBDATA_LIMIT` - -The current required gas per pubdata for L1->L2 transactions. - -```ts -export const REQUIRED_L1_TO_L2_GAS_PER_PUBDATA_LIMIT = 800; -``` - -## Functions - -### `applyL1ToL2Alias` - -Converts the address that submitted a transaction to the inbox on L1 to the `msg.sender` viewed on L2. - -Returns the `msg.sender` of the L1->L2 transaction as the `address` of the contract that initiated the transaction. - -:::tip More info - -1. During a normal transaction, if contract A calls contract B, the `msg.sender` is A. -2. During L1->L2 communication, if an EOA X calls contract B, the `msg.sender` is X. -3. During L1->L2 communication, if a contract A calls contract B, the `msg.sender` is `applyL1ToL2Alias(A)`. ::: - -#### Inputs - -| Parameter | Type | Description | -| --------- | ------ | ----------------- | -| `address` | string | Contract address. | - -```ts -export function applyL1ToL2Alias(address: string): string; -``` - -#### Example - -```ts -const l1ContractAddress = '0x702942B8205E5dEdCD3374E5f4419843adA76Eeb'; -const l2ContractAddress = utils.applyL1ToL2Alias(l1ContractAddress); -// l2ContractAddress = "0x813A42B8205E5DedCd3374e5f4419843ADa77FFC" -``` - -See also [`undol1tol2alias`](#undol1tol2alias). - -### `checkBaseCost` - -Checks if the transaction's base cost is greater than the provided value, which covers the transaction's cost. Throws an -error if it is not. - -#### Inputs - -| Parameter | Type | Description | -| ---------- | -------------- | ------------------------------------------ | -| `baseCost` | `BigNumberish` | transaction's base cost. | -| `value` | `BigNumberish` | value which covers the transaction's cost. | - -```ts -async function checkBaseCost( - baseCost: ethers.BigNumberish, - value: ethers.BigNumberish | Promise -): Promise; -``` - -### Example - -```ts -const baseCost = 100; -const value = 99; -try { - await utils.checkBaseCost(baseCost, value); -} catch (e) { - // e.message = `The base cost of performing the priority operation is higher than the provided value parameter for the transaction: baseCost: ${baseCost}, provided value: ${value}`, -} -``` - -### `create2Address` - -Generates a future-proof contract address using salt plus bytecode which allows determination of an address before -deployment. - -:::warning - -- The zkSync Era implementation is slightly different from Ethereum. ::: - -#### Inputs - -| Parameter | Type | Description | -| -------------- | ----------- | ---------------------------------- | -| `sender` | `Address` | Sender address. | -| `bytecodeHash` | `BytesLike` | Output from zkSolc. | -| `salt` | `BytesLike` | Randomization element. | -| `input` | `BytesLike` | ABI encoded constructor arguments. | - -```ts -export function create2Address(sender: Address, bytecodeHash: BytesLike, salt: BytesLike, input: BytesLike): string; -``` - -#### Example - -```ts -const address = utils.create2Address( - '0x36615Cf349d7F6344891B1e7CA7C72883F5dc049', - '0x010001cb6a6e8d5f6829522f19fa9568660e0a9cd53b2e8be4deb0a679452e41', - '0x01', - '0x01' -); -// address = "0x29bac3E5E8FFE7415F97C956BFA106D70316ad50" -``` - -:::tip The `prefix` is equal to `keccak256("zksyncCreate")`. ::: - -### `createAddress` - -Generates a contract address from deployer's account and nonce. - -#### Inputs - -| Parameter | Type | Description | -| ------------- | -------------- | --------------- | -| `sender` | `Address` | Sender address. | -| `senderNonce` | `BigNumberish` | Sender nonce. | - -```ts -export function createAddress(sender: Address, senderNonce: BigNumberish): string; -``` - -#### Example - -```ts -const address = utils.createAddress('0x36615Cf349d7F6344891B1e7CA7C72883F5dc049', 1); -// address = "0x4B5DF730c2e6b28E17013A1485E5d9BC41Efe021" -``` - -### `eip712TxHash` - -Returns the hash of an EIP712 transaction. - -#### Inputs - -| Parameter | Type | Description | -| --------------- | --------------------------------------------------- | ---------------------------------------------- | -| `transaction` | `any` | EIP-712 transaction. | -| `ethSignature?` | [`EthereumSignature`](./types.md#ethereumsignature) | ECDSA signature of the transaction (optional). | - -```ts -function eip712TxHash(transaction: any, ethSignature?: EthereumSignature): string; -``` - -### `estimateDefaultBridgeDepositL2Gas` - -Returns an estimation of L2 gas required for token bridging via the default ERC20 bridge. - -::: tip More info - -- See the [default bridges documentation](../../developer-reference/bridging-asset.md#default-bridges) ::: - -#### Inputs - -| Parameter | Type | Description | -| -------------------- | -------------- | ------------------------------------------- | -| `providerL1` | `Provider` | Ethers provider. | -| `providerL2` | `Provider` | zkSync provider. | -| `token` | `Address` | Token address. | -| `amount` | `BigNumberish` | Deposit amount. | -| `to` | `Address` | Recipient address. | -| `from?` | `Address` | Sender address (optional). | -| `gasPerPubdataByte?` | `BigNumberish` | Current gas per byte of pubdata (optional). | - -```ts -export async function estimateDefaultBridgeDepositL2Gas( - providerL1: ethers.providers.Provider, - providerL2: Provider, - token: Address, - amount: BigNumberish, - to: Address, - from?: Address, - gasPerPubdataByte?: BigNumberish -): Promise; -``` - -### `getDeployedContracts` - -Returns a log containing details of all deployed contracts related to a transaction receipt parameter. - -#### Inputs - -| Parameter | Type | Description | -| --------- | ----------------------------------------------------- | -------------------- | -| `receipt` | [`TransactionReceipt`](./types.md#transactionreceipt) | Transaction receipt. | - -```ts -export function getDeployedContracts(receipt: ethers.providers.TransactionReceipt): DeploymentInfo[]; -``` - -### `getERC20BridgeCalldata` - -Returns the calldata sent by an L1 ERC20 bridge to its L2 counterpart during token-bridging. - -#### Inputs - -| Parameter | Type | Description | -| ---------------- | -------------- | ------------------------------------------- | -| `l1TokenAddress` | `Address` | Token address on L1. | -| `l1Sender` | `Address` | Sender address on L1. | -| `l2Receiver` | `Address` | Recipient address on L2. | -| `amount` | `BigNumberish` | Gas fee for the number of tokens to bridge. | -| `bridgeData` | `BytesLike` | Data | - -```ts -export async function getERC20BridgeCalldata( - l1TokenAddress: string, - l1Sender: string, - l2Receiver: string, - amount: BigNumberish, - bridgeData: BytesLike -): Promise; -``` - -### `getL2HashFromPriorityOp` - -Returns the hash of the L2 priority operation from a given transaction receipt and L2 address. - -#### Inputs - -| Parameter | Type | Description | -| --------------- | ----------------------------------------------------- | ------------------------------------ | -| `txReceipt` | [`TransactionReceipt`](./types.md#transactionreceipt) | Receipt of the L1 transaction. | -| `zkSyncAddress` | `Address` | Address of zkSync Era main contract. | - -```ts -export function getL2HashFromPriorityOp(txReceipt: ethers.providers.TransactionReceipt, zkSyncAddress: Address): string; -``` - -### `getHashedL2ToL1Msg` - -Returns a keccak encoded message with a given sender address and block number from the L1 messenger contract. - -#### Inputs - -| Parameter | Type | Description | -| ----------------- | ----------- | -------------------------------------- | -| `sender` | `Address` | The sender of the message on L2. | -| `msg` | `BytesLike` | Encoded message. | -| `txNumberInBlock` | number | Index of the transaction in the block. | - -```ts -export function getHashedL2ToL1Msg(sender: Address, msg: BytesLike, txNumberInBlock: number): string; -``` - -#### Example - -```ts -const withdrawETHMessage = - '0x6c0960f936615cf349d7f6344891b1e7ca7c72883f5dc04900000000000000000000000000000000000000000000000000000001a13b8600'; -const withdrawETHMessageHash = utils.getHashedL2ToL1Msg( - '0x36615Cf349d7F6344891B1e7CA7C72883F5dc049', - withdrawETHMessage, - 0 -); -// withdrawETHMessageHash = "0xd8c80ecb64619e343f57c3b133c6c6d8dd0572dd3488f1ca3276c5b7fd3a938d" -``` - -### `hashBytecode` - -Returns the hash of given bytecode. - -#### Inputs - -| Parameter | Type | Description | -| ---------- | ----------- | ----------- | -| `bytecode` | `BytesLike` | Bytecode. | - -```ts -export function hashBytecode(bytecode: ethers.BytesLike): Uint8Array; -``` - -#### Examples - -```ts -const bytecode = - '0x000200000000000200010000000103550000006001100270000000130010019d0000008001000039000000400010043f0000000101200190000000290000c13d0000000001000031000000040110008c000000420000413d0000000101000367000000000101043b000000e001100270000000150210009c000000310000613d000000160110009c000000420000c13d0000000001000416000000000110004c000000420000c13d000000040100008a00000000011000310000001702000041000000200310008c000000000300001900000000030240190000001701100197000000000410004c000000000200a019000000170110009c00000000010300190000000001026019000000000110004c000000420000c13d00000004010000390000000101100367000000000101043b000000000010041b0000000001000019000000490001042e0000000001000416000000000110004c000000420000c13d0000002001000039000001000010044300000120000004430000001401000041000000490001042e0000000001000416000000000110004c000000420000c13d000000040100008a00000000011000310000001702000041000000000310004c000000000300001900000000030240190000001701100197000000000410004c000000000200a019000000170110009c00000000010300190000000001026019000000000110004c000000440000613d00000000010000190000004a00010430000000000100041a000000800010043f0000001801000041000000490001042e0000004800000432000000490001042e0000004a00010430000000000000000000000000000000000000000000000000000000000000000000000000ffffffff0000000200000000000000000000000000000040000001000000000000000000000000000000000000000000000000000000000000000000000000006d4ce63c0000000000000000000000000000000000000000000000000000000060fe47b18000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000080000000000000000000000000000000000000000000000000000000000000000000000000000000009c8c8fa789967eb514f3ec9def748480945cc9b10fcbd1a19597d924eb201083'; -const hashedBytecode = utils.hashBytecode(bytecode); -/* -hashedBytecode = new Uint8Array([ - 1, 0, 0, 27, 57, 231, 154, 55, 0, 164, 201, 96, 244, 120, 23, 112, 54, 34, 224, 133, - 160, 122, 88, 164, 112, 80, 0, 134, 48, 138, 74, 16, - ]), -); - */ -``` - -### `isECDSASignatureCorrect` - -Validates signatures from non-contract account addresses (EOA). Provides similar functionality in `ethers.js` but -returns `true` if the validation process succeeds, otherwise returns `false`. - -Called from [`isSignatureCorrect`](#isSignatureCorrect) for non-contract account addresses. - -#### Inputs - -| Parameter | Type | Description | -| ----------- | --------------- | ------------------------------ | -| `address` | `string` | Address which signs `msgHash`. | -| `msgHash` | `Address` | Hash of the message. | -| `signature` | `SignatureLike` | Ethers signature. | - -```ts -function isECDSASignatureCorrect(address: string, msgHash: string, signature: SignatureLike): boolean; -``` - -#### Examples - -```ts -import { Wallet, utils } from 'zksync-ethers'; - -const ADDRESS = ''; -const PRIVATE_KEY = ''; - -const message = 'Hello, world!'; -const signature = await new Wallet(PRIVATE_KEY).signMessage(message); -// ethers.Wallet can be used as well -// const signature = await new ethers.Wallet(PRIVATE_KEY).signMessage(message); - -const isValidSignature = await utils.isECDSASignatureCorrect(ADDRESS, message, signature); -// isValidSignature = true -``` - -See also [`isMessageSignatureCorrect()`](#ismessagesignaturecorrect) and -[`isTypedDataSignatureCorrect()`](#istypeddatasignaturecorrect) to validate signatures. - -### `isEIP1271SignatureCorrect` - -Called from [`isSignatureCorrect`](#isSignatureCorrect) for contract account addresses, the function returns true if the -validation process results in the `EIP1271_MAGIC_VALUE`. - -#### Inputs - -| Parameter | Type | Description | -| ----------- | --------------- | ------------------------ | -| `provider` | `Provider` | Provider. | -| `address` | `string` | Sender address. | -| `msgHash` | `string` | The hash of the message. | -| `signature` | `SignatureLike` | Ethers signature. | - -```ts -async function isEIP1271SignatureCorrect( - provider: Provider, - address: string, - msgHash: string, - signature: SignatureLike -): Promise; -``` - -See also [`isMessageSignatureCorrect()`](#ismessagesignaturecorrect) and -[`isTypedDataSignatureCorrect()`](#istypeddatasignaturecorrect) to validate signatures. - -### `isETH` - -Returns true if token represents ETH on L1 or L2. - -#### Inputs - -| Parameter | Type | Description | -| --------- | --------- | ------------------ | -| `token` | `Address` | The token address. | - -```ts -export function isETH(token: Address); -``` - -#### Example - -```ts -const isL1ETH = utils.isETH(utils.ETH_ADDRESS); // true -const isL2ETH = utils.isETH(utils.L2_ETH_TOKEN_ADDRESS); // true -``` - -### `isMessageSignatureCorrect` - -Returns true if account abstraction signature is correct. - -#### Inputs - -| Parameter | Type | Description | -| ----------- | --------------- | ------------------------ | -| `provider` | `Provider` | Provider. | -| `address` | `string` | Sender address. | -| `message` | `string` | The hash of the message. | -| `signature` | `SignatureLike` | Ethers signature. | - -```ts -export async function isMessageSignatureCorrect( - provider: Provider, - address: string, - message: ethers.Bytes | string, - signature: SignatureLike -): Promise; -``` - -#### Example - -```ts -import { Wallet, utils, Provider } from 'zksync-ethers'; - -const ADDRESS = ''; -const PRIVATE_KEY = ''; -const provider = Provider.getDefaultProvider(types.Network.Sepolia); - -const message = 'Hello, world!'; -const signature = await new Wallet(PRIVATE_KEY).signMessage(message); -// ethers.Wallet can be used as well -// const signature = await new ethers.Wallet(PRIVATE_KEY).signMessage(message); - -const isValidSignature = await utils.isMessageSignatureCorrect(provider, ADDRESS, message, signature); -// isValidSignature = true -``` - -### `isSignatureCorrect` - -Called from [`isMessageSignatureCorrect`](#ismessagesignaturecorrect) and -[`isTypedDataSignatureCorrect`](#istypeddatasignaturecorrect). Returns true if account abstraction EIP712 signature is -correct. - -#### Inputs - -| Parameter | Type | Description | -| ----------- | --------------- | ------------------------ | -| `provider` | `Provider` | Provider. | -| `address` | `string` | Sender address. | -| `msgHash` | `string` | The hash of the message. | -| `signature` | `SignatureLike` | Ethers signature. | - -```ts -async function isSignatureCorrect( - provider: Provider, - address: string, - msgHash: string, - signature: SignatureLike -): Promise; -``` - -### `isTypedDataSignatureCorrect` - -Returns true if account abstraction EIP712 signature is correct. - -#### Inputs - -| Parameter | Type | Description | -| ----------- | ----------------------------- | ------------------------------------------------------ | -| `provider` | `Provider` | Provider. | -| `address` | `string` | Sender address. | -| `domain` | `TypedDataDomain` | Domain data. | -| `types` | `Map` | Map of records pointing from field name to field type. | -| `value` | `Record` | A single record value. | -| `signature` | `SignatureLike` | Ethers signature. | - -```ts -export async function isTypedDataSignatureCorrect( - provider: Provider, - address: string, - domain: TypedDataDomain, - types: Record>, - value: Record, - signature: SignatureLike -): Promise; -``` - -#### Example - -```ts -import { Wallet, utils, Provider, EIP712Signer } from 'zksync-ethers'; - -const ADDRESS = ''; -const PRIVATE_KEY = ''; -const provider = Provider.getDefaultProvider(types.Network.Sepolia); - -const tx: types.TransactionRequest = { - type: 113, - chainId: 270, - from: ADDRESS, - to: '0xa61464658AfeAf65CccaaFD3a512b69A83B77618', - value: BigInt(7_000_000), -}; - -const eip712Signer = new EIP712Signer( - new Wallet(PRIVATE_KEY), // or new ethers.Wallet(PRIVATE_KEY), - Number((await provider.getNetwork()).chainId) -); - -const signature = await eip712Signer.sign(tx); - -const isValidSignature = await utils.isTypedDataSignatureCorrect( - provider, - ADDRESS, - await eip712Signer.getDomain(), - utils.EIP712_TYPES, - EIP712Signer.getSignInput(tx), - signature -); -// isValidSignature = true -``` - -### `parseTransaction` - -Parses an EIP712 transaction from a payload. - -#### Inputs - -| Parameter | Type | Description | -| --------- | ----------- | ----------- | -| `payload` | `BytesLike` | Payload. | - -```ts -export function parseTransaction(payload: ethers.BytesLike): ethers.Transaction; -``` - -### Example - -```ts -import { types } from 'zksync-ethers'; - -const serializedTx = - '0x71f87f8080808094a61464658afeaf65cccaafd3a512b69a83b77618830f42408001a073a20167b8d23b610b058c05368174495adf7da3a4ed4a57eb6dbdeb1fafc24aa02f87530d663a0d061f69bb564d2c6fb46ae5ae776bbd4bd2a2a4478b9cd1b42a82010e9436615cf349d7f6344891b1e7ca7c72883f5dc04982c350c080c0'; -const tx: types.TransactionLike = utils.parseEip712(serializedTx); -/* -tx = { - type: 113, - nonce: 0, - maxPriorityFeePerGas: BigNumber.from(0), - maxFeePerGas: BigNumber.from(0), - gasLimit: BigNumber.from(0), - to: "0xa61464658AfeAf65CccaaFD3a512b69A83B77618", - value: BigNumber.from(1000000), - data: "0x", - chainId: BigNumber.from(270), - from: "0x36615Cf349d7F6344891B1e7CA7C72883F5dc049", - customData: { - gasPerPubdata: BigNumber.from(50000), - factoryDeps: [], - customSignature: "0x", - paymasterParams: null, - }, - hash: "0x9ed410ce33179ac1ff6b721060605afc72d64febfe0c08cacab5a246602131ee", -}; - */ -``` - -### `serialize` - -Serializes an EIP712 transaction and include a signature if is provided. Throws an error if: - -- `transaction.customData.customSignature` is an empty `string`. The transaction should be signed and the - `transaction.customData.customSignature` field should be populated with the signature. It should not be specified if - the transaction is not signed. -- `transaction.chainId` is not provided. -- `transaction.from` is not provided. - -#### Inputs - -| Parameter | Type | Description | -| ------------- | -------------------- | ---------------------------------------------------------------------- | -| `transaction` | `TransactionRequest` | Transaction that needs to be serialized. | -| `signature?` | `SignatureLike` | Ethers signature that needs to be included in transactions (optional). | - -```ts -export function serialize(transaction: ethers.providers.TransactionRequest, signature?: SignatureLike); -``` - -#### Examples - -Serialize EIP712 transaction without signature. - -```ts -const serializedTx = utils.serializeEip712({ chainId: 270, from: '0x36615Cf349d7F6344891B1e7CA7C72883F5dc049' }, null); - -// serializedTx = "0x71ea8080808080808082010e808082010e9436615cf349d7f6344891b1e7ca7c72883f5dc04982c350c080c0" -``` - -Serialize EIP712 transaction with signature. - -```ts -const signature = ethers.Signature.from( - '0x73a20167b8d23b610b058c05368174495adf7da3a4ed4a57eb6dbdeb1fafc24aaf87530d663a0d061f69bb564d2c6fb46ae5ae776bbd4bd2a2a4478b9cd1b42a' -); - -const serializedTx = utils.serializeEip712( - { - chainId: 270, - from: '0x36615Cf349d7F6344891B1e7CA7C72883F5dc049', - to: '0xa61464658AfeAf65CccaaFD3a512b69A83B77618', - value: 1_000_000, - }, - signature -); -// serializedTx = "0x71f87f8080808094a61464658afeaf65cccaafd3a512b69a83b77618830f42408001a073a20167b8d23b610b058c05368174495adf7da3a4ed4a57eb6dbdeb1fafc24aa02f87530d663a0d061f69bb564d2c6fb46ae5ae776bbd4bd2a2a4478b9cd1b42a82010e9436615cf349d7f6344891b1e7ca7c72883f5dc04982c350c080c0" -``` - -### `sleep` - -Common sleep function that pauses execution for a number of milliseconds. - -#### Inputs - -| Parameter | Type | Description | -| --------- | ------ | ----------------------- | -| `millis` | number | Number of milliseconds. | - -```ts -export function sleep(millis: number); -``` - -### `undoL1ToL2Alias` - -Converts and returns the `msg.sender` viewed on L2 to the address that submitted a transaction to the inbox on L1. - -#### Inputs - -| Parameter | Type | Description | -| --------- | ------ | --------------- | -| `address` | string | Sender address. | - -```ts -export function undoL1ToL2Alias(address: string): string; -``` - -#### Example - -```ts -const l2ContractAddress = '0x813A42B8205E5DedCd3374e5f4419843ADa77FFC'; -const l1ContractAddress = utils.undoL1ToL2Alias(l2ContractAddress); -// const l1ContractAddress = "0x702942B8205E5dEdCD3374E5f4419843adA76Eeb" -``` - -See also [`applyl1tol2alias`](#applyl1tol2alias). diff --git a/content/20.build/sdks/js/zksync-ethers/accounts-l1-l2.md b/content/20.build/sdks/js/zksync-ethers/accounts-l1-l2.md deleted file mode 100644 index 435bba41..00000000 --- a/content/20.build/sdks/js/zksync-ethers/accounts-l1-l2.md +++ /dev/null @@ -1,52 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: JS SDK L1/L2 Transactions | zkSync Docs ---- - -# Accounts: L1<->L2 Transactions - -This section explores the methods which allow the [account](./accounts.md) to send transactions among both L1 to L2 -networks. - -If you want some background on how L1<->L2 interaction works on zkSync, go through the -[introduction](../../../developer-reference/l1-l2-interop.md). - -Full examples of actions below are available on the [getting started](./getting-started.md) page. - -## Deposit - -`Wallet` and `L1Signer` objects provide a deposit workflow. For more information, please refer to the method -specification [`Deposit`](accounts.md#deposit). - -For a complete example of how to execute the deposit workflow, take a look at the following: -[Deposit ETH and ERC20 token](https://github.com/zksync-sdk/zksync2-examples/blob/main/js/src/01_deposit.ts). - -## Request execute - -`Wallet` and `L1Signer` objects provide an option to request execution of L2 transaction from L1. For more information, -please refer to the method specification [`requestExecute`](accounts.md#requestexecute). - -## Base cost - -`Wallet` and `L1Signer` objects provide an option to calculate base cost for L2 transaction. For more information, -please refer to the method specification [`getBaseCost`](accounts.md#getbasecost). - -## Claim failed deposit - -`Wallet` and `L1Signer` objects provide a claim fail deposit workflow. For more information, please refer to the method -specification [`claimFailedDeposit`](accounts.md#claimfaileddeposit). - -## Finalize withdraw - -`Wallet` and `L1Signer` objects provide a finalize withdraw workflow. For more information, please refer to the method -specification [`finalizeWithdrawal`](accounts.md#finalizewithdrawal). - -## Withdrawal - -`Wallet` and `Signer` objects provide a withdrawal workflow. For more information, please refer to the method -specification [`Deposit`](accounts.md#deposit). - -For a complete example of how to execute the deposit workflow, take a look at the following: -[Withdraw ETH and ERC20 token](https://github.com/zksync-sdk/zksync2-examples/blob/main/js/src/03_withdraw.ts). diff --git a/content/20.build/sdks/js/zksync-ethers/accounts.md b/content/20.build/sdks/js/zksync-ethers/accounts.md deleted file mode 100644 index 8ec975da..00000000 --- a/content/20.build/sdks/js/zksync-ethers/accounts.md +++ /dev/null @@ -1,2552 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: JS SDK Accounts | zkSync Docs ---- - -# Accounts - -## Overview - -`zksync-ethers` exports following classes that can sign transactions on zkSync: - -- `Wallet` class is an extension of the `ethers.Wallet` with additional zkSync features. -- `EIP712Signer` class that is used to sign `EIP712`_-typed_ zkSync transactions. -- `Signer` and `L1Signer` classes, which should be used for browser integration. - -## `Wallet` - -### `constructor` - -#### Inputs - -| Parameter | Type | Description | -| ------------- | ------------------------------------------------------------------------------------ | ---------------------------------------------------------------------- | -| `privateKey` | `string` or [`ethers.SigningKey`](https://docs.ethers.org/v6/api/crypto/#SigningKey) | The private key of the Ethereum account. | -| `providerL2?` | [`Provider`](./providers.md#provider) | A zkSync node provider. Needed for interaction with zkSync (optional). | -| `providerL1?` | [`ethers.Provider`](https://docs.ethers.org/v6/api/providers/#Provider) | An Ethereum node provider. Needed for interaction with L1 (optional). | - -```ts -constructor(privateKey: string | ethers.SigningKey, providerL2?: Provider, providerL1?: ethers.Provider) -``` - -#### Example - -```ts -import { Wallet, Provider, utils } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const PRIVATE_KEY = ''; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const ethProvider = ethers.getDefaultProvider('sepolia'); -const wallet = new Wallet(PRIVATE_KEY, provider, ethProvider); -``` - -### `fromMnemonic` - -Creates a `Wallet` with the `provider` as L1 provider and a private key that is built from the `mnemonic` passphrase. - -#### Inputs - -| Parameter | Type | Description | -| ----------- | ----------------------------------------------------------------------- | --------------------------------------------------------------------- | -| `mnemonic` | `string` | The mnemonic of the private key. | -| `provider?` | [`ethers.Provider`](https://docs.ethers.org/v6/api/providers/#Provider) | An Ethereum node provider. Needed for interaction with L1 (optional). | - -```ts -static fromMnemonic(mnemonic: string, provider?: ethers.Provider): Wallet -``` - -#### Example - -```ts -import { Wallet, Provider, utils } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const MNEMONIC = 'stuff slice staff easily soup parent arm payment cotton hammer scatter struggle'; - -const ethProvider = ethers.getDefaultProvider('sepolia'); -const wallet = Wallet.fromMnemonic(MNEMONIC, ethProvider); -``` - -### `fromEncryptedJson` - -Creates a `Wallet` from encrypted `json` file using provided `password`. - -#### Inputs - -| Parameter | Type | Description | -| ----------- | ------------------------ | -------------------------------------------------------------------------------------------------------------- | -| `json` | `string` | Encrypted json file. | -| `password` | `string` or `Uint8Array` | Password for encrypted json file. | -| `callback?` | `ProgressCallback` | If callback is provided, it is called periodically during decryption so that any UI can be updated (optional). | - -```ts -static async fromEncryptedJson(json: string, password: string | Uint8Array, callback? : ProgressCallback): Promise -``` - -#### Example - -```ts -import { Wallet, Provider, utils } from 'zksync-ethers'; -import * as fs from 'fs'; - -const wallet = await Wallet.fromEncryptedJson(fs.readFileSync('wallet.json', 'utf8'), 'password'); -``` - -### `fromEncryptedJsonSync` - -Creates a `Wallet` from encrypted `json` file using provided `password`. - -#### Inputs - -| Parameter | Type | Description | -| ---------- | ------------------------ | --------------------------------- | -| `json` | `string` | Encrypted json file. | -| `password` | `string` or `Uint8Array` | Password for encrypted json file. | - -```ts -static fromEncryptedJsonSync(json: string, password: string | Uint8Array): Wallet -``` - -#### Example - -```ts -import { Wallet } from 'zksync-ethers'; -import * as fs from 'fs'; - -const wallet = Wallet.fromEncryptedJsonSync(fs.readFileSync('tests/files/wallet.json', 'utf8'), 'password'); -``` - -### `connect` - -To interact with the zkSync network, the `Wallet` object should be connected to a `Provider` by either passing it to the -constructor or with the `connect` method. - -#### Inputs - -| Parameter | Type | Description | -| ---------- | ------------------------------------- | ----------------------- | -| `provider` | [`Provider`](./providers.md#provider) | A zkSync node provider. | - -```ts -Wallet.connect(provider:Provider): Wallet -``` - -#### Example - -```ts -import { Wallet, Provider, types } from 'zksync-ethers'; - -const PRIVATE_KEY = ''; -const unconnectedWallet = new Wallet(PRIVATE_KEY); - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const wallet = unconnectedWallet.connect(provider); -``` - -It is possible to chain `connect` and `connectToL1` methods: - -```ts -const wallet = unconnectedWallet.connect(zkSyncProvider).connectToL1(ethProvider); -``` - -### `connectToL1` - -To perform L1 operations, the `Wallet` object needs to be connected to an `ethers.Provider` object. - -#### Inputs - -| Parameter | Type | Description | -| ---------- | ----------------------------------------------------------------------- | -------------------------- | -| `provider` | [`ethers.Provider`](https://docs.ethers.org/v6/api/providers/#Provider) | An Ethereum node provider. | - -```ts -Wallet.connectToL1(provider: ethers.Provider): Wallet -``` - -#### Example - -```ts -import { Wallet } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const PRIVATE_KEY = ''; -const unconnectedWallet = new Wallet(PRIVATE_KEY); - -const ethProvider = ethers.getDefaultProvider('sepolia'); -const wallet = unconnectedWallet.connectToL1(ethProvider); -``` - -It is possible to chain `connect` and `connectToL1` methods: - -```ts -const wallet = unconnectedWallet.connect(zkSyncProvider).connectToL1(ethProvider); -``` - -### `getMainContract` - -Returns `Contract` wrapper of the zkSync smart contract. - -```ts -async getMainContract(): Promise -``` - -#### Example - -```ts -import { Wallet, Provider, utils } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const PRIVATE_KEY = ''; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const ethProvider = ethers.getDefaultProvider('sepolia'); -const wallet = new Wallet(PRIVATE_KEY, provider, ethProvider); - -console.log(`Main contract: ${await wallet.getMainContract()}`); -``` - -### `getL1BridgeContracts` - -Returns L1 bridge contracts. - -```ts -async getL1BridgeContracts(): Promise<{ erc20: IL1Bridge; weth: IL1Bridge }> -``` - -:::note - -There is no separate Ether bridge contract, [Main contract](./accounts.md#getmaincontract) is used instead. - -::: - -#### Example - -```ts -import { Wallet, Provider, utils } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const PRIVATE_KEY = ''; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const ethProvider = ethers.getDefaultProvider('sepolia'); -const wallet = new Wallet(PRIVATE_KEY, provider, ethProvider); - -const l1BridgeContracts = await wallet.getL1BridgeContracts(); -``` - -### `getL2BridgeContracts` - -Returns L2 bridge contracts. - -```ts -async getL2BridgeContracts(): Promise<{ erc20: IL2Bridge; weth: IL2Bridge }> -``` - -#### Example - -```ts -import { Wallet, Provider, utils } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const PRIVATE_KEY = ''; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const ethProvider = ethers.getDefaultProvider('sepolia'); -const wallet = new Wallet(PRIVATE_KEY, provider, ethProvider); - -const l2BridgeContracts = await wallet.getL2BridgeContracts(); -``` - -### `getAddress` - -Returns the wallet address. - -```ts -async getAddress(): Promise
; -``` - -### Example - -```ts -import { Wallet, Provider, utils } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const PRIVATE_KEY = ''; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const ethProvider = ethers.getDefaultProvider('sepolia'); -const wallet = new Wallet(PRIVATE_KEY, provider, ethProvider); - -console.log(`Address: ${await wallet.getAddress()}`); -``` - -### `getBalance` - -Returns the amount of the token the `Wallet` has. - -#### Inputs - -| Parameter | Type | Description | -| ---------- | ---------- | ---------------------------------------------------------------------------------------------------------------- | -| `token?` | `Address` | The address of the token. ETH by default (optional). | -| `blockTag` | `BlockTag` | In which block a balance should be checked on. `committed`, i.e. the latest processed one is the default option. | - -```ts -async getBalance(token?: Address, blockTag: BlockTag = 'committed'): Promise -``` - -#### Example - -```ts -import { Wallet, Provider, utils } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const PRIVATE_KEY = ''; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const ethProvider = ethers.getDefaultProvider('sepolia'); -const wallet = new Wallet(PRIVATE_KEY, provider, ethProvider); - -const tokenL2 = '0x6a4Fb925583F7D4dF82de62d98107468aE846FD1'; - -console.log(`Token balance: ${await wallet.getBalance(tokenL2)}`); -``` - -### `getBalanceL1` - -Returns the amount of the token the `Wallet` has on Ethereum. - -#### Inputs - -| Parameter | Type | Description | -| ----------- | ---------- | --------------------------------------------------------------------------------------------------------------------------- | -| `token?` | `Address` | The address of the token. ETH by default (optional). | -| `blockTag?` | `BlockTag` | In which block a balance should be checked on. `committed`, i.e. the latest processed one is the default option (optional). | - -```ts -async getBalanceL1(token?: Address, blockTag?: BlockTag): Promise -``` - -#### Example - -```ts -import { Wallet, Provider, utils } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const PRIVATE_KEY = ''; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const ethProvider = ethers.getDefaultProvider('sepolia'); -const wallet = new Wallet(PRIVATE_KEY, provider, ethProvider); - -const tokenL1 = '0x56E69Fa1BB0d1402c89E3A4E3417882DeA6B14Be'; - -console.log(`Token balance: ${await wallet.getBalanceL1(tokenL1)}`); -``` - -### `getAllBalances` - -Returns all balances for confirmed tokens given by an account address. - -```ts -async getAllBalances(): Promise -``` - -#### Example - -```ts -import { Wallet, Provider, utils } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const PRIVATE_KEY = ''; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const ethProvider = ethers.getDefaultProvider('sepolia'); -const wallet = new Wallet(PRIVATE_KEY, provider, ethProvider); - -const allBalances = await wallet.getAllBalances(); -``` - -### `getNonce` - -Returns account's nonce number. - -#### Inputs - -| Parameter | Type | Description | -| ----------- | ---------- | --------------------------------------------------------------------------------------------------------------------------- | -| `blockTag?` | `BlockTag` | In which block a balance should be checked on. `committed`, i.e. the latest processed one is the default option (optional). | - -```ts -async getNonce(blockTag?: BlockTag): Promise -``` - -#### Example - -```ts -import { Wallet, Provider, utils } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const PRIVATE_KEY = ''; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const ethProvider = ethers.getDefaultProvider('sepolia'); -const wallet = new Wallet(PRIVATE_KEY, provider, ethProvider); - -console.log(`Nonce: ${await wallet.getNonce()}`); -``` - -### `getDeploymentNonce` - -Returns account's deployment nonce number. - -```ts -async getDeploymentNonce(): Promise -``` - -#### Example - -```ts -import { Wallet, Provider, utils } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const PRIVATE_KEY = ''; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const ethProvider = ethers.getDefaultProvider('sepolia'); -const wallet = new Wallet(PRIVATE_KEY, provider, ethProvider); - -console.log(`Nonce: ${await wallet.getDeploymentNonce()}`); -``` - -### `ethWallet` - -You can get an `ethers.Wallet` object with the same private key with `ethWallet()` method. - -```ts -ethWallet(): ethers.Wallet -``` - -#### Example - -```ts -import { Wallet, Provider, utils } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const PRIVATE_KEY = ''; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const ethProvider = ethers.getDefaultProvider('sepolia'); -const wallet = new Wallet(PRIVATE_KEY, provider, ethProvider); - -const ethWallet = wallet.ethWallet(); -``` - -### `l2TokenAddress` - -Returns the L2 token address equivalent for a L1 token address as they are not equal. ETH's address is set to zero -address. - -:::warning Only works for tokens bridged on default zkSync Era bridges. ::: - -#### Inputs - -| Parameter | Type | Description | -| --------- | --------- | ------------------------------- | -| `token` | `Address` | The address of the token on L1. | - -```ts -async l2TokenAddress(token: Address): Promise -``` - -#### Example - -```ts -import { Wallet, Provider, utils } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const PRIVATE_KEY = ''; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const ethProvider = ethers.getDefaultProvider('sepolia'); -const wallet = new Wallet(PRIVATE_KEY, provider, ethProvider); - -const tokenL1 = '0x5C221E77624690fff6dd741493D735a17716c26B'; - -console.log(`Token L2 address: ${await wallet.l2TokenAddress(tokenL1)}`); -``` - -### `populateTransaction` - -Designed for users who prefer a simplified approach by providing only the necessary data to create a valid transaction. -The only required fields are `transaction.to` and either `transaction.data` or `transaction.value` (or both, if the -method is payable). Any other fields that are not set will be prepared by this method. - -| Parameter | Type | Description | -| ------------- | ----------------------------------------------------- | -------------------- | -| `transaction` | [`TransactionRequest`](./types.md#transactionrequest) | Transaction request. | - -```ts -override async populateTransaction(transaction: TransactionRequest): Promise -``` - -#### Example - -```ts -import { Wallet, Provider, utils } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const PRIVATE_KEY = ''; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const ethProvider = ethers.getDefaultProvider('sepolia'); -const wallet = new Wallet(PRIVATE_KEY, provider, ethProvider); - -const recipient = Wallet.createRandom(); - -const tx = wallet.populateTransaction({ - to: recipient.address, - amount: ethers.parseEther('0.01'), -}); -``` - -### `signTransaction` - -Signs the transaction and serializes it to be ready to be broadcast to the network. Throws an error when -`transaction.from` is mismatched from the private key. - -#### Inputs - -| Parameter | Type | Description | -| ------------- | ----------------------------------------------------- | -------------------- | -| `transaction` | [`TransactionRequest`](./types.md#transactionrequest) | Transaction request. | - -```ts -async signTransaction(transaction: TransactionRequest): Promise -``` - -#### Example - -```ts -import { Wallet, Provider, utils } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const PRIVATE_KEY = ''; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const ethProvider = ethers.getDefaultProvider('sepolia'); -const wallet = new Wallet(PRIVATE_KEY, provider); - -const recipient = Wallet.createRandom(); - -const tx = await wallet.signTransaction({ - type: utils.EIP712_TX_TYPE, - to: recipient.address, - value: ethers.parseEther('1'), -}); -``` - -### `sendTransaction` - -Broadcast the transaction to the network. Throws an error when `tx.from` is mismatched from the private key. - -#### Inputs - -| Parameter | Type | Description | -| --------- | ----------------------------------------------------- | -------------------- | -| `tx` | [`TransactionRequest`](./types.md#transactionrequest) | Transaction request. | - -```ts -async sendTransaction(tx: TransactionRequest): Promise -``` - -#### Example - -```ts -import { Wallet, Provider, utils } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const PRIVATE_KEY = ''; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const ethProvider = ethers.getDefaultProvider('sepolia'); -const wallet = new Wallet(PRIVATE_KEY, provider); - -const recipient = Wallet.createRandom(); - -const tx = await wallet.sendTransaction({ - type: utils.EIP712_TX_TYPE, - to: recipient.address, - value: ethers.parseEther('1'), -}); -``` - -### `transfer` - -For convenience, the `Wallet` class has `transfer` method, which can transfer `ETH` or any `ERC20` token within the same -interface. - -#### Inputs - -| Parameter | Type | Description | -| ------------------------------ | ------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------- | -| `transaction.to` | `Address` | The address of the recipient. | -| `transaction.amount` | `BigNumberish` | The amount of the token to transfer (optional). | -| `transaction.token?` | `Address` | The address of the token. `ETH` by default (optional). | -| `transaction.paymasterParams?` | [`PaymasterParams`](./types.md#paymasterparams) | Paymaster parameters (optional). | -| `transaction.overrides?` | [`ethers.Overrides`](https://docs.ethers.org/v6/api/contract/#Overrides) | Transaction's overrides which may be used to pass l2 `gasLimit`, `gasPrice`, `value`, etc (optional). | - -```ts -async transfer(transaction: { - to: Address; - amount: BigNumberish; - token?: Address; - paymasterParams?: PaymasterParams; - overrides?: ethers.Overrides; -}): Promise -``` - -#### Examples - -Transfer ETH. - -```ts -import { Wallet, Provider, utils } from 'zksync-ethers'; - -const PRIVATE_KEY = ''; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const wallet = new Wallet(PRIVATE_KEY, provider); - -const recipient = Wallet.createRandom(); - -const transferHandle = await wallet.transfer({ - to: recipient.address, - amount: ethers.parseEther('0.01'), -}); - -const tx = await transferHandle.wait(); - -console.log(`The sum of ${tx.value} ETH was transferred to ${tx.to}`); -``` - -Transfer ETH using paymaster to facilitate fee payment with an ERC20 token. - -```ts -import { Wallet, Provider, utils } from 'zksync-ethers'; - -const PRIVATE_KEY = ''; -const token = '0x927488F48ffbc32112F1fF721759649A89721F8F'; // Crown token which can be minted for free -const paymaster = '0x13D0D8550769f59aa241a41897D4859c87f7Dd46'; // Paymaster for Crown token - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const wallet = new Wallet(PRIVATE_KEY, provider); - -const recipient = Wallet.createRandom(); - -const transferHandle = await wallet.transfer({ - to: recipient.address, - amount: ethers.parseEther('0.01'), - paymasterParams: utils.getPaymasterParams(paymaster, { - type: 'ApprovalBased', - token: token, - minimalAllowance: 1, - innerInput: new Uint8Array(), - }), -}); - -const tx = await transferHandle.wait(); - -console.log(`The sum of ${tx.value} ETH was transferred to ${tx.to}`); -``` - -### `getAllowanceL1` - -Returns the amount of approved tokens for a specific L1 bridge. - -#### Inputs - -| Parameter | Type | Description | -| ---------------- | ---------- | ----------------------------------------------------------------------------------------------------------------------------------------- | -| `token` | `Address` | The Ethereum address of the token. | -| `bridgeAddress?` | `Address` | The address of the bridge contract to be used. Defaults to the default zkSync bridge, either `L1EthBridge` or `L1Erc20Bridge` (optional). | -| `blockTag?` | `BlockTag` | In which block an allowance should be checked on. `committed`, i.e. the latest processed one is the default option (optional). | - -```ts -async getAllowanceL1( - token: Address, - bridgeAddress?: Address, - blockTag?: ethers.BlockTag -): Promise -``` - -#### Example - -```ts -import { Wallet, Provider, utils } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const PRIVATE_KEY = ''; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const ethProvider = ethers.getDefaultProvider('sepolia'); -const wallet = new Wallet(PRIVATE_KEY, provider, ethProvider); - -const tokenL1 = '0x5C221E77624690fff6dd741493D735a17716c26B'; -console.log(`Token allowance: ${await wallet.getAllowanceL1(tokenL1)}`); -``` - -### `approveERC20` - -Bridging ERC20 tokens from Ethereum requires approving the tokens to the zkSync Ethereum smart contract. - -#### Inputs - -| Parameter | Type | Description | -| ------------ | ------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------- | -| `token` | `Address` | The Ethereum address of the token. | -| `amount` | `BigNumberish` | The amount of the token to be approved. | -| `overrides?` | [`ethers.Overrides`](https://docs.ethers.org/v6/api/contract/#Overrides) | Transaction's overrides which may be used to pass l2 `gasLimit`, `gasPrice`, `value`, etc (optional). | - -```ts -async approveERC20( - token: Address, - amount: BigNumberish, - overrides?: ethers.Overrides & { bridgeAddress?: Address } -): Promise -``` - -#### Example - -```ts -import { Wallet, Provider, utils } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const PRIVATE_KEY = ''; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const ethProvider = ethers.getDefaultProvider('sepolia'); -const wallet = new Wallet(PRIVATE_KEY, provider, ethProvider); - -const tokenL1 = '0x56E69Fa1BB0d1402c89E3A4E3417882DeA6B14Be'; -const txHandle = await wallet.approveERC20(tokenL1, '10000000'); - -await txHandle.wait(); -``` - -### `getBaseCost` - -Returns base cost for L2 transaction. - -#### Inputs - -| Name | Type | Description | -| --------------------------- | -------------- | ------------------------------------------------------------------------------------------------- | -| `params.gasLimit` | `BigNumberish` | The `gasLimit` for the L2 contract call. | -| `params.gasPerPubdataByte?` | `BigNumberish` | The L2 gas price for each published L1 calldata byte (optional). | -| `params.gasPrice?` | `BigNumberish` | The L1 gas price of the L1 transaction that will send the request for an execute call (optional). | - -```ts -async getBaseCost(params: { - gasLimit: BigNumberish; - gasPerPubdataByte?: BigNumberish; - gasPrice?: BigNumberish; -}): Promise -``` - -#### Example - -```ts -import { Wallet, Provider, utils } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const PRIVATE_KEY = ''; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const ethProvider = ethers.getDefaultProvider('sepolia'); -const wallet = new Wallet(PRIVATE_KEY, provider, ethProvider); - -console.log(`Base cost: ${await wallet.getBaseCost({ gasLimit: 100_000 })}`); -``` - -### `deposit` - -Transfers the specified token from the associated account on the L1 network to the target account on the L2 network. The -token can be either ETH or any ERC20 token. For ERC20 tokens, enough approved tokens must be associated with the -specified L1 bridge (default one or the one defined in `transaction.bridgeAddress`). In this case, -`transaction.approveERC20` can be enabled to perform token approval. If there are already enough approved tokens for the -L1 bridge, token approval will be skipped. To check the amount of approved tokens for a specific bridge, use the -[`allowanceL1`](#getallowancel1) method. - -#### Inputs - -| Parameter | Type | Description | -| -------------------------------- | ------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `transaction.token` | `Address` | The address of the token to deposit. `ETH` by default. | -| `transaction.amount` | `BigNumberish` | The amount of the token to withdraw. | -| `transaction.to?` | `Address` | The address that will receive the deposited tokens on L2 (optional). | -| `transaction.operatorTip?` | `BigNumberish` | (_currently is not used_) If the ETH value passed with the transaction is not explicitly stated in the overrides, this field will be equal to the tip the operator will receive on top of the base cost of the transaction (optional). | -| `transaction.bridgeAddress?` | `Address` | The address of the bridge contract to be used. Defaults to the default zkSync bridge (either `L1EthBridge` or `L1Erc20Bridge`) (optional). | -| `transaction.approveERC20?` | `boolean` | Whether or not should the token approval be performed under the hood. Set this flag to `true` if you bridge an ERC20 token and didn't call the `approveERC20` function beforehand (optional). | -| `transaction.l2GasLimit?` | `BigNumberish` | Maximum amount of L2 gas that transaction can consume during execution on L2 (optional). | -| `transaction.gasPerPubdataByte?` | `BigNumberish` | Whether or not should the token approval be performed under the hood. Set this flag to `true` if you bridge an ERC20 token and didn't call the `approveERC20` function beforehand (optional). | -| `transaction.refundRecipient?` | `Address` | The address on L2 that will receive the refund for the transaction. If the transaction fails, it will also be the address to receive l2Value (optional). | -| `transaction.overrides?` | [`ethers.Overrides`](https://docs.ethers.org/v6/api/contract/#Overrides) | Transaction's overrides which may be used to pass l2 `gasLimit`, `gasPrice`, `value`, etc (optional). | -| `transaction.approveOverrides?` | [`ethers.Overrides`](https://docs.ethers.org/v6/api/contract/#Overrides) | Transaction's overrides which may be used to pass l2 `gasLimit`, `gasPrice`, `value`, etc (optional). | -| `transaction.customBridgeData?` | `BytesLike` | Additional data that can be sent to a bridge (optional). | - -```ts -async deposit(transaction: { - token: Address; - amount: BigNumberish; - to?: Address; - operatorTip?: BigNumberish; - bridgeAddress?: Address; - approveERC20?: boolean; - l2GasLimit?: BigNumberish; - gasPerPubdataByte?: BigNumberish; - refundRecipient?: Address; - overrides?: ethers.Overrides; - approveOverrides?: ethers.Overrides; - customBridgeData?: BytesLike; -}): Promise -``` - -#### Example - -```ts -import { Wallet, Provider, utils } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const PRIVATE_KEY = ''; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const ethProvider = ethers.getDefaultProvider('sepolia'); -const wallet = new Wallet(PRIVATE_KEY, provider, ethProvider); - -const tokenL1 = '0x56E69Fa1BB0d1402c89E3A4E3417882DeA6B14Be'; -const tokenDepositHandle = await wallet.deposit({ - token: tokenL1, - amount: '10000000', - approveERC20: true, -}); -// Note that we wait not only for the L1 transaction to complete but also for it to be -// processed by zkSync. If we want to wait only for the transaction to be processed on L1, -// we can use `await tokenDepositHandle.waitL1Commit()` -await tokenDepositHandle.wait(); - -const ethDepositHandle = await wallet.deposit({ - token: utils.ETH_ADDRESS, - amount: '10000000', -}); -// Note that we wait not only for the L1 transaction to complete but also for it to be -// processed by zkSync. If we want to wait only for the transaction to be processed on L1, -// we can use `await ethDepositHandle.waitL1Commit()` -await ethDepositHandle.wait(); -``` - -### `getDepositTx` - -Returns populated deposit transaction. - -#### Inputs - -| Parameter | Type | Description | -| -------------------------------- | ------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `transaction.token` | `Address` | The address of the token to deposit. `ETH` by default. | -| `transaction.amount` | `BigNumberish` | The amount of the token to withdraw. | -| `transaction.to?` | `Address` | The address that will receive the deposited tokens on L2 (optional). | -| `transaction.operatorTip?` | `BigNumberish` | (_currently is not used_) If the ETH value passed with the transaction is not explicitly stated in the overrides,
this field will be equal to the tip the operator will receive on top of the base cost of the transaction (optional). | -| `transaction.bridgeAddress?` | `Address` | The address of the bridge contract to be used. Defaults to the default zkSync bridge (either `L1EthBridge` or `L1Erc20Bridge`) (optional). | -| `transaction.l2GasLimit?` | `BigNumberish` | Maximum amount of L2 gas that transaction can consume during execution on L2 (optional). | -| `transaction.gasPerPubdataByte?` | `BigNumberish` | Whether or not should the token approval be performed under the hood. Set this flag to `true` if you bridge an ERC20 token and didn't call the `approveERC20` function beforehand (optional). | -| `transaction.customBridgeData?` | `BytesLike` | Additional data that can be sent to a bridge (optional). | -| `transaction.refundRecipient?` | `Address` | The address on L2 that will receive the refund for the transaction. If the transaction fails, it will also be the address to receive l2Value (optional). | -| `transaction.overrides?` | [`ethers.Overrides`](https://docs.ethers.org/v6/api/contract/#Overrides) | Transaction's overrides which may be used to pass l2 `gasLimit`, `gasPrice`, `value`, etc (optional). | - -```ts -async getDepositTx(transaction: { - token: Address; - amount: BigNumberish; - to?: Address; - operatorTip?: BigNumberish; - bridgeAddress?: Address; - l2GasLimit?: BigNumberish; - gasPerPubdataByte?: BigNumberish; - customBridgeData?: BytesLike; - refundRecipient?: Address; - overrides?: ethers.Overrides; -}): Promise -``` - -#### Example - -```ts -import { Wallet, Provider, utils } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const PRIVATE_KEY = ''; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const ethProvider = ethers.getDefaultProvider('sepolia'); -const wallet = new Wallet(PRIVATE_KEY, provider, ethProvider); - -const tokenL1 = '0x56E69Fa1BB0d1402c89E3A4E3417882DeA6B14Be'; -const tx = await wallet.getDepositTx({ - token: tokenL1, - amount: '10000000', -}); -``` - -### `estimateGasDeposit` - -Estimates the amount of gas required for a deposit transaction on L1 network. Gas of approving ERC20 token is not -included in estimation. - -#### Inputs - -| Parameter | Type | Description | -| -------------------------------- | ------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `transaction.token` | `Address` | The address of the token to deposit. `ETH` by default. | -| `transaction.amount` | `BigNumberish` | The amount of the token to withdraw. | -| `transaction.to?` | `Address` | The address that will receive the deposited tokens on L2 (optional). | -| `transaction.operatorTip?` | `BigNumberish` | (_currently is not used_) If the ETH value passed with the transaction is not explicitly stated in the overrides,
this field will be equal to the tip the operator will receive on top of the base cost of the transaction (optional). | -| `transaction.bridgeAddress?` | `Address` | The address of the bridge contract to be used. Defaults to the default zkSync bridge (either `L1EthBridge` or `L1Erc20Bridge`) (optional). | -| `transaction.l2GasLimit?` | `BigNumberish` | Maximum amount of L2 gas that transaction can consume during execution on L2 (optional). | -| `transaction.gasPerPubdataByte?` | `BigNumberish` | Whether or not should the token approval be performed under the hood. Set this flag to `true` if you bridge an ERC20 token and didn't call the `approveERC20` function beforehand (optional). | -| `transaction.customBridgeData?` | `BytesLike` | Additional data that can be sent to a bridge (optional). | -| `transaction.refundRecipient?` | `Address` | The address on L2 that will receive the refund for the transaction. If the transaction fails, it will also be the address to receive l2Value (optional). | -| `transaction.overrides?` | [`ethers.Overrides`](https://docs.ethers.org/v6/api/contract/#Overrides) | Transaction's overrides which may be used to pass l2 `gasLimit`, `gasPrice`, `value`, etc (optional). | - -```ts -async estimateGasDeposit(transaction: - token: Address; - amount: BigNumberish; - to?: Address; - operatorTip?: BigNumberish; - bridgeAddress?: Address; - customBridgeData?: BytesLike; - l2GasLimit?: BigNumberish; - gasPerPubdataByte?: BigNumberish; - refundRecipient?: Address; - overrides?: ethers.Overrides; - }): Promise -``` - -#### Example - -```ts -import { Wallet, Provider, utils } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const PRIVATE_KEY = ''; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const ethProvider = ethers.getDefaultProvider('sepolia'); -const wallet = new Wallet(PRIVATE_KEY, provider, ethProvider); - -const tokenL1 = '0x5C221E77624690fff6dd741493D735a17716c26B'; -const gas = await wallet.estimateGasDeposit({ - token: tokenL1, - amount: '10000000', -}); -console.log(`Gas: ${gas}`); -``` - -### `getFullRequiredDepositFee` - -Retrieves the full needed ETH fee for the deposit. Returns the L1 fee and the L2 fee -[`FullDepositFee`](./types.md#fulldepositfee). - -#### Inputs - -| Parameter | Type | Description | -| -------------------------------- | ------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `transaction.token` | `Address` | The address of the token to deposit. `ETH` by default. | -| `transaction.to?` | `Address` | The address that will receive the deposited tokens on L2 (optional). | -| `transaction.bridgeAddress?` | `Address` | The address of the bridge contract to be used. Defaults to the default zkSync bridge (either `L1EthBridge` or `L1Erc20Bridge`) (optional). | -| `transaction.customBridgeData?` | `BytesLike` | Additional data that can be sent to a bridge (optional). | -| `transaction.gasPerPubdataByte?` | `BigNumberish` | Whether or not should the token approval be performed under the hood. Set this flag to `true` if you bridge an ERC20 token and didn't call the `approveERC20` function beforehand (optional). | -| `transaction.overrides?` | [`ethers.Overrides`](https://docs.ethers.org/v6/api/contract/#Overrides) | Transaction's overrides which may be used to pass l2 `gasLimit`, `gasPrice`, `value`, etc (optional). | - -```ts -async getFullRequiredDepositFee(transaction: { - token: Address; - to?: Address; - bridgeAddress?: Address; - customBridgeData?: BytesLike; - gasPerPubdataByte?: BigNumberish; - overrides?: ethers.Overrides; -}): Promise -``` - -#### Example - -```ts -import { Wallet, Provider, utils } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const PRIVATE_KEY = ''; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const ethProvider = ethers.getDefaultProvider('sepolia'); -const wallet = new Wallet(PRIVATE_KEY, provider, ethProvider); - -const tokenL1 = '0x56E69Fa1BB0d1402c89E3A4E3417882DeA6B14Be'; -const fee = await wallet.getFullRequiredDepositFee({ - token: tokenL1, - to: await wallet.getAddress(), -}); -console.log(`Fee: ${fee}`); -``` - -### `claimFailedDeposit` - -The `claimFailedDeposit` method withdraws funds from the initiated deposit, which failed when finalizing on L2. -If the deposit L2 transaction has failed, it sends an L1 transaction calling `claimFailedDeposit` method of the L1 -bridge, which results in returning L1 tokens back to the depositor, otherwise throws the error. - -#### Inputs - -| Parameter | Type | Description | -| ----------- | --------- | ---------------------------------------------- | -| depositHash | `bytes32` | The L2 transaction hash of the failed deposit. | - -```ts -async claimFailedDeposit(depositHash: BytesLike): Promise -``` - -#### Example - -```ts -import { Wallet, Provider, utils } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const PRIVATE_KEY = ''; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const ethProvider = ethers.getDefaultProvider('sepolia'); -const wallet = new Wallet(PRIVATE_KEY, provider, ethProvider); - -const FAILED_DEPOSIT_HASH = ''; -const claimFailedDepositHandle = await wallet.claimFailedDeposit(FAILED_DEPOSIT_HASH); -``` - -### `withdraw` - -Initiates the withdrawal process which withdraws ETH or any ERC20 token from the associated account on L2 network to the -target account on L1 network. - -#### Inputs - -| Parameter | Type | Description | -| ------------------------------ | ------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------- | -| `transaction.token` | `Address` | The address of the token. `ETH` by default. | -| `transaction.amount` | `BigNumberish` | The amount of the token to withdraw. | -| `transaction.to?` | `Address` | The address of the recipient on L1 (optional). | -| `transaction.bridgeAddress?` | `Address` | The address of the bridge contract to be used (optional). | -| `transaction.paymasterParams?` | [`PaymasterParams`](./types.md#paymasterparams) | Paymaster parameters (optional). | -| `transaction.overrides?` | [`ethers.Overrides`](https://docs.ethers.org/v6/api/contract/#Overrides) | Transaction's overrides which may be used to pass l2 `gasLimit`, `gasPrice`, `value`, etc (optional). | - -```ts -async withdraw(transaction: { - token: Address; - amount: BigNumberish; - to?: Address; - bridgeAddress?: Address; - paymasterParams?: PaymasterParams; - overrides?: ethers.Overrides; -}): Promise -``` - -#### Examples - -Withdraw ETH. - -```ts -import { Wallet, Provider, utils } from 'zksync-ethers'; - -const PRIVATE_KEY = ''; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const wallet = new Wallet(PRIVATE_KEY, provider); - -const tokenL2 = '0x6a4Fb925583F7D4dF82de62d98107468aE846FD1'; -const tokenWithdrawHandle = await wallet.withdraw({ - token: tokenL2, - amount: 10_000_000, -}); -``` - -Withdraw ETH using paymaster to facilitate fee payment with an ERC20 token. - -```ts -import { Wallet, Provider, utils } from 'zksync-ethers'; - -const PRIVATE_KEY = ''; -const token = '0x927488F48ffbc32112F1fF721759649A89721F8F'; // Crown token which can be minted for free -const paymaster = '0x13D0D8550769f59aa241a41897D4859c87f7Dd46'; // Paymaster for Crown token - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const wallet = new Wallet(PRIVATE_KEY, provider); - -const tokenL2 = '0x6a4Fb925583F7D4dF82de62d98107468aE846FD1'; -const tokenWithdrawHandle = await wallet.withdraw({ - token: tokenL2, - amount: 10_000_000, - paymasterParams: utils.getPaymasterParams(paymaster, { - type: 'ApprovalBased', - token: token, - minimalAllowance: 1, - innerInput: new Uint8Array(), - }), -}); -``` - -### `finalizeWithdrawal` - -Proves the inclusion of the L2 -> L1 withdrawal message. - -#### Inputs - -| Name | Type | Description | -| ---------------- | ------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------- | -| `withdrawalHash` | `BytesLike` | Hash of the L2 transaction where the withdrawal was initiated. | -| `index?` | `number` | In case there were multiple withdrawals in one transaction, you may pass an index of the withdrawal you want to finalize. Defaults to 0 (optional). | -| `overrides?` | [`ethers.Overrides`](https://docs.ethers.org/v6/api/contract/#Overrides) | Transaction's overrides which may be used to pass l2 `gasLimit`, `gasPrice`, `value`, etc (optional). | - -```ts -async finalizeWithdrawal(withdrawalHash: BytesLike, index: number = 0, overrides?: ethers.Overrides): Promise -``` - -#### Example - -```ts -import { Wallet, Provider, utils } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const PRIVATE_KEY = ''; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const ethProvider = ethers.getDefaultProvider('sepolia'); -const wallet = new Wallet(PRIVATE_KEY, provider, ethProvider); - -const WITHDRAWAL_HASH = ''; -const finalizeWithdrawHandle = await wallet.finalizeWithdrawal(WITHDRAWAL_HASH); -``` - -### `isWithdrawalFinalized` - -Returns whether the withdrawal transaction is finalized on the L1 network. - -#### Inputs - -| Name | Type | Description | -| ---------------- | ----------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | -| `withdrawalHash` | `BytesLike` | Hash of the L2 transaction where the withdrawal was initiated. | -| `index?` | `number` | In case there were multiple withdrawals in one transaction, you may pass an index of the withdrawal you want to finalize. Defaults to 0 (optional). | - -```ts -async isWithdrawalFinalized(withdrawalHash: BytesLike, index: number = 0): Promise -``` - -#### Example - -```ts -import { Wallet, Provider, utils } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const PRIVATE_KEY = ''; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const ethProvider = ethers.getDefaultProvider('sepolia'); -const wallet = new Wallet(PRIVATE_KEY, provider, ethProvider); - -const WITHDRAWAL_HASH = ''; -const isFinalized = await wallet.isWithdrawalFinalized(WITHDRAWAL_HASH); -``` - -### `finalizeWithdrawalParams` - -Returns the [parameters](./types.md#finalizewithdrawalparams) required for finalizing a withdrawal from the withdrawal -transaction's log on the L1 network. - -#### Inputs - -| Name | Type | Description | -| ---------------- | ----------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | -| `withdrawalHash` | `BytesLike` | Hash of the L2 transaction where the withdrawal was initiated. | -| `index?` | `number` | In case there were multiple withdrawals in one transaction, you may pass an index of the withdrawal you want to finalize. Defaults to 0 (optional). | - -```ts -async finalizeWithdrawalParams(withdrawalHash: BytesLike, index: number = 0): Promise -``` - -#### Example - -```ts -import { Wallet, Provider, utils } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const PRIVATE_KEY = ''; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const ethProvider = ethers.getDefaultProvider('sepolia'); -const wallet = new Wallet(PRIVATE_KEY, provider, ethProvider); - -const WITHDRAWAL_HASH = ''; -const params = await wallet.finalizeWithdrawalParams(WITHDRAWAL_HASH); -``` - -### `requestExecute` - -Request execution of L2 transaction from L1. - -#### Inputs - -| Name | Type | Description | -| -------------------------------- | ------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `transaction.contractAddress` | `Address` | The L2 contract to be called (optional). | -| `transaction.calldata` | `BytesLike` | The input of the L2 transaction (optional). | -| `transaction.l2GasLimit` | `BigNumberish` | Maximum amount of L2 gas that transaction can consume during execution on L2 (optional). | -| `transaction.l2Value?` | `BigNumberish` | `msg.value` of L2 transaction (optional). | -| `transaction.factoryDeps?` | `ethers.BytesLike[]` | An array of L2 bytecodes that will be marked as known on L2 (optional). | -| `transaction.operatorTip?` | `BigNumberish` | (_currently is not used_) If the ETH value passed with the transaction is not explicitly stated in the overrides, this field will be equal to the tip the operator will receive on top of the base cost of the transaction (optional). | -| `transaction.gasPerPubdataByte?` | `BigNumberish` | The L2 gas price for each published L1 calldata byte (optional). | -| `transaction.refundRecipient?` | `Address` | The address on L2 that will receive the refund for the transaction. If the transaction fails, it will also be the address to receive `l2Value` (optional). | -| `transaction.overrides?` | [`ethers.Overrides`](https://docs.ethers.org/v6/api/contract/#Overrides) | Transaction's overrides which may be used to pass l2 `gasLimit`, `gasPrice`, `value`, etc (optional). | - -```ts -async requestExecute(transaction: { - contractAddress: Address; - calldata: string; - l2GasLimit: BigNumberish; - l2Value?: BigNumberish; - factoryDeps?: ethers.BytesLike[]; - operatorTip?: BigNumberish; - gasPerPubdataByte?: BigNumberish; - refundRecipient?: Address; - overrides?: ethers.Overrides; -}): Promise -``` - -#### Example - -```ts -import { Wallet, Provider, utils } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const PRIVATE_KEY = ''; -const CONTRACT_ADDRESS = ''; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const ethProvider = ethers.getDefaultProvider('sepolia'); -const wallet = new Wallet(PRIVATE_KEY, provider, ethProvider); - -const gasPrice = await wallet.providerL1.getGasPrice(); - -// The calldata can be encoded the same way as for Ethereum. -// Here is an example of how to get the calldata from an ABI: -const abi = [ - { - inputs: [], - name: 'increment', - outputs: [], - stateMutability: 'nonpayable', - type: 'function', - }, -]; -const contractInterface = new ethers.utils.Interface(abi); -const calldata = contractInterface.encodeFunctionData('increment', []); -const l2GasLimit = 1000n; - -const txCostPrice = await wallet.getBaseCost({ - gasPrice, - calldataLength: ethers.utils.arrayify(calldata).length, - l2GasLimit, -}); - -console.log(`Executing the transaction will cost ${ethers.utils.formatEther(txCostPrice)} ETH`); - -const executeTx = await wallet.requestExecute({ - contractAddress: CONTRACT_ADDRESS, - calldata, - l2Value: 1, - l2GasLimit, - overrides: { - gasPrice, - value: txCostPrice, - }, -}); - -await executeTx.wait(); -``` - -### `getRequestExecuteTx` - -Returns populated deposit transaction. - -#### Inputs - -| Name | Type | Description | -| -------------------------------- | ------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `transaction.contractAddress` | `Address` | The L2 contract to be called (optional). | -| `transaction.calldata` | `BytesLike` | The input of the L2 transaction (optional). | -| `transaction.l2GasLimit` | `BigNumberish` | Maximum amount of L2 gas that transaction can consume during execution on L2 (optional). | -| `transaction.l2Value?` | `BigNumberish` | `msg.value` of L2 transaction (optional). | -| `transaction.factoryDeps?` | `ethers.BytesLike[]` | An array of L2 bytecodes that will be marked as known on L2 (optional). | -| `transaction.operatorTip?` | `BigNumberish` | (_currently is not used_) If the ETH value passed with the transaction is not explicitly stated in the overrides, this field will be equal to the tip the operator will receive on top of the base cost of the transaction (optional). | -| `transaction.gasPerPubdataByte?` | `BigNumberish` | The L2 gas price for each published L1 calldata byte (optional). | -| `transaction.refundRecipient?` | `Address` | The address on L2 that will receive the refund for the transaction. If the transaction fails, it will also be the address to receive `l2Value` (optional). | -| `transaction.overrides` | [`ethers.Overrides`](https://docs.ethers.org/v6/api/contract/#Overrides) | Transaction's overrides which may be used to pass l2 `gasLimit`, `gasPrice`, `value`, etc (optional). | - -```ts -async getRequestExecuteTx(transaction: { - contractAddress: Address; - calldata: string; - l2GasLimit?: BigNumberish; - l2Value?: BigNumberish; - factoryDeps?: ethers.BytesLike[]; - operatorTip?: BigNumberish; - gasPerPubdataByte?: BigNumberish; - refundRecipient?: Address; - overrides?: ethers.Overrides; -}): Promise -``` - -#### Example - -```ts -import { Wallet, Provider, utils } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const PRIVATE_KEY = ''; -const CONTRACT_ADDRESS = ''; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const ethProvider = ethers.getDefaultProvider('sepolia'); -const wallet = new Wallet(PRIVATE_KEY, provider, ethProvider); - -const gasPrice = await wallet.providerL1.getGasPrice(); - -// The calldata can be encoded the same way as for Ethereum. -// Here is an example of how to get the calldata from an ABI: -const abi = [ - { - inputs: [], - name: 'increment', - outputs: [], - stateMutability: 'nonpayable', - type: 'function', - }, -]; -const contractInterface = new ethers.utils.Interface(abi); -const calldata = contractInterface.encodeFunctionData('increment', []); -const l2GasLimit = 1000n; - -const txCostPrice = await wallet.getBaseCost({ - gasPrice, - calldataLength: ethers.utils.arrayify(calldata).length, - l2GasLimit, -}); - -console.log(`Executing the transaction will cost ${ethers.utils.formatEther(txCostPrice)} ETH`); - -const executeTx = await wallet.getRequestExecuteTx({ - contractAddress: CONTRACT_ADDRESS, - calldata, - l2Value: 1, - l2GasLimit, - overrides: { - gasPrice, - value: txCostPrice, - }, -}); -``` - -### `estimateGasRequestExecute` - -Estimates the amount of gas required for a request execute transaction. - -#### Inputs - -| Name | Type | Description | -| -------------------------------- | ------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `transaction.contractAddress` | `Address` | The L2 contract to be called (optional). | -| `transaction.calldata` | `BytesLike` | The input of the L2 transaction (optional). | -| `transaction.l2GasLimit` | `BigNumberish` | Maximum amount of L2 gas that transaction can consume during execution on L2 (optional). | -| `transaction.l2Value?` | `BigNumberish` | `msg.value` of L2 transaction (optional). | -| `transaction.factoryDeps?` | `ethers.BytesLike[]` | An array of L2 bytecodes that will be marked as known on L2 (optional). | -| `transaction.operatorTip?` | `BigNumberish` | (_currently is not used_) If the ETH value passed with the transaction is not explicitly stated in the overrides, this field will be equal to the tip the operator will receive on top of the base cost of the transaction (optional). | -| `transaction.gasPerPubdataByte?` | `BigNumberish` | The L2 gas price for each published L1 calldata byte (optional). | -| `transaction.refundRecipient?` | `Address` | The address on L2 that will receive the refund for the transaction. If the transaction fails, it will also be the address to receive `l2Value` (optional). | -| `transaction.overrides` | [`ethers.Overrides`](https://docs.ethers.org/v6/api/contract/#Overrides) | Transaction's overrides which may be used to pass l2 `gasLimit`, `gasPrice`, `value`, etc (optional). | - -```ts -async estimateGasRequestExecute(transaction: { - contractAddress: Address; - calldata: string; - l2GasLimit?: BigNumberish; - l2Value?: BigNumberish; - factoryDeps?: ethers.BytesLike[]; - operatorTip?: BigNumberish; - gasPerPubdataByte?: BigNumberish; - refundRecipient?: Address; - overrides?: ethers.Overrides; -}): Promise -``` - -#### Example - -```ts -import { Wallet, Provider, utils } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const PRIVATE_KEY = ''; -const CONTRACT_ADDRESS = ''; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const ethProvider = ethers.getDefaultProvider('sepolia'); -const wallet = new Wallet(PRIVATE_KEY, provider, ethProvider); - -const gasPrice = await wallet.providerL1.getGasPrice(); - -// The calldata can be encoded the same way as for Ethereum. -// Here is an example of how to get the calldata from an ABI: -const abi = [ - { - inputs: [], - name: 'increment', - outputs: [], - stateMutability: 'nonpayable', - type: 'function', - }, -]; -const contractInterface = new ethers.utils.Interface(abi); -const calldata = contractInterface.encodeFunctionData('increment', []); -const l2GasLimit = 1000n; - -const txCostPrice = await wallet.getBaseCost({ - gasPrice, - calldataLength: ethers.utils.arrayify(calldata).length, - l2GasLimit, -}); - -console.log(`Executing the transaction will cost ${ethers.utils.formatEther(txCostPrice)} ETH`); - -const executeTx = await wallet.getRequestExecuteTx({ - contractAddress: CONTRACT_ADDRESS, - calldata, - l2Value: 1, - l2GasLimit, - overrides: { - gasPrice, - value: txCostPrice, - }, -}); -``` - -## `EIP712Signer` - -Provides support for an EIP712 transaction. The methods of this class are mostly used internally. - -### `getSignInput` - -Generates the EIP-712 typed data from provided transaction. Optional fields are populated by zero values. - -#### Inputs - -| Parameter | Type | Description | -| ------------- | ----------------------------------------------------- | -------------------- | -| `transaction` | [`TransactionRequest`](./types.md#transactionrequest) | Transaction request. | - -```ts -static getSignInput(transaction: TransactionRequest) -``` - -#### Example - -```ts -const tx = EIP712Signer.getSignInput({ - type: utils.EIP712_TX_TYPE, - to: '0xa61464658AfeAf65CccaaFD3a512b69A83B77618', - value: BigInt(7_000_000), - from: '0x36615Cf349d7F6344891B1e7CA7C72883F5dc049', - nonce: 0, - chainId: BigInt(270), - gasPrice: BigInt(250_000_000), - gasLimit: BigInt(21_000), - customData: {}, -}); -``` - -### `sign` - -Signs an Ethereum transaction using EIP-712. - -#### Inputs - -| Parameter | Type | Description | -| ------------- | ----------------------------------------------------- | -------------------- | -| `transaction` | [`TransactionRequest`](./types.md#transactionrequest) | Transaction request. | - -```ts -async sign(transaction: TransactionRequest): Promise -``` - -### `getSignedDigest` - -Generates the signed digest of an Ethereum transaction using EIP-712. - -#### Inputs - -| Parameter | Type | Description | -| ------------- | ----------------------------------------------------- | -------------------- | -| `transaction` | [`TransactionRequest`](./types.md#transactionrequest) | Transaction request. | - -```ts -static getSignedDigest(transaction: TransactionRequest): ethers.BytesLike -``` - -### `getDomain` - -Returns the EIP712 domain. - -```ts -async getDomain(): Promise -``` - -## `Signer` - -This class is to be used in a browser environment. The easiest way to construct it is to use the `getSigner` method of -the `BrowserProvider`. This structure extends `ethers.JsonRpcSigner` and so supports all the methods available for it. - -```ts -import { BrowserProvider } from 'zksync-ethers'; - -const provider = new BrowserProvider(window.ethereum); -const signer = provider.getSigner(); -``` - -### `getBalance` - -Returns the amount of the token the `Signer` has. - -#### Inputs - -| Parameter | Type | Description | -| ---------- | ---------- | ---------------------------------------------------------------------------------------------------------------- | -| `token?` | `Address` | The address of the token. ETH by default. | -| `blockTag` | `BlockTag` | In which block a balance should be checked on. `committed`, i.e. the latest processed one is the default option. | - -```ts -async getBalance(token?: Address, blockTag: BlockTag = 'committed'): Promise -``` - -#### Example - -```ts -import { BrowserProvider } from 'zksync-ethers'; - -const provider = new BrowserProvider(window.ethereum); -const signer = provider.getSigner(); - -const tokenL2 = '0x6a4Fb925583F7D4dF82de62d98107468aE846FD1'; -// Getting token balance -console.log(await signer.getBalance(tokenL2)); - -// Getting ETH balance -console.log(await signer.getBalance()); -``` - -### `getNonce` - -Returns account's nonce number. - -#### Inputs - -| Parameter | Type | Description | -| ----------- | ---------- | ---------------------------------------------------------------------------------------------------------------- | -| `blockTag?` | `BlockTag` | In which block a balance should be checked on. `committed`, i.e. the latest processed one is the default option. | - -```ts -async getNonce(blockTag?: BlockTag): Promise -``` - -#### Example - -```ts -import { BrowserProvider } from 'zksync-ethers'; - -const provider = new BrowserProvider(window.ethereum); -const signer = provider.getSigner(); - -console.log(await signer.getNonce()); -``` - -### `transfer` - -Please note that for now, unlike Ethereum, zkSync does not support native transfers, i.e. the `value` field of all -transactions is equal to `0`. All the token transfers are done through ERC20 `transfer` function calls. - -But for convenience, the `Wallet` class has `transfer` method, which can transfer any `ERC20` tokens. - -#### Inputs - -| Parameter | Type | Description | -| ------------------------------ | ------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------- | -| `transaction.to` | `Address` | The address of the recipient. | -| `transaction.amount` | `BigNumberish` | The amount of the token to transfer. | -| `transaction.token?` | `Address` | The address of the token. `ETH` by default. | -| `transaction.paymasterParams?` | [`PaymasterParams`](./types.md#paymasterparams) | Paymaster parameters (optional). | -| `transaction.overrides?` | [`ethers.Overrides`](https://docs.ethers.org/v6/api/contract/#Overrides) | Transaction's overrides which may be used to pass l2 `gasLimit`,
`gasPrice`, `value`, etc (optional). | - -```ts -async transfer(transaction: { - to: Address; - amount: BigNumberish; - token ? : Address; - paymasterParams?: PaymasterParams; - overrides ? : ethers.Overrides; -}): Promise -``` - -#### Examples - -Transfer ETH. - -```ts -import { BrowserProvider } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const provider = new BrowserProvider(window.ethereum); -const signer = provider.getSigner(); - -const recipient = Wallet.createRandom(); - -const transferHandle = signer.transfer({ - to: recipient.address, - amount: ethers.parseEther('0.01'), -}); -``` - -Transfer ETH using paymaster to facilitate fee payment with an ERC20 token. - -```ts -import { BrowserProvider } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const token = '0x927488F48ffbc32112F1fF721759649A89721F8F'; // Crown token which can be minted for free -const paymaster = '0x13D0D8550769f59aa241a41897D4859c87f7Dd46'; // Paymaster for Crown token - -const provider = new BrowserProvider(window.ethereum); -const signer = provider.getSigner(); - -const recipient = Wallet.createRandom(); - -const transferHandle = signer.transfer({ - to: recipient.address, - amount: ethers.parseEther('0.01'), - paymasterParams: utils.getPaymasterParams(paymaster, { - type: 'ApprovalBased', - token: token, - minimalAllowance: 1, - innerInput: new Uint8Array(), - }), -}); -``` - -### `withdraw` - -Initiates the withdrawal process which withdraws ETH or any ERC20 token from the associated account on L2 network to the -target account on L1 network. - -#### Inputs - -| Parameter | Type | Description | -| ------------------------------ | ------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------- | -| `transaction.token` | `Address` | The address of the token. `ETH` by default. | -| `transaction.amount` | `BigNumberish` | The amount of the token to withdraw. | -| `transaction.to?` | `Address` | The address of the recipient on L1 (optional). | -| `transaction.bridgeAddress?` | `Address` | The address of the bridge contract to be used (optional). | -| `transaction.paymasterParams?` | [`PaymasterParams`](./types.md#paymasterparams) | Paymaster parameters (optional). | -| `overrides?` | [`ethers.Overrides`](https://docs.ethers.org/v6/api/contract/#Overrides) | Transaction's overrides which may be used to pass l2 `gasLimit`, `gasPrice`, `value`, etc (optional). | - -```ts -async withdraw(transaction: { - token: Address; - amount: BigNumberish; - to?: Address; - bridgeAddress?: Address; - paymasterParams?: PaymasterParams; - overrides?: ethers.Overrides; -}): Promise -``` - -#### Examples - -Withdraw ETH. - -```ts -import { BrowserProvider } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const provider = new BrowserProvider(window.ethereum); -const signer = provider.getSigner(); - -const tokenL2 = '0x6a4Fb925583F7D4dF82de62d98107468aE846FD1'; -const tokenWithdrawHandle = await signer.withdraw({ - token: tokenL2, - amount: 10_000_000, -}); -``` - -Withdraw ETH using paymaster to facilitate fee payment with an ERC20 token. - -```ts -import { BrowserProvider } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const token = '0x927488F48ffbc32112F1fF721759649A89721F8F'; // Crown token which can be minted for free -const paymaster = '0x13D0D8550769f59aa241a41897D4859c87f7Dd46'; // Paymaster for Crown token - -const provider = new BrowserProvider(window.ethereum); -const signer = provider.getSigner(); - -const tokenL2 = '0x6a4Fb925583F7D4dF82de62d98107468aE846FD1'; -const tokenWithdrawHandle = await signer.withdraw({ - token: tokenL2, - amount: 10_000_000, - paymasterParams: utils.getPaymasterParams(paymaster, { - type: 'ApprovalBased', - token: token, - minimalAllowance: 1, - innerInput: new Uint8Array(), - }), -}); -``` - -## `L1Signer` - -This class is to be used in a browser environment to do zkSync-related operations on layer 1. This class extends -`ethers.JsonRpcSigner` and so supports all the methods available for it. - -The easiest way to construct it is from an `BrowserProvider` object. - -```ts -import { Provider, L1Signer, types } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const provider = new ethers.BrowserProvider(window.ethereum); -const zksyncProvider = Provider.getDefaultProvider(types.Network.Sepolia); -const signer = L1Signer.from(provider.getSigner(), zksyncProvider); -``` - -### `getMainContract` - -Returns the main zkSync Era smart contract address. - -```ts -async getMainContract(): Promise -``` - -#### Example - -```ts -import { Provider, L1Signer, types } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const provider = new ethers.BrowserProvider(window.ethereum); -const zksyncProvider = Provider.getDefaultProvider(types.Network.Sepolia); -const signer = L1Signer.from(provider.getSigner(), zksyncProvider); - -const mainContract = await signer.getMainContract(); -console.log(mainContract.address); -``` - -### `getL1BridgeContracts` - -Returns L1 bridge contracts. - -```ts -async getL1BridgeContracts(): Promise<{ erc20: IL1Bridge; weth: IL1Bridge }> -``` - -:::note - -there is no separate Ether bridge contract, [Main contract](./accounts.md#getmaincontract) is used instead. - -::: - -### Example - -```ts -import { Provider, L1Signer, types } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const provider = new ethers.BrowserProvider(window.ethereum); -const zksyncProvider = Provider.getDefaultProvider(types.Network.Sepolia); -const signer = L1Signer.from(provider.getSigner(), zksyncProvider); - -const l1BridgeContracts = await signer.getL1BridgeContracts(); -``` - -### `getBalanceL1` - -Returns the amount of the token the `L1Signer` has on Ethereum. - -#### Inputs - -| Parameter | Type | Description | -| ----------- | ---------- | ---------------------------------------------------------------------------------------------------------------- | -| `token?` | `Address` | The address of the token. ETH by default. | -| `blockTag?` | `BlockTag` | In which block a balance should be checked on. `committed`, i.e. the latest processed one is the default option. | - -```ts -async getBalanceL1(token?: Address, blockTag?: BlockTag): Promise -``` - -#### Example - -```ts -import { Provider, L1Signer, types } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const provider = new ethers.BrowserProvider(window.ethereum); -const zksyncProvider = Provider.getDefaultProvider(types.Network.Sepolia); -const signer = L1Signer.from(provider.getSigner(), zksyncProvider); - -const tokenL1 = '0x56E69Fa1BB0d1402c89E3A4E3417882DeA6B14Be'; - -// Getting token balance -console.log(await signer.getBalanceL1(tokenL1)); - -// Getting ETH balance -console.log(await signer.getBalanceL1()); -``` - -### `l2TokenAddress` - -Returns the L2 token address equivalent for a L1 token address as they are not equal. ETH's address is set to zero -address. - -:::warning Only works for tokens bridged on default zkSync Era bridges. ::: - -#### Inputs - -| Parameter | Type | Description | -| --------- | --------- | ------------------------------- | -| `token` | `Address` | The address of the token on L1. | - -```ts -async l2TokenAddress(token: Address): Promise -``` - -#### Example - -```ts -import { Provider, L1Signer, types } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const provider = new ethers.BrowserProvider(window.ethereum); -const zksyncProvider = Provider.getDefaultProvider(types.Network.Sepolia); -const signer = L1Signer.from(provider.getSigner(), zksyncProvider); - -const tokenL1 = '0x5C221E77624690fff6dd741493D735a17716c26B'; - -console.log(`Token L2 address: ${await signer.l2TokenAddress(tokenL1)}`); -``` - -### `getAllowanceL1` - -Returns the amount of approved tokens for a specific L1 bridge. - -#### Inputs - -| Parameter | Type | Description | -| ---------------- | ---------- | ----------------------------------------------------------------------------------------------------------------------------------------- | -| `token` | `Address` | The Ethereum address of the token. | -| `bridgeAddress?` | `Address` | The address of the bridge contract to be used. Defaults to the default zkSync bridge, either `L1EthBridge` or `L1Erc20Bridge` (optional). | -| `blockTag?` | `BlockTag` | In which block an allowance should be checked on. `committed`, i.e. the latest processed one is the default option (optional). | - -```ts -async getAllowanceL1( - token: Address, - bridgeAddress?: Address, - blockTag?: ethers.BlockTag -): Promise -``` - -#### Example - -```ts -import { Provider, L1Signer, types } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const provider = new ethers.BrowserProvider(window.ethereum); -const zksyncProvider = Provider.getDefaultProvider(types.Network.Sepolia); -const signer = L1Signer.from(provider.getSigner(), zksyncProvider); - -const tokenL1 = '0x5C221E77624690fff6dd741493D735a17716c26B'; -console.log(`Token allowance: ${await signer.getAllowanceL1(tokenL1)}`); -``` - -### `approveERC20` - -Bridging ERC20 tokens from Ethereum requires approving the tokens to the zkSync Ethereum smart contract. - -#### Inputs - -| Parameter | Type | Description | -| ------------ | ------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------- | -| `token` | `Address` | The Ethereum address of the token. | -| `amount` | `BigNumberish` | The amount of the token to be approved. | -| `overrides?` | [`ethers.Overrides`](https://docs.ethers.org/v6/api/contract/#Overrides) | Transaction's overrides which may be used to pass l2 `gasLimit`, `gasPrice`, `value`, etc (optional). | - -```ts -async approveERC20( - token: Address, - amount: BigNumberish, - overrides?: ethers.Overrides & { bridgeAddress?: Address } -): Promise -``` - -#### Example - -```ts -import { Provider, L1Signer, types } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const provider = new ethers.BrowserProvider(window.ethereum); -const zksyncProvider = Provider.getDefaultProvider(types.Network.Sepolia); -const signer = L1Signer.from(provider.getSigner(), zksyncProvider); - -const tokenL1 = '0x56E69Fa1BB0d1402c89E3A4E3417882DeA6B14Be'; -const txHandle = await signer.approveERC20(tokenL1, '10000000'); - -await txHandle.wait(); -``` - -### `getBaseCost` - -Returns base cost for L2 transaction. - -#### Inputs - -| Name | Type | Description | -| --------------------------- | -------------- | ------------------------------------------------------------------------------------------------ | -| `params.gasLimit` | `BigNumberish` | The `gasLimit` for the L2 contract call. | -| `params.gasPerPubdataByte?` | `BigNumberish` | The L2 gas price for each published L1 calldata byte (optional). | -| `params.gasPrice?` | `BigNumberish` | The L1 gas price of the L1 transaction that will send the request for an execute call (optional. | - -```ts -async getBaseCost(params: { - gasLimit: BigNumberish; - gasPerPubdataByte?: BigNumberish; - gasPrice?: BigNumberish; -}): Promise -``` - -#### Example - -```ts -import { Provider, L1Signer, types } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const provider = new ethers.BrowserProvider(window.ethereum); -const zksyncProvider = Provider.getDefaultProvider(types.Network.Sepolia); -const signer = L1Signer.from(provider.getSigner(), zksyncProvider); - -console.log(`Base cost: ${await signer.getBaseCost({ gasLimit: 100_000 })}`); -``` - -### `deposit` - -Transfers the specified token from the associated account on the L1 network to the target account on the L2 network. The -token can be either ETH or any ERC20 token. For ERC20 tokens, enough approved tokens must be associated with the -specified L1 bridge (default one or the one defined in `transaction.bridgeAddress`). In this case, -`transaction.approveERC20` can be enabled to perform token approval. If there are already enough approved tokens for the -L1 bridge, token approval will be skipped. To check the amount of approved tokens for a specific bridge, use the -[`allowanceL1`](#getallowancel1) method. - -#### Inputs - -| Parameter | Type | Description | -| -------------------------------- | ------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `transaction.token` | `Address` | The address of the token to deposit. `ETH` by default. | -| `transaction.amount` | `BigNumberish` | The amount of the token to withdraw. | -| `transaction.to?` | `Address` | The address that will receive the deposited tokens on L2 (optional). | -| `transaction.operatorTip?` | `BigNumberish` | (_currently is not used_) If the ETH value passed with the transaction is not explicitly stated in the overrides,
this field will be equal to the tip the operator will receive on top of the base cost of the transaction (optional). | -| `transaction.bridgeAddress?` | `Address` | The address of the bridge contract to be used. Defaults to the default zkSync bridge (either `L1EthBridge` or `L1Erc20Bridge`) (optional). | -| `transaction.approveERC20?` | `boolean` | Whether or not should the token approval be performed under the hood. Set this flag to `true` if you bridge an ERC20 token and didn't call the `approveERC20` function beforehand (optional). | -| `transaction.l2GasLimit?` | `BigNumberish` | Maximum amount of L2 gas that transaction can consume during execution on L2 (optional). | -| `transaction.gasPerPubdataByte?` | `BigNumberish` | Whether or not should the token approval be performed under the hood. Set this flag to `true` if you bridge an ERC20 token and didn't call the `approveERC20` function beforehand (optional). | -| `transaction.refundRecipient?` | `Address` | The address on L2 that will receive the refund for the transaction. If the transaction fails, it will also be the address to receive l2Value (optional). | -| `transaction.overrides?` | [`ethers.Overrides`](https://docs.ethers.org/v6/api/contract/#Overrides) | Transaction's overrides which may be used to pass l2 `gasLimit`, `gasPrice`, `value`, etc (optional). | -| `transaction.approveOverrides?` | [`ethers.Overrides`](https://docs.ethers.org/v6/api/contract/#Overrides) | Transaction's overrides which may be used to pass l2 `gasLimit`, `gasPrice`, `value`, etc (optional). | -| `transaction.customBridgeData?` | `BytesLike` | Additional data that can be sent to a bridge (optional). | - -```ts -async deposit(transaction: { - token: Address; - amount: BigNumberish; - to?: Address; - operatorTip?: BigNumberish; - bridgeAddress?: Address; - approveERC20?: boolean; - l2GasLimit?: BigNumberish; - gasPerPubdataByte?: BigNumberish; - refundRecipient?: Address; - overrides?: ethers.Overrides; - approveOverrides?: ethers.Overrides; - customBridgeData?: BytesLike; -}): Promise -``` - -#### Example - -```ts -import { Provider, L1Signer, types } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const provider = new ethers.BrowserProvider(window.ethereum); -const zksyncProvider = Provider.getDefaultProvider(types.Network.Sepolia); -const signer = L1Signer.from(provider.getSigner(), zksyncProvider); - -const tokenL1 = '0x56E69Fa1BB0d1402c89E3A4E3417882DeA6B14Be'; -const tokenDepositHandle = await signer.deposit({ - token: tokenL1, - amount: '10000000', - approveERC20: true, -}); -// Note that we wait not only for the L1 transaction to complete but also for it to be -// processed by zkSync. If we want to wait only for the transaction to be processed on L1, -// we can use `await tokenDepositHandle.waitL1Commit()` -await tokenDepositHandle.wait(); - -const ethDepositHandle = await signer.deposit({ - token: utils.ETH_ADDRESS, - amount: '10000000', -}); -// Note that we wait not only for the L1 transaction to complete but also for it to be -// processed by zkSync. If we want to wait only for the transaction to be processed on L1, -// we can use `await ethDepositHandle.waitL1Commit()` -await ethDepositHandle.wait(); -``` - -### `getDepositTx` - -Returns populated deposit transaction. - -#### Inputs - -| Parameter | Type | Description | -| -------------------------------- | ------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `transaction.token` | `Address` | The address of the token to deposit. `ETH` by default. | -| `transaction.amount` | `BigNumberish` | The amount of the token to withdraw. | -| `transaction.to?` | `Address` | The address that will receive the deposited tokens on L2 (optional). | -| `transaction.operatorTip?` | `BigNumberish` | (_currently is not used_) If the ETH value passed with the transaction is not explicitly stated in the overrides,
this field will be equal to the tip the operator will receive on top of the base cost of the transaction (optional). | -| `transaction.bridgeAddress?` | `Address` | The address of the bridge contract to be used. Defaults to the default zkSync bridge (either `L1EthBridge` or `L1Erc20Bridge`) (optional). | -| `transaction.l2GasLimit?` | `BigNumberish` | Maximum amount of L2 gas that transaction can consume during execution on L2 (optional). | -| `transaction.gasPerPubdataByte?` | `BigNumberish` | Whether or not should the token approval be performed under the hood. Set this flag to `true` if you bridge an ERC20 token and didn't call the `approveERC20` function beforehand (optional). | -| `transaction.customBridgeData?` | `BytesLike` | Additional data that can be sent to a bridge (optional). | -| `transaction.refundRecipient?` | `Address` | The address on L2 that will receive the refund for the transaction. If the transaction fails, it will also be the address to receive l2Value (optional). | -| `transaction.overrides?` | [`ethers.Overrides`](https://docs.ethers.org/v6/api/contract/#Overrides) | Transaction's overrides which may be used to pass l2 `gasLimit`, `gasPrice`, `value`, etc (optional). | - -```ts -async getDepositTx(transaction: { - token: Address; - amount: BigNumberish; - to?: Address; - operatorTip?: BigNumberish; - bridgeAddress?: Address; - l2GasLimit?: BigNumberish; - gasPerPubdataByte?: BigNumberish; - customBridgeData?: BytesLike; - refundRecipient?: Address; - overrides?: ethers.Overrides; -}): Promise -``` - -#### Example - -```ts -import { Provider, L1Signer, types } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const provider = new ethers.BrowserProvider(window.ethereum); -const zksyncProvider = Provider.getDefaultProvider(types.Network.Sepolia); -const signer = L1Signer.from(provider.getSigner(), zksyncProvider); - -const tokenL1 = '0x56E69Fa1BB0d1402c89E3A4E3417882DeA6B14Be'; -const tx = await signer.getDepositTx({ - token: tokenL1, - amount: '10000000', -}); -``` - -### `estimateGasDeposit` - -Estimates the amount of gas required for a deposit transaction on L1 network. Gas of approving ERC20 token is not -included in estimation. - -#### Inputs - -| Parameter | Type | Description | -| -------------------------------- | ------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `transaction.token` | `Address` | The address of the token to deposit. `ETH` by default. | -| `transaction.amount` | `BigNumberish` | The amount of the token to withdraw. | -| `transaction.to?` | `Address` | The address that will receive the deposited tokens on L2 (optional). | -| `transaction.operatorTip?` | `BigNumberish` | (_currently is not used_) If the ETH value passed with the transaction is not explicitly stated in the overrides,
this field will be equal to the tip the operator will receive on top of the base cost of the transaction (optional). | -| `transaction.bridgeAddress?` | `Address` | The address of the bridge contract to be used. Defaults to the default zkSync bridge (either `L1EthBridge` or `L1Erc20Bridge`) (optional). | -| `transaction.l2GasLimit?` | `BigNumberish` | Maximum amount of L2 gas that transaction can consume during execution on L2 (optional). | -| `transaction.gasPerPubdataByte?` | `BigNumberish` | Whether or not should the token approval be performed under the hood. Set this flag to `true` if you bridge an ERC20 token and didn't call the `approveERC20` function beforehand (optional). | -| `transaction.customBridgeData?` | `BytesLike` | Additional data that can be sent to a bridge (optional). | -| `transaction.refundRecipient?` | `Address` | The address on L2 that will receive the refund for the transaction. If the transaction fails, it will also be the address to receive l2Value (optional). | -| `transaction.overrides?` | [`ethers.Overrides`](https://docs.ethers.org/v6/api/contract/#Overrides) | Transaction's overrides which may be used to pass l2 `gasLimit`, `gasPrice`, `value`, etc (optional). | - -```ts -async estimateGasDeposit(transaction: - token: Address; - amount: BigNumberish; - to?: Address; - operatorTip?: BigNumberish; - bridgeAddress?: Address; - customBridgeData?: BytesLike; - l2GasLimit?: BigNumberish; - gasPerPubdataByte?: BigNumberish; - refundRecipient?: Address; - overrides?: ethers.Overrides; - }): Promise -``` - -#### Example - -```ts -import { Provider, L1Signer, types } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const provider = new ethers.BrowserProvider(window.ethereum); -const zksyncProvider = Provider.getDefaultProvider(types.Network.Sepolia); -const signer = L1Signer.from(provider.getSigner(), zksyncProvider); - -const tokenL1 = '0x5C221E77624690fff6dd741493D735a17716c26B'; -const gas = await signer.estimateGasDeposit({ - token: tokenL1, - amount: '10000000', -}); -console.log(`Gas: ${gas}`); -``` - -### `getFullRequiredDepositFee` - -Retrieves the full needed ETH fee for the deposit. Returns the L1 fee and the L2 fee -[`FullDepositFee`](./types.md#fulldepositfee). - -#### Inputs - -| Parameter | Type | Description | -| -------------------------------- | ------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `transaction.token` | `Address` | The address of the token to deposit. `ETH` by default. | -| `transaction.to?` | `Address` | The address that will receive the deposited tokens on L2 (optional). | -| `transaction.bridgeAddress?` | `Address` | The address of the bridge contract to be used. Defaults to the default zkSync bridge (either `L1EthBridge` or `L1Erc20Bridge`) (optional). | -| `transaction.customBridgeData?` | `BytesLike` | Additional data that can be sent to a bridge (optional). | -| `transaction.gasPerPubdataByte?` | `BigNumberish` | Whether or not should the token approval be performed under the hood. Set this flag to `true` if you bridge an ERC20 token and didn't call the `approveERC20` function beforehand (optional). | -| `transaction.overrides?` | [`ethers.Overrides`](https://docs.ethers.org/v6/api/contract/#Overrides) | Transaction's overrides which may be used to pass l2 `gasLimit`, `gasPrice`, `value`, etc (optional). | - -```ts -async getFullRequiredDepositFee(transaction: { - token: Address; - to?: Address; - bridgeAddress?: Address; - customBridgeData?: BytesLike; - gasPerPubdataByte?: BigNumberish; - overrides?: ethers.Overrides; -}): Promise -``` - -#### Example - -```ts -import { Provider, L1Signer, types } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const provider = new ethers.BrowserProvider(window.ethereum); -const zksyncProvider = Provider.getDefaultProvider(types.Network.Sepolia); -const signer = L1Signer.from(provider.getSigner(), zksyncProvider); - -const tokenL1 = '0x56E69Fa1BB0d1402c89E3A4E3417882DeA6B14Be'; -const fee = await signer.getFullRequiredDepositFee({ - token: tokenL1, - to: await wallet.getAddress(), -}); -console.log(`Fee: ${fee}`); -``` - -### `claimFailedDeposit` - -The `claimFailedDeposit` method withdraws funds from the initiated deposit, which failed when finalizing on L2. -If the deposit L2 transaction has failed, it sends an L1 transaction calling `claimFailedDeposit` method of the L1 -bridge, which results in returning L1 tokens back to the depositor, otherwise throws the error. - -#### Inputs - -| Parameter | Type | Description | -| ----------- | --------- | ---------------------------------------------- | -| depositHash | `bytes32` | The L2 transaction hash of the failed deposit. | - -```ts -async claimFailedDeposit(depositHash: BytesLike): Promise -``` - -#### Example - -```ts -import { Provider, L1Signer, types } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const provider = new ethers.BrowserProvider(window.ethereum); -const zksyncProvider = Provider.getDefaultProvider(types.Network.Sepolia); -const signer = L1Signer.from(provider.getSigner(), zksyncProvider); - -const FAILED_DEPOSIT_HASH = ''; -const claimFailedDepositHandle = await signer.claimFailedDeposit(FAILED_DEPOSIT_HASH); -``` - -### `finalizeWithdrawal` - -Proves the inclusion of the L2 -> L1 withdrawal message. - -#### Inputs - -| Name | Type | Description | -| ---------------- | ------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------- | -| `withdrawalHash` | `BytesLike` | Hash of the L2 transaction where the withdrawal was initiated. | -| `index?` | `number` | In case there were multiple withdrawals in one transaction, you may pass an index of the withdrawal you want to finalize. Defaults to 0) (optional). | -| `overrides?` | [`ethers.Overrides`](https://docs.ethers.org/v6/api/contract/#Overrides) | Transaction's overrides which may be used to pass l2 `gasLimit`, `gasPrice`, `value`, etc (optional). | - -```ts -async finalizeWithdrawal(withdrawalHash: BytesLike, index: number = 0, overrides?: ethers.Overrides): Promise -``` - -#### Example - -```ts -import { Provider, L1Signer, types } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const provider = new ethers.BrowserProvider(window.ethereum); -const zksyncProvider = Provider.getDefaultProvider(types.Network.Sepolia); -const signer = L1Signer.from(provider.getSigner(), zksyncProvider); - -const WITHDRAWAL_HASH = ''; -const finalizeWithdrawHandle = await signer.finalizeWithdrawal(WITHDRAWAL_HASH); -``` - -### `isWithdrawalFinalized` - -Returns whether the withdrawal transaction is finalized on the L1 network. - -#### Inputs - -| Name | Type | Description | -| ---------------- | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | -| `withdrawalHash` | `BytesLike` | Hash of the L2 transaction where the withdrawal was initiated. | -| `index?` | `number` | In case there were multiple withdrawals in one transaction, you may pass an index of the withdrawal you want to finalize. Defaults to 0) (optional). | - -```ts -async isWithdrawalFinalized(withdrawalHash: BytesLike, index: number = 0): Promise -``` - -#### Example - -```ts -import { Provider, L1Signer, types } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const provider = new ethers.BrowserProvider(window.ethereum); -const zksyncProvider = Provider.getDefaultProvider(types.Network.Sepolia); -const signer = L1Signer.from(provider.getSigner(), zksyncProvider); - -const WITHDRAWAL_HASH = ''; -const isFinalized = await signer.isWithdrawalFinalized(WITHDRAWAL_HASH); -``` - -### `finalizeWithdrawalParams` - -Returns the [parameters](./types.md#finalizewithdrawalparams) required for finalizing a withdrawal from the withdrawal -transaction's log on the L1 network. - -#### Inputs - -| Name | Type | Description | -| ---------------- | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | -| `withdrawalHash` | `BytesLike` | Hash of the L2 transaction where the withdrawal was initiated. | -| `index?` | `number` | In case there were multiple withdrawals in one transaction, you may pass an index of the withdrawal you want to finalize. Defaults to 0) (optional). | - -```ts -async finalizeWithdrawalParams(withdrawalHash: BytesLike, index: number = 0): Promise -``` - -#### Example - -```ts -import { Provider, L1Signer, types } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const provider = new ethers.BrowserProvider(window.ethereum); -const zksyncProvider = Provider.getDefaultProvider(types.Network.Sepolia); -const signer = L1Signer.from(provider.getSigner(), zksyncProvider); - -const WITHDRAWAL_HASH = ''; -const params = await signer.finalizeWithdrawalParams(WITHDRAWAL_HASH); -``` - -### `requestExecute` - -Request execution of L2 transaction from L1. - -#### Inputs - -| Name | Type | Description | -| -------------------------------- | ------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `transaction.contractAddress` | `Address` | The L2 contract to be called (optional). | -| `transaction.calldata` | `BytesLike` | The input of the L2 transaction (optional). | -| `transaction.l2GasLimit` | `BigNumberish` | Maximum amount of L2 gas that transaction can consume during execution on L2 (optional). | -| `transaction.l2Value?` | `BigNumberish` | `msg.value` of L2 transaction (optional). | -| `transaction.factoryDeps?` | `ethers.BytesLike[]` | An array of L2 bytecodes that will be marked as known on L2 (optional). | -| `transaction.operatorTip?` | `BigNumberish` | (_currently is not used_) If the ETH value passed with the transaction is not explicitly stated in the overrides, this field will be equal to the tip the operator will receive on top of the base cost of the transaction (optional). | -| `transaction.gasPerPubdataByte?` | `BigNumberish` | The L2 gas price for each published L1 calldata byte (optional). | -| `transaction.refundRecipient?` | `Address` | The address on L2 that will receive the refund for the transaction. If the transaction fails, it will also be the address to receive `l2Value` (optional). | -| `transaction.overrides` | [`ethers.Overrides`](https://docs.ethers.org/v6/api/contract/#Overrides) | Transaction's overrides which may be used to pass l2 `gasLimit`, `gasPrice`, `value`, etc (optional). | - -```ts -async requestExecute(transaction: { - contractAddress: Address; - calldata: string; - l2GasLimit: BigNumberish; - l2Value?: BigNumberish; - factoryDeps?: ethers.BytesLike[]; - operatorTip?: BigNumberish; - gasPerPubdataByte?: BigNumberish; - refundRecipient?: Address; - overrides?: ethers.Overrides; -}): Promise -``` - -#### Example - -```ts -import { Provider, L1Signer, types } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const CONTRACT_ADDRESS = ''; - -const provider = new ethers.BrowserProvider(window.ethereum); -const zksyncProvider = Provider.getDefaultProvider(types.Network.Sepolia); -const signer = L1Signer.from(provider.getSigner(), zksyncProvider); - -const gasPrice = await signer.providerL1.getGasPrice(); - -// The calldata can be encoded the same way as for Ethereum. -// Here is an example of how to get the calldata from an ABI: -const abi = [ - { - inputs: [], - name: 'increment', - outputs: [], - stateMutability: 'nonpayable', - type: 'function', - }, -]; -const contractInterface = new ethers.utils.Interface(abi); -const calldata = contractInterface.encodeFunctionData('increment', []); -const l2GasLimit = 1000n; - -const txCostPrice = await signer.getBaseCost({ - gasPrice, - calldataLength: ethers.utils.arrayify(calldata).length, - l2GasLimit, -}); - -console.log(`Executing the transaction will cost ${ethers.utils.formatEther(txCostPrice)} ETH`); - -const executeTx = await signer.requestExecute({ - contractAddress: CONTRACT_ADDRESS, - calldata, - l2Value: 1, - l2GasLimit, - overrides: { - gasPrice, - value: txCostPrice, - }, -}); - -await executeTx.wait(); -``` - -### `getRequestExecuteTx` - -Returns populated deposit transaction. - -#### Inputs - -| Name | Type | Description | -| -------------------------------- | ------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `transaction.contractAddress` | `Address` | The L2 contract to be called (optional). | -| `transaction.calldata` | `BytesLike` | The input of the L2 transaction (optional). | -| `transaction.l2GasLimit` | `BigNumberish` | Maximum amount of L2 gas that transaction can consume during execution on L2 (optional). | -| `transaction.l2Value?` | `BigNumberish` | `msg.value` of L2 transaction (optional). | -| `transaction.factoryDeps?` | `ethers.BytesLike[]` | An array of L2 bytecodes that will be marked as known on L2 (optional). | -| `transaction.operatorTip?` | `BigNumberish` | (_currently is not used_) If the ETH value passed with the transaction is not explicitly stated in the overrides, this field will be equal to the tip the operator will receive on top of the base cost of the transaction (optional). | -| `transaction.gasPerPubdataByte?` | `BigNumberish` | The L2 gas price for each published L1 calldata byte (optional). | -| `transaction.refundRecipient?` | `Address` | The address on L2 that will receive the refund for the transaction. If the transaction fails, it will also be the address to receive `l2Value` (optional). | -| `transaction.overrides` | [`ethers.Overrides`](https://docs.ethers.org/v6/api/contract/#Overrides) | Transaction's overrides which may be used to pass l2 `gasLimit`, `gasPrice`, `value`, etc (optional). | - -```ts -async getRequestExecuteTx(transaction: { - contractAddress: Address; - calldata: string; - l2GasLimit?: BigNumberish; - l2Value?: BigNumberish; - factoryDeps?: ethers.BytesLike[]; - operatorTip?: BigNumberish; - gasPerPubdataByte?: BigNumberish; - refundRecipient?: Address; - overrides?: ethers.Overrides; -}): Promise -``` - -#### Example - -```ts -import { Provider, L1Signer, types } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const CONTRACT_ADDRESS = ''; - -const provider = new ethers.BrowserProvider(window.ethereum); -const zksyncProvider = Provider.getDefaultProvider(types.Network.Sepolia); -const signer = L1Signer.from(provider.getSigner(), zksyncProvider); - -const gasPrice = await signer.providerL1.getGasPrice(); - -// The calldata can be encoded the same way as for Ethereum. -// Here is an example of how to get the calldata from an ABI: -const abi = [ - { - inputs: [], - name: 'increment', - outputs: [], - stateMutability: 'nonpayable', - type: 'function', - }, -]; -const contractInterface = new ethers.utils.Interface(abi); -const calldata = contractInterface.encodeFunctionData('increment', []); -const l2GasLimit = 1000n; - -const txCostPrice = await signer.getBaseCost({ - gasPrice, - calldataLength: ethers.utils.arrayify(calldata).length, - l2GasLimit, -}); - -console.log(`Executing the transaction will cost ${ethers.utils.formatEther(txCostPrice)} ETH`); - -const executeTx = await signer.getRequestExecuteTx({ - contractAddress: CONTRACT_ADDRESS, - calldata, - l2Value: 1, - l2GasLimit, - overrides: { - gasPrice, - value: txCostPrice, - }, -}); -``` - -### `estimateGasRequestExecute` - -Estimates the amount of gas required for a request execute transaction. - -#### Inputs - -| Name | Type | Description | -| -------------------------------- | ------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `transaction.contractAddress` | `Address` | The L2 contract to be called (optional). | -| `transaction.calldata` | `BytesLike` | The input of the L2 transaction (optional). | -| `transaction.l2GasLimit` | `BigNumberish` | Maximum amount of L2 gas that transaction can consume during execution on L2 (optional). | -| `transaction.l2Value?` | `BigNumberish` | `msg.value` of L2 transaction (optional). | -| `transaction.factoryDeps?` | `ethers.BytesLike[]` | An array of L2 bytecodes that will be marked as known on L2 (optional). | -| `transaction.operatorTip?` | `BigNumberish` | (_currently is not used_) If the ETH value passed with the transaction is not explicitly stated in the overrides, this field will be equal to the tip the operator will receive on top of the base cost of the transaction (optional). | -| `transaction.gasPerPubdataByte?` | `BigNumberish` | The L2 gas price for each published L1 calldata byte (optional). | -| `transaction.refundRecipient?` | `Address` | The address on L2 that will receive the refund for the transaction. If the transaction fails, it will also be the address to receive `l2Value` (optional). | -| `transaction.overrides` | [`ethers.Overrides`](https://docs.ethers.org/v6/api/contract/#Overrides) | Transaction's overrides which may be used to pass l2 `gasLimit`, `gasPrice`, `value`, etc (optional). | - -```ts -async estimateGasRequestExecute(transaction: { - contractAddress: Address; - calldata: string; - l2GasLimit?: BigNumberish; - l2Value?: BigNumberish; - factoryDeps?: ethers.BytesLike[]; - operatorTip?: BigNumberish; - gasPerPubdataByte?: BigNumberish; - refundRecipient?: Address; - overrides?: ethers.Overrides; -}): Promise -``` - -#### Example - -```ts -import { Provider, L1Signer, types } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const CONTRACT_ADDRESS = ''; - -const provider = new ethers.BrowserProvider(window.ethereum); -const zksyncProvider = Provider.getDefaultProvider(types.Network.Sepolia); -const signer = L1Signer.from(provider.getSigner(), zksyncProvider); - -const gasPrice = await signer.providerL1.getGasPrice(); - -// The calldata can be encoded the same way as for Ethereum. -// Here is an example of how to get the calldata from an ABI: -const abi = [ - { - inputs: [], - name: 'increment', - outputs: [], - stateMutability: 'nonpayable', - type: 'function', - }, -]; -const contractInterface = new ethers.utils.Interface(abi); -const calldata = contractInterface.encodeFunctionData('increment', []); -const l2GasLimit = 1000n; - -const txCostPrice = await signer.getBaseCost({ - gasPrice, - calldataLength: ethers.utils.arrayify(calldata).length, - l2GasLimit, -}); - -console.log(`Executing the transaction will cost ${ethers.utils.formatEther(txCostPrice)} ETH`); - -const executeTx = await signer.getRequestExecuteTx({ - contractAddress: CONTRACT_ADDRESS, - calldata, - l2Value: 1, - l2GasLimit, - overrides: { - gasPrice, - value: txCostPrice, - }, -}); -``` diff --git a/content/20.build/sdks/js/zksync-ethers/contracts.md b/content/20.build/sdks/js/zksync-ethers/contracts.md deleted file mode 100644 index fee5eca4..00000000 --- a/content/20.build/sdks/js/zksync-ethers/contracts.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: JS SDK Contracts | zkSync Docs ---- - -# Contracts - -`zksync-ethers` does not implement any new `Contract` class, since `ethers.Contract` fully works out of the box. -However, for convenience, the library still re-exports this class. - -Since deploying smart contracts on zkSync has some differences from deploying on Ethereum, there is a need for a -specific `ContractFactory` method. It supports the same interface as `ethers.ContractFactory`. - -In order to pay for smart contract interactions in ERC20 tokens, `customData` override should be used. You can read more -about accessing zkSync features in [the next chapter](./features.md). diff --git a/content/20.build/sdks/js/zksync-ethers/features.md b/content/20.build/sdks/js/zksync-ethers/features.md deleted file mode 100644 index 79de4eda..00000000 --- a/content/20.build/sdks/js/zksync-ethers/features.md +++ /dev/null @@ -1,127 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: JS SDK Features | zkSync Docs ---- - -# zkSync Era Features - -While zkSync is mostly Web3-compatible, it has some differences compared to Ethereum. The major of those are: - -- Account abstraction support (accounts may have near-arbitrary validation logic, and also paymaster support is - enabled). -- Deployment transactions require the contracts' bytecode to be passed in a separate field. -- The fee system is somewhat different. - -These require us to extend standard Ethereum transactions with new custom fields. Such extended transactions are called -EIP712 transactions since [EIP712](https://eips.ethereum.org/EIPS/eip-712) is used to sign them. You can look at the -internal structure of the EIP712 transactions -[here](../../../../zk-stack/concepts/transaction-lifecycle.md#eip-712-0x71). - -This document will focus solely on how to pass these arguments to the SDK. - -## Overrides - -`ethers.js` has a notion of overrides. For any on-chain transaction, `ethers.js` finds the optimal `gasPrice`, -`gasLimit`, `nonce`, and other important fields under the hood. But sometimes, you may have a need to explicitly provide -these values (you want to set a smaller `gasPrice` for instance, or sign a transaction with future `nonce`). - -In this case, you can provide an `Overrides` object as the last parameter. There you can supply fields like `gasPrice`, -`gasLimit`, `nonce` etc. - -In order to make the SDK as flexible as possible, `zksync-ethers` uses `customData` object in the overrides to supply -zkSync-specific fields. To supply zkSync-specific fields, you need to pass the following override: - -```typescript -{ - overrides: { - customData: { - gasPerPubdata?: BigNumberish; - factoryDeps?: BytesLike[]; - customSignature?: BytesLike; - paymasterParams?: { - paymaster: Address; - paymasterInput: BytesLike; - }; - } - } -} -``` - -Please note once again: everything that is inside `customData` in `overrides` is related to zkSync(L2 gas, etc). - -Examples: - -Override to deploy a contract with bytecode `0xcde...12` and enforce that the operator will not charge more than `100` -L2 gas per published bytes on Layer 1: - -```typescript -{ - customData: { - gasPerPubdata: "100", - factoryDeps: ["0xcde...12"], - } -} -``` - -Use custom signature `0x123456` for account, while using paymaster with address -`0x8e1DC7E4Bb15927E76a854a92Bf8053761501fdC` and paymaster input `0x8c5a3445`: - -```typescript -{ - customData: { - customSignature: "0x123456", - paymasterParams: { - paymaster: "0x8e1DC7E4Bb15927E76a854a92Bf8053761501fdC", - paymasterInput: "0x8c5a3445" - } - } -} -``` - -## Encoding paymaster params - -While the paymaster feature by itself does not impose any limitations on values of the `paymasterInput`, the Matter Labs -team endorses certain types of -[paymaster flows](../../../developer-reference/account-abstraction.md#built-in-paymaster-flows) that are processable by -EOAs. - -zkSync SDK provides a utility method that can be used to get the correctly formed `paymasterParams` object: -[getPaymasterParams](./paymaster-utils.md#getpaymasterparams). - -## See in action - -If you want to call the method `setGreeting` of an ethers `Contract` object called `greeter`, this would look the -following way, while paying fees with the -[testnet paymaster](../../../developer-reference/account-abstraction.md#testnet-paymaster): - -```ts -// The `setGreeting` method has a single parameter -- new greeting -// We will set its value as `a new greeting`. -const greeting = 'a new greeting'; -const tx = await greeter.populateTransaction.setGreeting(greeting); -const gasPrice = await sender.provider.getGasPrice(); -const gasLimit = await greeter.estimateGas.setGreeting(greeting); -const fee = gasPrice.mul(gasLimit); - -const paymasterParams = utils.getPaymasterParams(testnetPaymaster, { - type: 'ApprovalBased', - token, - minimalAllowance: fee, - innerInput: new Uint8Array(), -}); -const sentTx = await sender.sendTransaction({ - ...tx, - maxFeePerGas: gasPrice, - maxPriorityFeePerGas: 0n, - gasLimit, - customData: { - gasPerPubdata: utils.DEFAULT_GAS_PER_PUBDATA_LIMIT, - paymasterParams, - }, -}); -``` - -You can also check out our [tutorial](../../../quick-start/hello-world.md) on the full-fledged mini-dApp, where users -can choose token to pay the fee. diff --git a/content/20.build/sdks/js/zksync-ethers/front-end.md b/content/20.build/sdks/js/zksync-ethers/front-end.md deleted file mode 100644 index b58ae42f..00000000 --- a/content/20.build/sdks/js/zksync-ethers/front-end.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: JS SDK Front-end Integration | zkSync Docs ---- - -# Front-end Integration - -This section describes how to make the most of zkSync to provide the best UX. - -## Going to production right away - -If your front-end code does not deploy new smart contracts, then no changes to the codebase are required! All the -existing SDKs/infrastructure will work out-of-box. - -## Enabling zkSync features - -If you want to deploy smart contracts or enable advanced zkSync features, like account abstraction, then you need to use -the `zksync-ethers` library. You can read about the basics [here](./features.md). - -If you want to see some code, check out our basic [tutorial](../../../quick-start/hello-world.md) for full mini-dApp. diff --git a/content/20.build/sdks/js/zksync-ethers/getting-started.md b/content/20.build/sdks/js/zksync-ethers/getting-started.md deleted file mode 100644 index 78cd75d1..00000000 --- a/content/20.build/sdks/js/zksync-ethers/getting-started.md +++ /dev/null @@ -1,96 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: JS SDK Getting Started | zkSync Docs ---- - -# Getting Started - -::: info Take a look at [migration guide](migration.md) if you are migrating from `zksync-web3`. ::: - -This is a short introduction to `zksync-ethers` SDK, but covers many of the most common operations that developers -require and provides a starting point for those newer to zkSync Era. - -## Getting zksync-ethers - -### Prerequisites - -- Node: >=v18 ([installation guide](https://nodejs.org/en/download/package-manager)) - -In order to install SDK for zkSync Era, run the command below in your terminal. - -```bash -yarn add zksync-ethers -yarn add ethers@6 # ethers is a peer dependency of zksync-ethers -``` - -## Overview - -While most of the existing SDKs should work out of the box, deploying smart contracts or using unique zkSync features, -like account abstraction, requires providing additional fields to those that Ethereum transactions have by default. - -To begin, it is useful to have a basic understanding of the types of objects available and what they are responsible -for, at a high level: - -- `Provider` provides connection to the zkSync Era blockchain, which allows querying the blockchain state, such as - account, block or transaction details, querying event logs or evaluating read-only code using call. Additionally, the - client facilitates writing to the blockchain by sending transactions. -- `Wallet` wraps all operations that interact with an account. An account generally has a private key, which can be used - to sign a variety of types of payloads. It provides easy usage of the most common features. - -## Examples - -The following examples could be easily run by writing the code snippets in a file and executing them as follows: - -```shell -npx ts-node src/zksync.ts -``` - -Connect to the zkSync Era network: - -```ts -import { Provider, utils, types } from 'zksync-ethers'; -import { ethers } from 'ethers'; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const ethProvider = ethers.getDefaultProvider('sepolia'); -``` - -Get the network (helper function [toJSON](./providers.md#tojson)): - -```ts -console.log(`Network: ${toJSON(await provider.getNetwork())}`); -``` - -Get the latest block number: - -```ts -console.log(`Block number: ${await provider.getBlockNumber()}`); -``` - -Get the block by hash (helper function [toJSON](./providers.md#tojson)): - -```ts -console.log( - `Block: ${toJSON(await provider.getBlock('b472c070c9e121ba42702f6c322b7b266e287a4d8b5fa426ed265b105430c397', true))}` -); -``` - -Get the transaction by hash (helper function [toJSON](./providers.md#tojson)): - -```ts -console.log( - `Block: ${toJSON(await provider.getTransaction('0x9af27afed9a4dd018c0625ea1368afb8ba08e4cfb69b3e76dfb8521c8a87ecfc'))}` -); -``` - -Also, the following examples demonstrate how to: - -1. [Deposit ETH and tokens from Ethereum into zkSync Era](https://github.com/zksync-sdk/zksync2-examples/blob/main/js/src/01_deposit.ts) -2. [Transfer ETH and tokens on zkSync Era](https://github.com/zksync-sdk/zksync2-examples/blob/main/js/src/02_transfer.ts) -3. [Withdraw ETH and tokens from zkSync Era to Ethereum](https://github.com/zksync-sdk/zksync2-examples/blob/main/js/src/04_withdraw.ts) -4. [Use paymaster to pay fee with token](https://github.com/zksync-sdk/zksync2-examples/blob/main/js/src/22_use_paymaster.ts) - -Full code for all examples is available [here](https://github.com/zksync-sdk/zksync2-examples/tree/main/js/src). -Examples are configured to interact with `zkSync Era` and `Sepolia` test networks. diff --git a/content/20.build/sdks/js/zksync-ethers/migration.md b/content/20.build/sdks/js/zksync-ethers/migration.md deleted file mode 100644 index 1061f61b..00000000 --- a/content/20.build/sdks/js/zksync-ethers/migration.md +++ /dev/null @@ -1,38 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: JS SDK Migration | zkSync Docs ---- - -# Migration from `zksync-web3` - -::: tip Note on v5 and v6 - -This migration notes apply to `zksync-ethers v6`. - -If you're using v5, you don't need to do any changes in your code as `zksync-ethers v5` uses `ethers v5` similar to the -deprecated `zksync-web3`. - -::: - -This guide provides some high-level differences between `zksync-web3`/`zksync-ethers v5` and `zksync-ethers v6` for -those who are familiar with `zksync-web3` and need a quick primer. `zksync-ethers v6` has several differences since it's -using `ethers.js v6`, compared to `zksync-web3`, which uses `ethers.js v5`. Before continuing to get to know the changes -made in `zksync-ethers`, you should read the [migration guide](https://docs.ethers.org/v6/migrating/) from -`ethers.js v5` to `ethers.js v6`. - -Differences: - -- `Token.Address` has been removed because it was deprecated. -- `Provider.getMessageProof` has been removed because it was deprecated. -- `Provider.getTokenPrice` has been removed because it was deprecated. -- `Provider.getBlockWithTransaction` has been replaced with `Provider.getBlock(, true)`. -- `BlockWithTransaction` has been removed. -- `TransactionRequest.calldata` has been changed from `BytesLike` to `string`. -- `transaction.calldata` parameter in`Provider.estimateL1ToL2Execute` has been changed from `BytesLike` to `string`. -- `transaction.calldata` parameter in `AdaterL1.getRequestExecuteTx` has been changed from `BytesLike` to `string`. -- `transaction.calldata` parameter in `AdapterL1.estimateGasRequestExecute` has been changed from `BytesLike` to - `string`. -- `transaction.calldata` parameter in `AdapterL1.RequestExecute` has been changed from `BytesLike` to `string`. -- `utils.parseTransaction` has been replaced by `utils.parseEip712`. diff --git a/content/20.build/sdks/js/zksync-ethers/paymaster-utils.md b/content/20.build/sdks/js/zksync-ethers/paymaster-utils.md deleted file mode 100644 index 8791f38e..00000000 --- a/content/20.build/sdks/js/zksync-ethers/paymaster-utils.md +++ /dev/null @@ -1,91 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: JS SDK Paymaster Utilities | zkSync Docs ---- - -# Paymaster Utilities - -The [paymaster utilities library](https://github.com/zksync-sdk/zksync-ethers/blob/main/src/paymaster-utils.ts) contains -essential utilities for using paymasters on zkSync Era. - -## Contract interfaces - -Constant ABI definition for the -[Paymaster Flow Interface](https://github.com/matter-labs/era-contracts/blob/583cb674a2b942dda34e9f46edb5a9f5b696b90a/l2-contracts/contracts/interfaces/IPaymasterFlow.sol). - -```typescript -export const PAYMASTER_FLOW_ABI = new ethers.Interface(require('../abi/IPaymasterFlow.json')); -``` - -## Functions - -### `getApprovalBasedPaymasterInput` - -Returns encoded input for an approval-based paymaster. - -#### Inputs - -| Parameter | Type | Description | -| ---------------- | ----------------------------------------------------------------------- | -------------------------------- | -| `paymasterInput` | [`ApprovalBasedPaymasterInput`](./types.md#approvalbasedpaymasterinput) | The input data to the paymaster. | - -```ts -export function getApprovalBasedPaymasterInput(paymasterInput: ApprovalBasedPaymasterInput): BytesLike; -``` - -### `getGeneralPaymasterInput` - -As above but for general-based paymaster. - -#### Inputs - -| Parameter | Type | Description | -| ---------------- | ----------------------------------------------------------- | -------------------------------- | -| `paymasterInput` | [`GeneralPaymasterInput`](./types.md#generalpaymasterinput) | The input data to the paymaster. | - -```ts -export function getGeneralPaymasterInput(paymasterInput: GeneralPaymasterInput): BytesLike; -``` - -### `getPaymasterParams` - -Returns a correctly-formed `paymasterParams` object for common -[paymaster flows](../../../developer-reference/account-abstraction.md#built-in-paymaster-flows). - -#### Inputs - -| Parameter | Type | Description | -| ------------------ | --------------------------------------------- | --------------------------------- | -| `paymasterAddress` | `Address` | The non-zero `paymaster` address. | -| `paymasterInput` | [`PaymasterInput`](./types.md#paymasterinput) | The input data to the paymaster. | - -```typescript -export function getPaymasterParams(paymasterAddress: Address, paymasterInput: PaymasterInput): PaymasterParams; -``` - -Find out more about the [`PaymasterInput` type](./types.md). - -#### Examples - -Creating `General` paymaster parameters. - -```ts -const paymasterAddress = '0x0a67078A35745947A37A552174aFe724D8180c25'; -const paymasterParams = utils.getPaymasterParams(paymasterAddress, { - type: 'General', - innerInput: new Uint8Array(), -}); -``` - -Creating `ApprovalBased` paymaster parameters. - -```ts -const result = utils.getPaymasterParams('0x0a67078A35745947A37A552174aFe724D8180c25', { - type: 'ApprovalBased', - token: '0x65C899B5fb8Eb9ae4da51D67E1fc417c7CB7e964', - minimalAllowance: BigInt(1), - innerInput: new Uint8Array(), -}); -``` diff --git a/content/20.build/sdks/js/zksync-ethers/providers.md b/content/20.build/sdks/js/zksync-ethers/providers.md deleted file mode 100644 index 4562c5e1..00000000 --- a/content/20.build/sdks/js/zksync-ethers/providers.md +++ /dev/null @@ -1,1407 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: JS SDK Providers | zkSync Docs ---- - -# Providers - -A Web3 Provider object provides application-layer access to underlying blockchain networks. - -The [`zksync-ethers`](https://www.npmjs.com/package/zksync-ethers)) library supports provider methods from the -[`ethers.js`](https://docs.ethers.io/v6/api/providers) library and supplies additional functionality. - -Two providers are available: - -- [`Provider`](#provider): Supplies the same functionality as - [`ethers.JsonRpcProvider`](https://docs.ethers.org/v6/api/providers/jsonrpc/#about-jsonrpcProvider) and extends it - with zkSync-specific methods. -- [`BrowserProvider`](#browserprovider): Extends the zkSync Era [`Provider`](#provider) class to make it more compatible - with Web3 wallets. - -:::tip - -- Use the [`BrowserProvider`](#browserprovider) for browser integrations. -- Access the latest [provider.ts code](https://github.com/zksync-sdk/zksync-ethers/blob/main/src/provider.ts) in the - zkSync Era GitHub repo. ::: - -## `Provider` - -:::info - -- This doc details zkSync Era specific methods. -- Ethers implementations link to the [Ethers Providers documentation](https://docs.ethers.org/v6/api/providers/). ::: - -### `constructor` - -Returns a zkSync Era `Provider` object. - -#### Inputs - -| Parameter | Type | Description | -| ---------- | ------------------------------------------------------------------------------------ | --------------------------- | -| `url?` | [`ethers.FetchRequest`](https://docs.ethers.org/v6/api/utils/fetching/#FetchRequest) | Network RPC URL (optional). | -| `network?` | [`ethers.Networkish`](https://docs.ethers.org/v6/api/providers/#Networkish) | Network name (optional). | -| `options?` | `any` | options (optional). | - -```ts -constructor(url ? : ethers.FetchRequest | string, network ? : Networkish, options ? : any) -``` - -#### Example - -```ts -import { Provider } from 'zksync-ethers'; - -const provider = new Provider('https://sepolia.era.zksync.dev'); -``` - -### `broadcastTransaction` - -Override of [Ethers implementation.](https://docs.ethers.org/v6/api/providers/#Provider-broadcastTransaction) - -#### Inputs - -| Parameter | Type | Description | -| ---------- | -------- | ------------------- | -| `signedTx` | `string` | Signed transaction. | - -```ts -override async broadcastTransaction(signedTx: string): Promise -``` - -#### Example - -```ts -import { Provider, types, Wallet } from 'zksync-ethers'; - -const PRIVATE_KEY = ''; -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const wallet = new Wallet(PRIVATE_KEY, provider, ethProvider); - -const signedTx = await wallet.signTransaction({ - to: '0xa61464658AfeAf65CccaaFD3a512b69A83B77618', - value: ethers.parseEther('0.01'), -}); -const tx = await provider.broadcastTransaction(signedTx); -console.log(tx.hash); -``` - -### `estimateFee` - -Returns an estimated [`Fee`](./types.md#fee) for requested transaction. - -#### Inputs - -| Parameter | Type | Description | -| ------------- | ------------------------------------------------------------------------------------ | -------------------- | -| `transaction` | [`TransactionRequest`](https://docs.ethers.org/v6/api/providers/#TransactionRequest) | Transaction request. | - -```ts -async estimateFee([`TransactionRequest`](https://docs.ethers.org/v6/api/providers/#TransactionRequest)): Promise -``` - -Helper function: [toJSON](#tojson). - -```ts -import { Provider, types } from 'zksync-ethers'; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const fee = await provider.estimateFee({ - from: '0x36615Cf349d7F6344891B1e7CA7C72883F5dc049', - to: '0xa61464658AfeAf65CccaaFD3a512b69A83B77618', - value: `0x${BigInt(7_000_000_000).toString(16)}`, -}); -console.log(`Fee: ${toJSON(fee)}`); -``` - -### `estimateGas` - -Returns an estimate of the amount of gas required to submit a transaction to the network. - -#### Inputs - -| Parameter | Type | Description | -| --------- | ------------------------------------------------------------------------------------ | -------------------- | -| `_tx` | [`TransactionRequest`](https://docs.ethers.org/v6/api/providers/#TransactionRequest) | Transaction request. | - -```ts -async estimateGas(_tx: TransactionRequest): Promise -``` - -#### Example - -```ts -import { Provider, types, utils } from 'zksync-ethers'; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const gasTokenApprove = await provider.estimateGas({ - from: '0x36615Cf349d7F6344891B1e7CA7C72883F5dc049', - to: '0x765F5AF819D818a8e8ee6ff63D8d0e8056DBE150', - data: utils.IERC20.encodeFunctionData('approve', [RECEIVER, 1]), -}); -console.log(`Gas for token approval tx: ${gasTokenApprove}`); -``` - -```ts -import { Provider, types, utils } from 'zksync-ethers'; - -const ADDRESS = '0x36615Cf349d7F6344891B1e7CA7C72883F5dc049'; -const RECEIVER = '0xa61464658AfeAf65CccaaFD3a512b69A83B77618'; -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const tokenAddress = '0x927488F48ffbc32112F1fF721759649A89721F8F'; // Crown token which can be minted for free -const paymasterAddress = '0x13D0D8550769f59aa241a41897D4859c87f7Dd46'; // Paymaster for Crown token - -const paymasterParams = utils.getPaymasterParams(paymasterAddress, { - type: 'ApprovalBased', - token: tokenAddress, - minimalAllowance: 1, - innerInput: new Uint8Array(), -}); - -const tokenApprove = await provider.estimateGas({ - from: ADDRESS, - to: tokenAddress, - data: utils.IERC20.encodeFunctionData('approve', [RECEIVER, 1]), - customData: { - gasPerPubdata: utils.DEFAULT_GAS_PER_PUBDATA_LIMIT, - paymasterParams, - }, -}); -console.log(`Gas for token approval using EIP-712 tx: ${tokenApprove}`); -``` - -### `estimateGasL1` - -Returns an estimate of the amount of gas required to submit a transaction from L1 to L2 as a `bigint` object. - -Calls the [`zks_estimateL1ToL2`](../../../api.md#zks-estimategasl1tol2) JSON-RPC method. - -#### Inputs - -| Parameter | Type | Description | -| ------------- | ----------------------------------------------------- | -------------------- | -| `transaction` | [`TransactionRequest`](./types.md#transactionrequest) | Transaction request. | - -```ts -async estimateGasL1(transaction: TransactionRequest): Promise -``` - -#### Example - -```ts -import { Provider, types } from 'zksync-ethers'; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const gasL1 = await provider.estimateGasL1({ - from: '0x36615Cf349d7F6344891B1e7CA7C72883F5dc049', - to: await provider.getMainContractAddress(), - value: 7_000_000_000, - customData: { - gasPerPubdata: 800, - }, -}); -console.log(`L1 gas: ${BigInt(gasL1)}`); -``` - -### `estimateGasTransfer` - -Returns the gas estimation for a transfer transaction. - -Calls internal method [`getTransferTx`](#gettransfertx) to get the transfer transaction and sends it to the -[`estimateGas`](#estimategas) method. - -#### Inputs - -| Parameter | Type | Description | -| ------------------ | ------------------------------------------------------------------------ | ----------------------------------- | -| `token` | `Address` | Token address. | -| `amount` | `BigNumberish` | Amount of token. | -| `from?` | `Address` | From address (optional). | -| `to?` | `Address` | To address (optional). | -| `paymasterParams?` | [`PaymasterParams`](./types.md#paymasterparams) | Paymaster parameters (optional). | -| `overrides?` | [`ethers.Overrides`](https://docs.ethers.org/v6/api/contract/#Overrides) | Ethers overrides object (optional). | - -```ts -async estimateGasTransfer(transaction: { - to: Address; - amount: BigNumberish; - from ? : Address; - token ? : Address; - paymasterParams ?: PaymasterParams; - overrides ? : ethers.Overrides; -}): Promise -``` - -#### Example - -```ts -import { Provider, types, utils } from 'zksync-ethers'; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const gasTransfer = await provider.estimateGasTransfer({ - token: utils.ETH_ADDRESS, - amount: 7_000_000_000, - to: '0xa61464658AfeAf65CccaaFD3a512b69A83B77618', - from: '0x36615Cf349d7F6344891B1e7CA7C72883F5dc049', -}); -console.log(`Gas for transfer tx: ${gasTransfer}`); -``` - -### `estimateGasWithdraw` - -Returns the gas estimation for a withdrawal transaction. - -Calls internal method [`getWithdrawTx`](#getwithdrawtx) to get the withdrawal transaction and sends it to the -[`estimateGas`](#estimategas) method. - -#### Inputs - -| Parameter | Type | Description | -| ------------------ | ------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------- | -| `token` | `Address` | Token address. | -| `amount` | `BigNumberish` | Amount of token. | -| `from?` | `Address` | From address (optional). | -| `to?` | `Address` | To address (optional). | -| `bridgeAddress?` | `Address` | Bridge address (optional). | -| `paymasterParams?` | [`PaymasterParams`](./types.md#paymasterparams) | Paymaster parameters (optional). | -| `overrides?` | [`ethers.Overrides`](https://docs.ethers.org/v6/api/contract/#Overrides) | Transaction's overrides which may be used to pass l2 `gasLimit`, `gasPrice`, `value`, etc (optional). . | - -```ts -async estimateGasWithdraw(transaction: { - token: Address; - amount: BigNumberish; - from ? : Address; - to ? : Address; - bridgeAddress ? : Address; - paymasterParams ?: PaymasterParams; - overrides ? : ethers.Overrides; -}): Promise -``` - -#### Example - -```ts -import { Provider, types, utils } from 'zksync-ethers'; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const gasWithdraw = await provider.estimateGasWithdraw({ - token: utils.ETH_ADDRESS, - amount: 7_000_000, - to: '0x36615Cf349d7F6344891B1e7CA7C72883F5dc049', - from: '0x36615Cf349d7F6344891B1e7CA7C72883F5dc049', -}); -console.log(`Gas for withdrawal tx: ${gasWithdraw}`); -``` - -### `estimateL1ToL2Execute` - -Returns gas estimation for an L1 to L2 execute operation. - -#### Inputs - -| Parameter | Type | Description | -| -------------------- | ------------------ | ----------------------------------------------------------------------------------------------------- | -| `contractAddress` | `Address` | Address of contract. | -| `calldata` | `string` | The transaction call data. | -| `caller?` | `Address` | Caller address (optional). | -| `l2Value?` | `BigNumberish` | Current L2 gas value (optional). | -| `factoryDeps?` | `BytesLike[]` | Byte array containing contract bytecode. | -| `gasPerPubdataByte?` | `BigNumberish` | Constant representing current amount of gas per byte (optional). | -| `overrides?` | `ethers.Overrides` | Transaction's overrides which may be used to pass l2 `gasLimit`, `gasPrice`, `value`, etc (optional). | - -```ts -async estimateL1ToL2Execute(transaction: { - contractAddress: Address; - calldata: string; - caller ? : Address; - l2Value ? : BigNumberish; - factoryDeps ? : ethers.BytesLike[]; - gasPerPubdataByte ? : BigNumberish; - overrides ? : ethers.Overrides; -}): Promise -``` - -#### Example - -```ts -import { Provider, types } from 'zksync-ethers'; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const gasL1ToL2 = await provider.estimateL1ToL2Execute({ - contractAddress: await provider.getMainContractAddress(), - calldata: '0x', - caller: '0x36615Cf349d7F6344891B1e7CA7C72883F5dc049', - l2Value: 7_000_000_000, -}); -console.log(`Gas L1 to L2: ${BigInt(gasL1ToL2)}`); -``` - -### `getAllAccountBalances` - -Returns all balances for confirmed tokens given by an account address. - -Calls the [`zks_getAllAccountBalances`](../../../api.md#zks-getallaccountbalances) JSON-RPC method. - -#### Inputs - -| Parameter | Type | Description | -| --------- | --------- | ---------------- | -| `address` | `Address` | Account address. | - -```ts -async getAllAccountBalances(address: Address): Promise -``` - -#### Example - -Helper function: [toJSON](#tojson). - -```ts -import { Provider, types } from 'zksync-ethers'; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const balances = await provider.getAllAccountBalances('0x36615Cf349d7F6344891B1e7CA7C72883F5dc049'); -console.log(`All balances: ${toJSON(balances)}`); -``` - -### `getBalance` - -Returns the user's balance as a `bigint` object for an (optional) block tag and (optional) token. - -When block and token are not supplied, `committed` and `ETH` are the default values. - -#### Inputs - -| Parameter | Type | Description | -| --------------- | ---------- | ------------------------------------------------------------------------------------- | -| `address` | `Address` | Account address. | -| `blockTag?` | `BlockTag` | Block tag for getting the balance on. Latest `committed` block is default (optional). | -| `tokenAddress?` | `Address` | Token address. ETH is default (optional). | - -```ts -async getBalance(address: Address, blockTag?: BlockTag, tokenAddress?: Address) -``` - -#### Example - -```ts -import { Provider, types } from 'zksync-ethers'; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const account = '0x36615Cf349d7F6344891B1e7CA7C72883F5dc049'; -const tokenAddress = '0x927488F48ffbc32112F1fF721759649A89721F8F'; // Crown token which can be minted for free -console.log(`ETH balance: ${await provider.getBalance(account)}`); -console.log(`Token balance: ${await provider.getBalance(account, 'latest', tokenAddres)}`); -``` - -### `getBlock` - -Returns block from the network, or false if there is no block. - -#### Inputs - -| Parameter | Type | Description | -| --------------------- | ---------- | ----------------------------------------------------------- | -| `blockHashOrBlockTag` | `BlockTag` | Block tag for getting the balance on. | -| `includeTxs?` | `boolean` | Whether to fetch transactions that are in block (optional). | - -```ts -async getBlock(blockHashOrBlockTag: BlockTag, includeTxs?: boolean): Promise -``` - -#### Example - -Helper function: [toJSON](#tojson). - -```ts -import { Provider, types } from 'zksync-ethers'; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -console.log(`Block: ${toJSON(await provider.getBlock('latest', true))}`); -``` - -### `getBlockDetails` - -Returns additional zkSync-specific information about the L2 block. - -Calls the [`zks_getBlockDetails`](../../../api.md#zks-getblockdetails) JSON-RPC method. - -#### Inputs - -| Parameter | Type | Description | -| --------- | -------- | ------------- | -| `number` | `number` | Block number. | - -```ts -async getBlockDetails(number:number): Promise -``` - -#### Example - -Helper function: [toJSON](#tojson). - -```ts -import { Provider, types } from 'zksync-ethers'; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -console.log(`Block details: ${toJSON(await provider.getBlockDetails(90_000))}`); -``` - -### `getBytecodeByHash` - -Returns bytecode of a contract given by its hash. - -Calls the [`zks_getBytecodeByHash`](../../../api.md#zks-getbytecodebyhash) JSON-RPC method. - -#### Inputs - -| Parameter | Type | Description | -| -------------- | ----------- | -------------- | -| `bytecodeHash` | `BytesLike` | Bytecode hash. | - -```ts -async getBytecodeByHash(bytecodeHash: BytesLike): Promise -``` - -#### Example - -```ts -import { Provider, types } from 'zksync-ethers'; - -// Bytecode hash can be computed by following these steps: -// const testnetPaymasterBytecode = await provider.getCode(await provider.getTestnetPaymasterAddress()); -// const testnetPaymasterBytecodeHash = ethers.hexlify(utils.hashBytecode(testnetPaymasterBytecode)); - -const testnetPaymasterBytecodeHash = '0x010000f16d2b10ddeb1c32f2c9d222eb1aea0f638ec94a81d4e916c627720e30'; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -console.log(`Bytecode: ${await provider.getBytecodeByHash(testnetPaymasterBytecodeHash)}`); -``` - -### `getContractAccountInfo` - -Returns the version of the supported account abstraction and nonce ordering from a given contract address. - -#### Inputs - -| Parameter | Type | Description | -| --------- | --------- | ----------------- | -| `address` | `Address` | Contract address. | - -```ts -async getContractAccountInfo(address:Address): Promise -``` - -#### Example - -Helper function: [toJSON](#tojson). - -```ts -import { Provider, types } from 'zksync-ethers'; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const tokenAddress = '0x927488F48ffbc32112F1fF721759649A89721F8F'; // Crown token which can be minted for free -console.log(`Contract account info: ${toJSON(await provider.getContractAccountInfo(tokenAddress))}`); -``` - -### `getDefaultBridgeAddresses` - -Returns the addresses of the default zkSync Era bridge contracts on both L1 and L2. - -```ts -async getDefaultBridgeAddresses(): Promise<{erc20L1: string, erc20L2: string, wethL1: string, wethL2: string}>; -``` - -#### Example - -Helper function: [toJSON](#tojson). - -```ts -import { Provider, types } from 'zksync-ethers'; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -console.log(`Default bridges: ${toJSON(await provider.getDefaultBridgeAddresses())}`); -``` - -### `getDefaultProvider` - -Static method which returns a Provider object from the RPC URL or localhost. - -#### Inputs - -| Parameter | Type | Description | -| --------------- | ------------------------------------- | ------------------------------------------------- | -| `zksyncNetwork` | [`ZkSyncNetwork`](./types.md#network) | Type of zkSync network. `Localhost` _by default_. | - -```ts -static getDefaultProvider(zksyncNetwork: ZkSyncNetwork = ZkSyncNetwork.Localhost) -``` - -#### Example - -```ts -import { Provider, types } from 'zksync-ethers'; - -const providerMainnet = Provider.getDefaultProvider(types.Network.Mainnet); -const providerTestnet = Provider.getDefaultProvider(types.Network.Sepolia); -const providerLocalnet = Provider.getDefaultProvider(types.Network.Localhost); -``` - -### `getFilterChanges` - -Returns an array of logs by calling Ethereum method -[`eth_getFilterChanges`.](https://ethereum.github.io/execution-apis/api-documentation/) - -#### Inputs - -| Parameter | Type | Description | -| --------- | -------- | ------------- | -| `idx` | `bigint` | Filter index. | - -```ts -async getFilterChanges(idx: bigint): Promise> -``` - -#### Example - -```ts -import { Provider, types, utils } from 'zksync-ethers'; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const filter = await provider.newFilter({ - address: utils.L2_ETH_TOKEN_ADDRESS, - topics: [ethers.id('Transfer(address,address,uint256)')], -}); -const result = await provider.getFilterChanges(filter); -``` - -### `getGasPrice` - -Returns an estimate (best guess) of the gas price to use in a transaction. - -```ts -async getGasPrice(): Promise -``` - -#### Example - -```ts -import { Provider, types } from 'zksync-ethers'; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -console.log(`Gas price: ${await provider.getGasPrice()}`); -``` - -### `getL1BatchBlockRange` - -Returns the range of blocks contained within a batch given by batch number. - -Calls the [`zks_getL1BatchBlockRange`](../../../api.md#zks-getl1batchblockrange) JSON-RPC method. - -#### Inputs - -| Parameter | Type | Description | -| --------------- | -------- | ---------------- | -| `l1BatchNumber` | `number` | L1 batch number. | - -```ts -async getL1BatchBlockRange(l1BatchNumber: number): Promise<[number, number] | null> -``` - -#### Example - -Helper function: [toJSON](#tojson). - -```ts -import { Provider, types } from 'zksync-ethers'; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const l1BatchNumber = await provider.getL1BatchNumber(); -console.log(`L1 batch block range: ${toJSON(await provider.getL1BatchBlockRange(l1BatchNumber))}`); -``` - -### `getL1BatchDetails` - -Returns data pertaining to a given batch. - -Calls the [`zks_getL1BatchDetails`](../../../api.md#zks-getl1batchdetails) JSON-RPC method. - -#### Inputs - -| Parameter | Type | Description | -| --------- | -------- | ---------------- | -| `number` | `number` | L1 batch number. | - -```ts -async getL1BatchDetails(number: number): Promise -``` - -#### Example - -Helper function: [toJSON](#tojson). - -```ts -import { Provider, types } from 'zksync-ethers'; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const l1BatchNumber = await provider.getL1BatchNumber(); -console.log(`L1 batch details: ${toJSON(await provider.getL1BatchDetails(l1BatchNumber))}`); -``` - -### `getL1BatchNumber` - -Returns the latest L1 batch number. - -Calls the [`zks_getL1BatchNumber`](../../../api.md#zks-l1batchnumber) JSON-RPC method. - -```ts -async getL1BatchNumber(): Promise -``` - -#### Example - -```ts -import { Provider, types } from 'zksync-ethers'; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -console.log(`L1 batch number: ${await provider.getL1BatchNumber()}`); -``` - -### `getL2TransactionFromPriorityOp` - -Returns a L2 transaction from L1 transaction response. - -#### Inputs - -| Parameter | Type | Description | -| -------------- | -------------------------------------------------------------------------------------- | ------------------------ | -| `l1TxResponse` | [`TransactionResponse`](https://docs.ethers.org/v6/api/providers/#TransactionResponse) | L1 transaction response. | - -```ts -async getL2TransactionFromPriorityOp(l1TxResponse: ethers.TransactionResponse): Promise -``` - -#### Example - -Helper function: [toJSON](#tojson). - -```ts -import { Provider, types } from 'zksync-ethers'; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const ethProvider = ethers.getDefaultProvider('sepolia'); -const l1Tx = '0xcca5411f3e514052f4a4ae1c2020badec6e0998adb52c09959c5f5ff15fba3a8'; -const l1TxResponse = await ethProvider.getTransaction(l1Tx); -if (l1TxResponse) { - console.log(`Tx: ${toJSON(await provider.getL2TransactionFromPriorityOp(l1TxResponse))}`); -} -``` - -### `getLogProof` - -Returns the proof for a transaction's L2 to L1 log sent via the L1Messenger system contract. - -Calls the [`zks_getL2ToL1LogProof`](../../../api.md#zks-getl2tol1logproof) JSON-RPC method. - -#### Inputs - -| Parameter | Type | Description | -| --------- | ----------- | ---------------------------------------------------------------- | -| `txHash` | `BytesLike` | Hash of the L2 transaction the L2 to L1 log was produced within. | -| `index?` | `number` | The index of the L2 to L1 log in the transaction (optional). | - -```ts -async getLogProof(txHash: BytesLike, index ? : number): Promise -``` - -#### Example - -Helper function: [toJSON](#tojson). - -```ts -import { Provider, types } from 'zksync-ethers'; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -// Any L2 -> L1 transaction can be used. -// In this case, withdrawal transaction is used. -const tx = '0x2a1c6c74b184965c0cb015aae9ea134fd96215d2e4f4979cfec12563295f610e'; -console.log(`Log ${toJSON(await provider.getLogProof(tx, 0))}`); -``` - -### `getLogs` - -Returns an array of all logs that match a filter with a given id by calling Ethereum method -[`eth_getLogs.`](https://ethereum.github.io/execution-apis/api-documentation/) - -#### Inputs - -| Parameter | Type | Description | -| --------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- | -| `filter` | [`Filter`](https://docs.ethers.org/v6/api/providers/#Filter) or [`FilterByBlockHash`](https://docs.ethers.org/v6/api/providers/#FilterByBlockHash) | Filter query. | - -```ts -async getLogs(filter: Filter | FilterByBlockHash): Promise -``` - -#### Example - -Helper function: [toJSON](#tojson). - -```ts -import { Provider, types, utils } from 'zksync-ethers'; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -console.log( - `Logs: ${toJSON(await provider.getLogs({ fromBlock: 0, toBlock: 5, address: utils.L2_ETH_TOKEN_ADDRESS }))}` -); -``` - -### `getMainContractAddress` - -Returns the main zkSync Era smart contract address. - -Calls the [`zks_getMainContract`](../../../api.md#zks-getmaincontract) JSON-RPC method. - -```ts -async getMainContractAddress(): Promise
-``` - -#### Example - -Helper function: [toJSON](#tojson). - -```ts -import { Provider, types } from 'zksync-ethers'; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -console.log(`Main contract: ${await provider.getMainContractAddress()}`); -``` - -### `getPriorityOpResponse` - -Returns a [`TransactionResponse`](https://docs.ethers.org/v6/api/providers/#TransactionResponse) as a -`PriorityOpResponse` object. - -#### Inputs - -| Parameter | Type | Description | -| -------------- | -------------------------------------------------------------------------------------- | ------------------------ | -| `l1TxResponse` | [`TransactionResponse`](https://docs.ethers.org/v6/api/providers/#TransactionResponse) | L1 transaction response. | - -```ts -async getPriorityOpResponse(l1TxResponse: ethers.TransactionResponse): Promise -``` - -#### Example - -Helper function: [toJSON](#tojson). - -```ts -import { Provider, types } from 'zksync-ethers'; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const ethProvider = ethers.getDefaultProvider('sepolia'); -const l1Tx = '0xcca5411f3e514052f4a4ae1c2020badec6e0998adb52c09959c5f5ff15fba3a8'; -const l1TxResponse = await ethProvider.getTransaction(l1Tx); -if (l1TxResponse) { - console.log(`Tx: ${toJSON(await provider.getPriorityOpResponse(l1TxResponse))}`); -} -``` - -### `getProof` - -Returns Merkle [`proofs`](./types.md#storageproof) for one or more storage values at the specified account along with a -Merkle proof of their authenticity. - -Calls the [`zks_getProof`](../../../api.md#zks-getproof) JSON-RPC method. - -#### Inputs - -| Parameter | Type | Description | -| --------------- | ---------- | ----------------------------------------------------------------------------------------------- | -| `address` | `Address` | The account to fetch storage values and proofs for. | -| `keys` | `string[]` | Vector of storage keys in the account. | -| `l1BatchNumber` | `number` | Number of the L1 batch specifying the point in time at which the requested values are returned. | - -```ts -async getProof(address: Address, keys: string[], l1BatchNumber: number): Promise -``` - -#### Example - -Helper function: [toJSON](#tojson). - -```ts -import { Provider, types, utils } from 'zksync-ethers'; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const address = '0x082b1BB53fE43810f646dDd71AA2AB201b4C6b04'; - -// Fetching the storage proof for rawNonces storage slot in NonceHolder system contract. -// mapping(uint256 => uint256) internal rawNonces; - -// Ensure the address is a 256-bit number by padding it -// because rawNonces slot uses uint256 for mapping addresses and their nonces. -const addressPadded = ethers.zeroPadValue(address, 32); - -// Convert the slot number to a hex string and pad it to 32 bytes. -const slotPadded = ethers.zeroPadValue(ethers.toBeHex(0), 32); - -// Concatenate the padded address and slot number. -const concatenated = addressPadded + slotPadded.slice(2); // slice to remove '0x' from the slotPadded - -// Hash the concatenated string using Keccak-256. -const storageKey = ethers.keccak256(concatenated); - -const l1BatchNumber = await provider.getL1BatchNumber(); -const storageProof = await provider.getProof(utils.NONCE_HOLDER_ADDRESS, [storageKey], l1BatchNumber); -console.log(`Storage proof: ${toJSON(storageProof)}`); -``` - -### `getRawBlockTransactions` - -Returns data of transactions in a block. - -Calls the [`zks_getRawBlockTransactions`](../../../api.md#zks-getrawblocktransactions) JSON-RPC method. - -#### Inputs - -| Parameter | Type | Description | -| --------- | -------- | ------------- | -| `number` | `number` | Block number. | - -```ts -async getRawBlockTransactions(number: number): Promise -``` - -#### Example - -Helper function: [toJSON](#tojson). - -```ts -import { Provider, types } from 'zksync-ethers'; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -console.log(`Raw block transactions: ${toJSON(await provider.getRawBlockTransactions(90_000))}`); -``` - -### `getTestnetPaymasterAddress` - -Returns the [testnet paymaster](../../../developer-reference/account-abstraction.md#paymasters) address if available, or -null. - -```ts -async getTestnetPaymasterAddress(): Promise
-``` - -#### Example - -```ts -import { Provider, types } from 'zksync-ethers'; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -console.log(`Testnet paymaster: ${await provider.getTestnetPaymasterAddress()}`); -``` - -### `getTransaction` - -Returns a specified L2 transaction response object by overriding the -[Ethers implementation](https://docs.ethers.org/v5/api/providers/provider/#Provider-getTransaction). - -#### Inputs - -| Parameter | Type | Description | -| --------- | -------- | ----------------- | -| `txHash` | `string` | Transaction hash. | - -```ts -override async getTransaction(txHash: string): Promise -``` - -#### Example - -```ts -import { Provider, types } from 'zksync-ethers'; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); - -const TX_HASH = ''; -const txHandle = await provider.getTransaction(TX_HASH); - -// Wait until the transaction is processed by the server. -await txHandle.wait(); -// Wait until the transaction is finalized. -await txHandle.waitFinalize(); -``` - -### `getTransactionDetails` - -Returns data from a specific transaction given by the transaction hash. - -Calls the [`getTransactionDetails`](../../../api.md#zks-gettransactiondetails) JSON-RPC method. - -#### Inputs - -| Parameter | Type | Description | -| --------- | ----------- | ----------------- | -| `txHash` | `BytesLike` | Transaction hash. | - -```ts -async getTransactionDetails(txHash: BytesLike): Promise -``` - -#### Example - -Helper function: [toJSON](#tojson). - -```ts -import { Provider, types } from 'zksync-ethers'; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); - -const TX_HASH = ''; -console.log(`Transaction details: ${toJSON(await provider.getTransactionDetails(TX_HASH))}`); -``` - -### `getTransactionReceipt` - -Returns the transaction receipt from a given hash number. - -[Ethers implementation.](https://docs.ethers.org/v5/api/providers/provider/#Provider-getTransactionReceipt) - -#### Inputs - -| Parameter | Type | Description | -| --------- | -------- | ----------------- | -| `txHash` | `string` | Transaction hash. | - -```ts -async getTransactionReceipt(txHash: string): Promise -``` - -#### Example - -Helper function: [toJSON](#tojson). - -```ts -import { Provider, types } from 'zksync-ethers'; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const TX_HASH = ''; -console.log(`Transaction receipt: ${toJSON(await provider.getTransactionReceipt(TX_HASH))}`); -``` - -### `getTransactionStatus` - -Returns the status of a specified transaction. - -#### Inputs - -| Parameter | Type | Description | -| --------- | -------- | ----------------- | -| `txHash` | `string` | Transaction hash. | - -```ts -async getTransactionStatus(txHash: string): Promise -``` - -#### Example - -Helper function: [toJSON](#tojson). - -```ts -import { Provider, types } from 'zksync-ethers'; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); - -const TX_HASH = ''; -console.log(`Transaction status: ${toJSON(await provider.getTransactionStatus(TX_HASH))}`); -``` - -### `getTransferTx` - -Returns the populated transfer transaction. - -#### Inputs - -| Parameter | Type | Description | -| ------------------ | ------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------- | -| `token` | `Address` | Token address. | -| `amount` | `BigNumberish` | Amount of token. | -| `from?` | `Address` | From address (optional). | -| `to?` | `Address` | To address (optional). | -| `paymasterParams?` | [`PaymasterParams`](./types.md#paymasterparams) | Paymaster parameters (optional). | -| `overrides?` | [`ethers.Overrides`](https://docs.ethers.org/v6/api/contract/#Overrides) | Transaction's overrides which may be used to pass l2 `gasLimit`, `gasPrice`, `value`, etc (optional). | - -```ts -async getTransferTx(transaction: { - to: Address; - amount: BigNumberish; - from ? : Address; - token ? : Address; - paymasterParams?: PaymasterParams; - overrides ? : ethers.Overrides; -}): Promise -``` - -#### Examples - -Retrieve populated ETH transfer transaction. - -```ts -import { Provider, types, utils } from 'zksync-ethers'; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); - -const tx = await provider.getTransferTx({ - token: utils.ETH_ADDRESS, - amount: 7_000_000_000, - to: '0xa61464658AfeAf65CccaaFD3a512b69A83B77618', - from: '0x36615Cf349d7F6344891B1e7CA7C72883F5dc049', -}); -console.log(`Transfer tx: ${tx}`); -``` - -Retrieve populated ETH transfer transaction using paymaster to facilitate fee payment with an ERC20 token. - -```ts -import { Provider, types, utils } from 'zksync-ethers'; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const token = '0x927488F48ffbc32112F1fF721759649A89721F8F'; // Crown token which can be minted for free -const paymaster = '0x13D0D8550769f59aa241a41897D4859c87f7Dd46'; // Paymaster for Crown token - -const tx = await provider.getTransferTx({ - token: utils.ETH_ADDRESS, - amount: 7_000_000_000, - to: '0xa61464658AfeAf65CccaaFD3a512b69A83B77618', - from: '0x36615Cf349d7F6344891B1e7CA7C72883F5dc049', - paymasterParams: utils.getPaymasterParams(paymaster, { - type: 'ApprovalBased', - token: token, - minimalAllowance: 1, - innerInput: new Uint8Array(), - }), -}); -console.log(`Transfer tx: ${tx}`); -``` - -### `getWithdrawTx` - -Returns the populated withdrawal transaction. - -#### Inputs - -| Parameter | Type | Description | -| ------------------ | ------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------- | -| `token` | `Address` | Token address. | -| `amount` | `BigNumberish` | Amount of token. | -| `from?` | `Address` | From address (optional). | -| `to?` | `Address` | To address (optional). | -| `bridgeAddress?` | `Address` | Bridge address (optional). | -| `paymasterParams?` | [`PaymasterParams`](./types.md#paymasterparams) | Paymaster parameters (optional). | -| `overrides?` | [`ethers.Overrides`](https://docs.ethers.org/v6/api/contract/#Overrides) | Transaction's overrides which may be used to pass l2 `gasLimit`, `gasPrice`, `value`, etc (optional). | - -```ts -async getWithdrawTx(transaction: { - token: Address; - amount: BigNumberish; - from ? : Address; - to ? : Address; - bridgeAddress ? : Address; - paymasterParams?: PaymasterParams; - overrides ? : ethers.Overrides; -}): Promise -``` - -#### Examples - -Retrieve populated ETH withdrawal transactions. - -```ts -import { Provider, types, utils } from 'zksync-ethers'; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); - -const tx = await provider.getWithdrawTx({ - token: utils.ETH_ADDRESS, - amount: 7_000_000_000, - to: '0x36615Cf349d7F6344891B1e7CA7C72883F5dc049', - from: '0x36615Cf349d7F6344891B1e7CA7C72883F5dc049', -}); -console.log(`Withdrawal tx: ${tx}`); -``` - -Retrieve populated ETH withdrawal transaction using paymaster to facilitate fee payment with an ERC20 token. - -```ts -import { Provider, types, utils } from 'zksync-ethers'; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -const token = '0x927488F48ffbc32112F1fF721759649A89721F8F'; // Crown token which can be minted for free -const paymaster = '0x13D0D8550769f59aa241a41897D4859c87f7Dd46'; // Paymaster for Crown token - -const tx = await provider.getWithdrawTx({ - token: utils.ETH_ADDRESS, - amount: 7_000_000_000, - to: '0x36615Cf349d7F6344891B1e7CA7C72883F5dc049', - from: '0x36615Cf349d7F6344891B1e7CA7C72883F5dc049', - paymasterParams: utils.getPaymasterParams(paymaster, { - type: 'ApprovalBased', - token: token, - minimalAllowance: 1, - innerInput: new Uint8Array(), - }), -}); -console.log(`Withdrawal tx: ${tx}`); -``` - -### `l1ChainId` - -Returns the chain id of the underlying L1. - -Calls the [`zks_L1ChainId`](../../../api.md#zks-L1ChainId) JSON-RPC method. - -```ts -async l1ChainId(): Promise -``` - -#### Example - -```ts -import { Provider, types } from 'zksync-ethers'; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -console.log(`L1 chain ID: ${await provider.l1ChainId()}`); -``` - -### `l1TokenAddress` - -Returns the L1 token address equivalent for a L2 token address as they are not equal. ETH's address is set to zero -address. - -:::warning Only works for tokens bridged on default zkSync Era bridges. ::: - -#### Inputs - -| Parameter | Type | Description | -| --------- | --------- | ------------------------------- | -| `token` | `Address` | The address of the token on L2. | - -```ts -async l1TokenAddress(token: Address): Promise -``` - -#### Example - -```ts -import { Provider, types } from 'zksync-ethers'; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -console.log(`L1 token address: ${await provider.l1TokenAddress('0x3e7676937A7E96CFB7616f255b9AD9FF47363D4b')}`); -``` - -### `l2TokenAddress` - -Returns the L2 token address equivalent for a L1 token address as they are not equal. ETH's address is set to zero -address. - -:::warning Only works for tokens bridged on default zkSync Era bridges. ::: - -#### Inputs - -| Parameter | Type | Description | -| --------- | --------- | ------------------------------- | -| `token` | `Address` | The address of the token on L1. | - -```ts -async l2TokenAddress(token: Address): Promise -``` - -#### Example - -```ts -import { Provider, types } from 'zksync-ethers'; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -console.log(`L2 token address: ${await provider.l2TokenAddress('0x5C221E77624690fff6dd741493D735a17716c26B')}`); -``` - -### `newBlockFilter` - -Returns a new block filter by calling Ethereum method -[`eth_newBlockFilter.`](https://ethereum.github.io/execution-apis/api-documentation/) - -```ts -async newBlockFilter(): Promise -``` - -#### Example - -```ts -import { Provider, types } from 'zksync-ethers'; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -console.log(`New block filter: ${await provider.newBlockFilter()}`); -``` - -### `newFilter` - -Returns a new filter by calling Ethereum method -[`eth_newFilter`](https://ethereum.github.io/execution-apis/api-documentation/) and passing a filter object. - -#### Inputs - -| Parameter | Type | Description | -| --------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- | -| `filter` | [`FilterByBlockHash`](https://docs.ethers.org/v6/api/providers/#FilterByBlockHash) or [`Filter`](https://docs.ethers.org/v6/api/providers/#Filter) | Filter query. | - -```ts -async newFilter(filter: FilterByBlockHash | Filter): Promise -``` - -#### Example - -```ts -import { Provider, types, utils } from 'zksync-ethers'; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -console.log( - `New filter: ${await provider.newFilter({ - fromBlock: 0, - toBlock: 5, - address: utils.L2_ETH_TOKEN_ADDRESS, - })}` -); -``` - -### `newPendingTransactionFilter` - -Returns a new pending transaction filter by calling Ethereum method -[`eth_newPendingTransactionFilter`](https://ethereum.github.io/execution-apis/api-documentation/) and passing a filter -object. - -```ts -async newPendingTransactionsFilter(): Promise -``` - -#### Example - -```ts -import { Provider, types } from 'zksync-ethers'; - -const provider = Provider.getDefaultProvider(types.Network.Sepolia); -console.log(`New pending transaction filter: ${await provider.newPendingTransactionsFilter()}`); -``` - -## `BrowserProvider` - -Use this provider for Web3 browser wallet integrations for easy compatibility with Metamask, WalletConnect, and other -popular browser wallets. - -### `constructor` - -Returns a provider object by extending the constructor of the `Provider` class and accepting an `Eip1193Provider` -instead of a node URL. - -#### Inputs - -| Parameter | Type | Description | -| ---------- | ------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------- | -| `ethereum` | [`Eip1193Provider`](https://docs.ethers.org/v6/api/providers/#Eip1193Provider) | The `Eip1193Provider` class instance. For instance, Metamask is `window.ethereum`. | -| `network?` | [`Networkish`](https://docs.ethers.org/v6/api/providers/#Networkish) | Network name (optional). | - -```ts -constructor(ethereum: Eip1193Provider, network?: Networkish) -``` - -#### Example - -```ts -import { BrowserProvider } from 'zksync-ethers'; - -const provider = new BrowserProvider(window.ethereum); -``` - -### `estimateGas` - -Returns gas estimate by overriding the zkSync Era [`estimateGas`](#estimategas) method. - -#### Inputs - -| Parameter | Type | Description | -| ------------- | ----------------------------------------------------- | -------------------- | -| `transaction` | [`TransactionRequest`](./types.md#transactionrequest) | Transaction request. | - -```ts -override async estimateGas(transaction: TransactionRequest): Promise -``` - -#### Example - -```ts -import { BrowserProvider } from 'zksync-ethers'; - -const provider = new BrowserProvider(window.ethereum); -const gas = await provider.estimateGas({ - to: '', - amount: ethers.parseEther('0.01'), -}); -console.log(`Gas: ${gas}`); -``` - -### `getSigner` - -Override of [Ethers implementation](https://docs.ethers.org/v6/api/providers/jsonrpc/#JsonRpcApiProvider-getSigner). - -#### Inputs - -| Parameter | Type | Description | -| ---------- | -------------------- | ------------------------------------ | -| `address?` | `number` or `string` | Account address or index (optional). | - -```ts -async getSigner(address ? : number | string): Promise -``` - -#### Example - -```ts -import { BrowserProvider } from 'zksync-ethers'; - -const provider = new BrowserProvider(window.ethereum); -const signer = await provider.getSigner(); -``` - -### `send` - -Returns a provider request object by overriding the -[Ethers implementation](https://docs.ethers.org/v6/api/providers/jsonrpc/#JsonRpcApiProvider-send). - -#### Inputs - -| Parameter | Type | Description | -| --------- | ------------ | ---------------------------------- | -| `method` | `Address` | Request method name as string. | -| `params?` | `Array` | Parameters of any type (optional). | - -```ts -async send(method: string, params?: Array): Promise -``` - -## Appendix - -### toJSON - -```ts -function toJSON(object: any): string { - return JSON.stringify(object, (key, value) => { - if (typeof value === 'bigint') { - return value.toString(); // Convert BigInt to string - } - return value; - }); -} -``` diff --git a/content/20.build/sdks/js/zksync-ethers/types.md b/content/20.build/sdks/js/zksync-ethers/types.md deleted file mode 100644 index 41b0a2a8..00000000 --- a/content/20.build/sdks/js/zksync-ethers/types.md +++ /dev/null @@ -1,345 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: JS SDK Types | zkSync Docs ---- - -# Types and Interfaces - -## `AccountAbstractionVersion` - -Enumerated list of account abstraction versions. - -- None = `0` (Used for contracts that are not accounts.) -- Version1 = `1` - -## `AccountNonceOrdering` - -Enumerated list of account nonce ordering formats. - -- Sequential = `0` -- Arbitrary = `1` - -## `Address` - -0x-prefixed, hex-encoded, Ethereum account address as string. - -## `ApprovalBasedPaymasterInput` - -Interface representation of approval based paymaster input containing various fields including an `ApprovalBased` type. - -- `type`: `'ApprovalBased'`; -- `token`: `Address`; -- `minimalAllowance`: `BigNumberish`; -- `innerInput`: `BytesLike`; - -## `BalancesMap` - -Type defining a map object containing accounts and their balances. - -- `{ [key: string]`: `bigint }` - -## `BatchDetails` - -Interface representation of batch information containing various optional and mandatory fields. - -- `number`: `number`; -- `timestamp`: `number`; -- `l1TxCount`: `number`; -- `l2TxCount`: `number`; -- `rootHash?`: `string`; -- `status`: `string`; -- `commitTxHash?`: `string`; -- `committedAt?`: `Date`; -- `proveTxHash?`: `string`; -- `provenAt?`: `Date`; -- `executeTxHash?`: `string`; -- `executedAt?`: `Date`; -- `l1GasPrice`: `number`; -- `l2FairGasPrice`: `number`; - -## `Block` - -Interface representation of a block that extends the Ethers -[`providers.Block`](https://docs.ethers.org/v5/api/providers/types/#providers-Block) definition with additional fields. - -- `l1BatchNumber`: `number`; -- `l1BatchTimestamp`: `number`; - -## `BlockDetails` - -Interface representation of block information containing various optional and mandatory fields. - -- `number`: `number`; -- `timestamp`: `number`; -- `l1BatchNumber`: `number`; -- `l1TxCount`: `number`; -- `l2TxCount`: `number`; -- `rootHash?`: `string`; -- `status`: `string`; -- `commitTxHash?`: `string`; -- `committedAt?`: `Date`; -- `proveTxHash?`: `string`; -- `provenAt?`: `Date`; -- `executeTxHash?`: `string`; -- `executedAt?`: `Date`; - -## `BlockTag` - -Pipe-delimited list of block labels that includes block number in denary and hex plus block statuses. - -- `BigNumberish` -- `string` // block hash -- `committed` -- `finalized` -- `latest` -- `earliest` -- `pending` - -## `ContractAccountInfo` - -Interface representation for contract account information containing information on account abstraction version and -nonce ordering format. - -- `supportedAAVersion`: `AccountAbstractionVersion`; -- `nonceOrdering`: `AccountNonceOrdering`; - -## `DeploymentInfo` - -Interface representation of deployment information with various fields. - -- `sender`: `Address`; -- `bytecodeHash`: `string`; -- `deployedAddress`: `Address`; - -## `DeploymentType` - -Pipe-delimited choice of two deployment types that support all `create2` variants. - -- `create` -- `createAccount` - -## `Eip712Meta` - -Type defining an EIP-712 transaction with optional parameters. - -- `gasPerPubdata?`: `BigNumberish`; -- `factoryDeps?`: `BytesLike[]`; -- `customSignature?`: `BytesLike`; -- `paymasterParams?`: `PaymasterParams`; - -## `EthereumSignature` - -Interface representation of an Ethereum signature. - -- `v`: `number`; -- `r`: `BytesLike`; -- `s`: `BytesLike`; - -## `Fee` - -Interface representation of transaction fee. - -- `gasLimit`: `BigInt`; -- `gasPerPubdataLimit`: `BigInt`; -- `maxPriorityFeePerGas`: `BigInt`; -- `maxFeePerGas`: `BigInt`; - -## `FinalizeWithdrawalParams` - -Interface representation of finalize withdrawal parameters. - -- `l1BatchNumber`: `number | null`; -- `l2MessageIndex`: `number`; -- `l2TxNumberInBlock`: `number | null`; -- `message`: `any`; -- `sender`: `string`; -- `proof`: `string[]`; - -## `FullDepositFee` - -Interface representation of full deposit fee containing various mandatory and optional fields. - -- `maxFeePerGas?`: `BigInt`; -- `maxPriorityFeePerGas?`: `BigInt`; -- `gasPrice?`: `BigInt`; -- `baseCost`: `BigInt`; -- `l1GasLimit`: `BigInt`; -- `l2GasLimit`: `BigInt`; - -## `GeneralPaymasterInput` - -Interface representation of general paymaster input containing a couple of fields, including a `General` type. - -- `type`: `'General'`; -- `innerInput`: `BytesLike`; - -## `L2ToL1Log` - -Interface representation of a layer 2 to layer 1 transaction log containing various fields. - -- `blockNumber`: `number`; -- `blockHash`: `string`; -- `l1BatchNumber`: `number`; -- `transactionIndex`: `number`; -- `shardId`: `number`; -- `isService`: `boolean`; -- `sender`: `string`; -- `key`: `string`; -- `value`: `string`; -- `transactionHash`: `string`; -- `logIndex`: `number`; - -## `Log` - -Interface representation of log that extends Ethers -[`providers.Log`](https://docs.ethers.org/v5/api/providers/types/#providers-Log) and supplies the layer 1 batch number. - -- `l1BatchNumber`: `number`; - -## `MessageProof` - -Interface representation of message proof containing various fields. - -- `id`: `number`; -- `proof`: `string[]`; -- `root`: `string`; - -## `Network` - -Enumerated list of networks and their ids. - -- Mainnet = `1` -- Ropsten = `3` -- Rinkeby = `4` -- Sepolia = `6`, -- localhost = `9` - -## `PaymasterInput` - -Type definition for a paymaster input specified as either approval based or general. - -- `ApprovalBasedPaymasterInput` | `GeneralPaymasterInput` - -## `PaymasterParams` - -Type defining a paymaster by address and the bytestream input. - -- `paymaster`: `Address`; -- `paymasterInput`: `BytesLike`; - -## `PriorityOpResponse` - -Interface representation of priority op response that extends [`TransactionResponse`](#transactionresponse) and adds a -function that waits to commit a layer 1 transaction, including when given on optional confirmation number. - -- `waitL1Commit(confirmation?: number)`: `Promise`; - -## `RawBlockTransaction` - -Interface representation of raw block with transactions - -- `common_data`: - - `L2`: - - `nonce`: `number`; - - `fee`: - - `gas_limit`: `BigInt`; - - `max_fee_per_gas`: `BigInt`; - - `max_priority_fee_per_gas`: `BigInt`; - - `gas_per_pubdata_limit`: `BigInt`; - - `initiatorAddress`: `Address`; - - `signature`: `Uint8Array`; - - `transactionType`: `string`; - - `input` - - `hash`: `string`; - - `data`: `Uint8Array`; - - `paymasterParams`: - - `paymaster`: `Address`; - - `paymasterInput`: `Uint8Array`; -- `execute`: - - `calldata`: `string`; - - `contractAddress`: `Address`; - - `factoryDeps`: `BytesLike[]`; - - `value`: `BigInt`; -- `received_timestamp_ms`: `number`; -- `raw_bytes`: `string`; - -## `Signature` - -0x-prefixed, hex-encoded, ECDSA signature as string. - -## `StorageProof` - -Interace representation of Merkle proofs for storage values. - -- `address`: `string`; -- `storageProof` (Array): - - `key`: `string`; - - `value`: `string`; - - `index`: `number`; - - `proof`: `string[]`; - -## `Token` - -Interface representation of token containing various fields. - -- `l1Address`: `Address`; -- `l2Address`: `Address`; -- `name`: `string`; -- `symbol`: `string`; -- `decimals`: `number`; - -## `TransactionDetails` - -Interface representation of transaction details containing various mandatory and optional fields. - -- `isL1Originated`: `boolean`; -- `status`: `string`; -- `fee`: `BigNumberish`; -- `initiatorAddress`: `Address`; -- `receivedAt`: `Date`; -- `ethCommitTxHash?`: `string`; -- `ethProveTxHash?`: `string`; -- `ethExecuteTxHash?`: `string`; - -## `TransactionReceipt` - -Interface representation of transaction receipt that extends from Ethers -[`providers.TransactionReceipt`](https://docs.ethers.org/v5/api/providers/types/#providers-TransactionReceipt) with -additional fields. - -- `l1BatchNumber`: `number`; -- `l1BatchTxIndex`: `number`; -- `l2ToL1Logs`: `Array`; -- `_logs`: `ReadonlyArray`; - -## `TransactionRequest` - -Interface representation of transaction request that extends from Ethers -[`providers.TransactionRequest`](https://docs.ethers.org/v5/api/providers/types/#providers-TransactionRequest) which -adds an optional field for EIP-712 transactions. - -- `customData?`: `Eip712Meta`; - -## `TransactionResponse` - -Interface representation of transaction response that extends from Ethers -[`providers.TransactionResponse`](https://docs.ethers.org/v5/api/providers/types/#providers-TransactionResponse) with -additional fields. - -- `l1BatchNumber`: `number`; -- `l1BatchTxIndex`: `number`; -- `waitFinalize()`: `Promise`; - -## `TransactionStatus` - -Non-enumerated enum list of transaction statuses. - -- NotFound = `not-found` -- Processing = `processing` -- Committed = `committed` -- Finalized = `finalized` - -:::tip More info Find the code definition of the types above on the -[zkSync Era Github repo.](https://github.com/zksync-sdk/zksync-ethers/blob/main/src/types.ts) ::: diff --git a/content/20.build/sdks/js/zksync-ethers/utils.md b/content/20.build/sdks/js/zksync-ethers/utils.md deleted file mode 100644 index 22ad401f..00000000 --- a/content/20.build/sdks/js/zksync-ethers/utils.md +++ /dev/null @@ -1,834 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: JS SDK Utilities | zkSync Docs ---- - -# Utilities - -The [utilities library](https://github.com/zksync-sdk/zksync-ethers/blob/main/src/utils.ts) contains essential utilities -for building on zkSync Era. - -:::info - -- This document describes common functions and constants you may need. -- Functions used internally are not necessarily described. -- Check the code for the full list. ::: - -## Use the library - -Access the library by importing it into your scripts. - -```typescript -import { utils } from 'zksync-ethers'; -``` - -## Constants - -### Interfaces - -#### zkSync Era main contract - -```typescript -export const ZKSYNC_MAIN_ABI = new utils.Interface(require('../abi/IZkSync.json')); -``` - -#### IERC20 - -For interacting with native tokens. - -```typescript -export const IERC20 = new utils.Interface(require('../abi/IERC20.json')); -``` - -#### IERC1271 - -For interacting with contract which implements ERC1271. - -```ts -export const IERC1271 = new utils.Interface(require('../abi/IERC1271.json')); -``` - -#### Contract deployer - -Used for deploying smart contracts. - -```ts -export const CONTRACT_DEPLOYER = new utils.Interface(require('../abi/ContractDeployer.json')); -``` - -#### L1 messenger - -Used for sending messages from zkSync Era to Ethereum. - -```ts -export const L1_MESSENGER = new utils.Interface(require('../abi/IL1Messenger.json')); -``` - -#### L1 and L2 bridges - -Bridge interface ABIs for L1 and L2. - -```ts -export const L1_BRIDGE_ABI = new utils.Interface(require('../abi/IL1Bridge.json')); -export const L2_BRIDGE_ABI = new utils.Interface(require('../abi/IL2Bridge.json')); -``` - -#### NonceHolder - -Used for managing deployment nonce. - -```ts -export const NONCE_HOLDER_ABI = new ethers.Interface(require('../abi/INonceHolder.json')); -``` - -#### L1 to L2 alias offset - -Used for applying and undoing aliases on addresses during bridging from L1 to L2. - -```ts -export const L1_TO_L2_ALIAS_OFFSET = '0x1111000000000000000000000000000000001111'; -``` - -#### Magic value - -The value returned from `isEIP1271SignatureCorrect` to confirm signature correctness. - -```ts -export const EIP1271_MAGIC_VALUE = '0x1626ba7e'; -``` - -#### EIP712 transaction type - -Constant representing an EIP712 transaction type. - -```ts -export const EIP712_TX_TYPE = 0x71; -``` - -#### EIP712 structures - -Collection of EIP712 structures with their types. - -```ts -export const EIP712_TYPES = { - Transaction: [ - { name: 'txType', type: 'uint256' }, - { name: 'from', type: 'uint256' }, - { name: 'to', type: 'uint256' }, - { name: 'gasLimit', type: 'uint256' }, - { name: 'gasPerPubdataByteLimit', type: 'uint256' }, - { name: 'maxFeePerGas', type: 'uint256' }, - { name: 'maxPriorityFeePerGas', type: 'uint256' }, - { name: 'paymaster', type: 'uint256' }, - { name: 'nonce', type: 'uint256' }, - { name: 'value', type: 'uint256' }, - { name: 'data', type: 'bytes' }, - { name: 'factoryDeps', type: 'bytes32[]' }, - { name: 'paymasterInput', type: 'bytes' }, - ], -}; -``` - -#### Priority op transaction on L2 - -Constant representing a priority transaction operation on L2. - -```ts -export const PRIORITY_OPERATION_L2_TX_TYPE = 0xff; -``` - -#### Max bytecode length - -Used for ensuring bytecode length is not over the maximum allowed. - -```ts -export const MAX_BYTECODE_LEN_BYTES = ((1 << 16) - 1) * 32; -``` - -### Useful addresses - -#### ETH token layer 1 - -```typescript -export const ETH_ADDRESS = '0x0000000000000000000000000000000000000000'; -``` - -#### ETH token alias on ZkSync Era - -```typescript -export const L2_ETH_TOKEN_ADDRESS = '0x000000000000000000000000000000000000800a'; -``` - -#### Bootloader - -```ts -export const BOOTLOADER_FORMAL_ADDRESS = '0x0000000000000000000000000000000000008001'; -``` - -#### Contract deployer - -```ts -export const CONTRACT_DEPLOYER_ADDRESS = '0x0000000000000000000000000000000000008006'; -``` - -#### L1 messenger - -```ts -export const L1_MESSENGER_ADDRESS = '0x0000000000000000000000000000000000008008'; -``` - -#### Nonce holder - -```ts -export const NONCE_HOLDER_ADDRESS = '0x0000000000000000000000000000000000008003'; -``` - -### Gas - -#### `DEFAULT_GAS_PER_PUBDATA_LIMIT` - -- Use a large amount of gas per pubdata for signing on layer 2. -- The amount ensures any reasonable limit is accepted. - -:::info - -- The operator is NOT required to use the actual value and can use any value up to that signed by the user. ::: - -```typescript -export const DEFAULT_GAS_PER_PUBDATA_LIMIT = 50000; -``` - -#### `REQUIRED_L1_TO_L2_GAS_PER_PUBDATA_LIMIT` - -The current required gas per pubdata for L1->L2 transactions. - -```ts -export const REQUIRED_L1_TO_L2_GAS_PER_PUBDATA_LIMIT = 800; -``` - -## Functions - -### `applyL1ToL2Alias` - -Converts the address that submitted a transaction to the inbox on L1 to the `msg.sender` viewed on L2. - -Returns the `msg.sender` of the L1->L2 transaction as the `address` of the contract that initiated the transaction. - -:::tip More info - -1. During a normal transaction, if contract A calls contract B, the `msg.sender` is A. -2. During L1->L2 communication, if an EOA X calls contract B, the `msg.sender` is X. -3. During L1->L2 communication, if a contract A calls contract B, the `msg.sender` is `applyL1ToL2Alias(A)`. ::: - -#### Inputs - -| Parameter | Type | Description | -| --------- | ------ | ----------------- | -| `address` | string | Contract address. | - -```ts -export function applyL1ToL2Alias(address: string): string; -``` - -#### Example - -```ts -const l1ContractAddress = '0x702942B8205E5dEdCD3374E5f4419843adA76Eeb'; -const l2ContractAddress = utils.applyL1ToL2Alias(l1ContractAddress); -// l2ContractAddress = "0x813A42B8205E5DedCd3374e5f4419843ADa77FFC" -``` - -See also [`undol1tol2alias`](#undol1tol2alias). - -### `checkBaseCost` - -Checks if the transaction's base cost is greater than the provided value, which covers the transaction's cost. Throws an -error if it is not. - -#### Inputs - -| Parameter | Type | Description | -| ---------- | -------------- | ------------------------------------------ | -| `baseCost` | `BigNumberish` | transaction's base cost. | -| `value` | `BigNumberish` | value which covers the transaction's cost. | - -```ts -async function checkBaseCost( - baseCost: ethers.BigNumberish, - value: ethers.BigNumberish | Promise -): Promise; -``` - -### Example - -```ts -const baseCost = 100; -const value = 99; -try { - await utils.checkBaseCost(baseCost, value); -} catch (e) { - // e.message = `The base cost of performing the priority operation is higher than the provided value parameter for the transaction: baseCost: ${baseCost}, provided value: ${value}`, -} -``` - -### `create2Address` - -Generates a future-proof contract address using salt plus bytecode which allows determination of an address before -deployment. - -:::warning - -- The zkSync Era implementation is slightly different from Ethereum. ::: - -#### Inputs - -| Parameter | Type | Description | -| -------------- | ----------- | ---------------------------------- | -| `sender` | `Address` | Sender address. | -| `bytecodeHash` | `BytesLike` | Output from zkSolc. | -| `salt` | `BytesLike` | Randomization element. | -| `input` | `BytesLike` | ABI encoded constructor arguments. | - -```ts -export function create2Address(sender: Address, bytecodeHash: BytesLike, salt: BytesLike, input: BytesLike): string; -``` - -#### Example - -```ts -const address = utils.create2Address( - '0x36615Cf349d7F6344891B1e7CA7C72883F5dc049', - '0x010001cb6a6e8d5f6829522f19fa9568660e0a9cd53b2e8be4deb0a679452e41', - '0x01', - '0x01' -); -// address = "0x29bac3E5E8FFE7415F97C956BFA106D70316ad50" -``` - -:::tip The `prefix` is equal to `keccak256("zksyncCreate")`. ::: - -### `createAddress` - -Generates a contract address from deployer's account and nonce. - -#### Inputs - -| Parameter | Type | Description | -| ------------- | -------------- | --------------- | -| `sender` | `Address` | Sender address. | -| `senderNonce` | `BigNumberish` | Sender nonce. | - -```ts -export function createAddress(sender: Address, senderNonce: BigNumberish): string; -``` - -#### Example - -```ts -const address = utils.createAddress('0x36615Cf349d7F6344891B1e7CA7C72883F5dc049', 1); -// address = "0x4B5DF730c2e6b28E17013A1485E5d9BC41Efe021" -``` - -### `eip712TxHash` - -Returns the hash of an EIP712 transaction. - -#### Inputs - -| Parameter | Type | Description | -| --------------- | --------------------------------------------------- | ---------------------------------------------- | -| `transaction` | `any` | EIP-712 transaction. | -| `ethSignature?` | [`EthereumSignature`](./types.md#ethereumsignature) | ECDSA signature of the transaction (optional). | - -```ts -function eip712TxHash(transaction: any, ethSignature?: EthereumSignature): string; -``` - -### `estimateDefaultBridgeDepositL2Gas` - -Returns an estimation of L2 gas required for token bridging via the default ERC20 bridge. - -::: tip More info - -- See the [default bridges documentation](../../../developer-reference/bridging-asset.md#default-bridges) ::: - -#### Inputs - -| Parameter | Type | Description | -| -------------------- | -------------- | ------------------------------------------- | -| `providerL1` | `Provider` | Ethers provider. | -| `providerL2` | `Provider` | zkSync provider. | -| `token` | `Address` | Token address. | -| `amount` | `BigNumberish` | Deposit amount. | -| `to` | `Address` | Recipient address. | -| `from?` | `Address` | Sender address (optional). | -| `gasPerPubdataByte?` | `BigNumberish` | Current gas per byte of pubdata (optional). | - -```ts -export async function estimateDefaultBridgeDepositL2Gas( - providerL1: ethers.providers.Provider, - providerL2: Provider, - token: Address, - amount: BigNumberish, - to: Address, - from?: Address, - gasPerPubdataByte?: BigNumberish -): Promise; -``` - -### `getDeployedContracts` - -Returns a log containing details of all deployed contracts related to a transaction receipt parameter. - -#### Inputs - -| Parameter | Type | Description | -| --------- | ----------------------------------------------------- | -------------------- | -| `receipt` | [`TransactionReceipt`](./types.md#transactionreceipt) | Transaction receipt. | - -```ts -export function getDeployedContracts(receipt: ethers.providers.TransactionReceipt): DeploymentInfo[]; -``` - -### `getERC20BridgeCalldata` - -Returns the calldata sent by an L1 ERC20 bridge to its L2 counterpart during token-bridging. - -#### Inputs - -| Parameter | Type | Description | -| ---------------- | -------------- | ------------------------------------------- | -| `l1TokenAddress` | `Address` | Token address on L1. | -| `l1Sender` | `Address` | Sender address on L1. | -| `l2Receiver` | `Address` | Recipient address on L2. | -| `amount` | `BigNumberish` | Gas fee for the number of tokens to bridge. | -| `bridgeData` | `BytesLike` | Data | - -```ts -export async function getERC20BridgeCalldata( - l1TokenAddress: string, - l1Sender: string, - l2Receiver: string, - amount: BigNumberish, - bridgeData: BytesLike -): Promise; -``` - -### `getL2HashFromPriorityOp` - -Returns the hash of the L2 priority operation from a given transaction receipt and L2 address. - -#### Inputs - -| Parameter | Type | Description | -| --------------- | ----------------------------------------------------- | ------------------------------------ | -| `txReceipt` | [`TransactionReceipt`](./types.md#transactionreceipt) | Receipt of the L1 transaction. | -| `zkSyncAddress` | `Address` | Address of zkSync Era main contract. | - -```ts -export function getL2HashFromPriorityOp(txReceipt: ethers.providers.TransactionReceipt, zkSyncAddress: Address): string; -``` - -### `getHashedL2ToL1Msg` - -Returns a keccak encoded message with a given sender address and block number from the L1 messenger contract. - -#### Inputs - -| Parameter | Type | Description | -| ----------------- | ----------- | -------------------------------------- | -| `sender` | `Address` | The sender of the message on L2. | -| `msg` | `BytesLike` | Encoded message. | -| `txNumberInBlock` | number | Index of the transaction in the block. | - -```ts -export function getHashedL2ToL1Msg(sender: Address, msg: BytesLike, txNumberInBlock: number): string; -``` - -#### Example - -```ts -const withdrawETHMessage = - '0x6c0960f936615cf349d7f6344891b1e7ca7c72883f5dc04900000000000000000000000000000000000000000000000000000001a13b8600'; -const withdrawETHMessageHash = utils.getHashedL2ToL1Msg( - '0x36615Cf349d7F6344891B1e7CA7C72883F5dc049', - withdrawETHMessage, - 0 -); -// withdrawETHMessageHash = "0xd8c80ecb64619e343f57c3b133c6c6d8dd0572dd3488f1ca3276c5b7fd3a938d" -``` - -### `hashBytecode` - -Returns the hash of given bytecode. - -#### Inputs - -| Parameter | Type | Description | -| ---------- | ----------- | ----------- | -| `bytecode` | `BytesLike` | Bytecode. | - -```ts -export function hashBytecode(bytecode: ethers.BytesLike): Uint8Array; -``` - -#### Examples - -```ts -const bytecode = - '0x000200000000000200010000000103550000006001100270000000130010019d0000008001000039000000400010043f0000000101200190000000290000c13d0000000001000031000000040110008c000000420000413d0000000101000367000000000101043b000000e001100270000000150210009c000000310000613d000000160110009c000000420000c13d0000000001000416000000000110004c000000420000c13d000000040100008a00000000011000310000001702000041000000200310008c000000000300001900000000030240190000001701100197000000000410004c000000000200a019000000170110009c00000000010300190000000001026019000000000110004c000000420000c13d00000004010000390000000101100367000000000101043b000000000010041b0000000001000019000000490001042e0000000001000416000000000110004c000000420000c13d0000002001000039000001000010044300000120000004430000001401000041000000490001042e0000000001000416000000000110004c000000420000c13d000000040100008a00000000011000310000001702000041000000000310004c000000000300001900000000030240190000001701100197000000000410004c000000000200a019000000170110009c00000000010300190000000001026019000000000110004c000000440000613d00000000010000190000004a00010430000000000100041a000000800010043f0000001801000041000000490001042e0000004800000432000000490001042e0000004a00010430000000000000000000000000000000000000000000000000000000000000000000000000ffffffff0000000200000000000000000000000000000040000001000000000000000000000000000000000000000000000000000000000000000000000000006d4ce63c0000000000000000000000000000000000000000000000000000000060fe47b18000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000080000000000000000000000000000000000000000000000000000000000000000000000000000000009c8c8fa789967eb514f3ec9def748480945cc9b10fcbd1a19597d924eb201083'; -const hashedBytecode = utils.hashBytecode(bytecode); -/* -hashedBytecode = new Uint8Array([ - 1, 0, 0, 27, 57, 231, 154, 55, 0, 164, 201, 96, 244, 120, 23, 112, 54, 34, 224, 133, - 160, 122, 88, 164, 112, 80, 0, 134, 48, 138, 74, 16, - ]), -); - */ -``` - -### `isECDSASignatureCorrect` - -Validates signatures from non-contract account addresses (EOA). Provides similar functionality in `ethers.js` but -returns `true` if the validation process succeeds, otherwise returns `false`. - -Called from [`isSignatureCorrect`](#isSignatureCorrect) for non-contract account addresses. - -#### Inputs - -| Parameter | Type | Description | -| ----------- | --------------- | ------------------------------ | -| `address` | `string` | Address which signs `msgHash`. | -| `msgHash` | `Address` | Hash of the message. | -| `signature` | `SignatureLike` | Ethers signature. | - -```ts -function isECDSASignatureCorrect(address: string, msgHash: string, signature: SignatureLike): boolean; -``` - -#### Examples - -```ts -import { Wallet, utils } from 'zksync-ethers'; - -const ADDRESS = ''; -const PRIVATE_KEY = ''; - -const message = 'Hello, world!'; -const signature = await new Wallet(PRIVATE_KEY).signMessage(message); -// ethers.Wallet can be used as well -// const signature = await new ethers.Wallet(PRIVATE_KEY).signMessage(message); - -const isValidSignature = await utils.isECDSASignatureCorrect(ADDRESS, message, signature); -// isValidSignature = true -``` - -See also [`isMessageSignatureCorrect()`](#ismessagesignaturecorrect) and -[`isTypedDataSignatureCorrect()`](#istypeddatasignaturecorrect) to validate signatures. - -### `isEIP1271SignatureCorrect` - -Called from [`isSignatureCorrect`](#isSignatureCorrect) for contract account addresses, the function returns true if the -validation process results in the `EIP1271_MAGIC_VALUE`. - -#### Inputs - -| Parameter | Type | Description | -| ----------- | --------------- | ------------------------ | -| `provider` | `Provider` | Provider. | -| `address` | `string` | Sender address. | -| `msgHash` | `string` | The hash of the message. | -| `signature` | `SignatureLike` | Ethers signature. | - -```ts -async function isEIP1271SignatureCorrect( - provider: Provider, - address: string, - msgHash: string, - signature: SignatureLike -): Promise; -``` - -See also [`isMessageSignatureCorrect()`](#ismessagesignaturecorrect) and -[`isTypedDataSignatureCorrect()`](#istypeddatasignaturecorrect) to validate signatures. - -### `isETH` - -Returns true if token represents ETH on L1 or L2. - -#### Inputs - -| Parameter | Type | Description | -| --------- | --------- | ------------------ | -| `token` | `Address` | The token address. | - -```ts -export function isETH(token: Address); -``` - -#### Example - -```ts -const isL1ETH = utils.isETH(utils.ETH_ADDRESS); // true -const isL2ETH = utils.isETH(utils.L2_ETH_TOKEN_ADDRESS); // true -``` - -### `isMessageSignatureCorrect` - -Returns true if account abstraction signature is correct. - -#### Inputs - -| Parameter | Type | Description | -| ----------- | --------------- | ------------------------ | -| `provider` | `Provider` | Provider. | -| `address` | `string` | Sender address. | -| `message` | `string` | The hash of the message. | -| `signature` | `SignatureLike` | Ethers signature. | - -```ts -export async function isMessageSignatureCorrect( - provider: Provider, - address: string, - message: ethers.Bytes | string, - signature: SignatureLike -): Promise; -``` - -#### Example - -```ts -import { Wallet, utils, Provider } from 'zksync-ethers'; - -const ADDRESS = ''; -const PRIVATE_KEY = ''; -const provider = Provider.getDefaultProvider(types.Network.Sepolia); - -const message = 'Hello, world!'; -const signature = await new Wallet(PRIVATE_KEY).signMessage(message); -// ethers.Wallet can be used as well -// const signature = await new ethers.Wallet(PRIVATE_KEY).signMessage(message); - -const isValidSignature = await utils.isMessageSignatureCorrect(provider, ADDRESS, message, signature); -// isValidSignature = true -``` - -### `isSignatureCorrect` - -Called from [`isMessageSignatureCorrect`](#ismessagesignaturecorrect) and -[`isTypedDataSignatureCorrect`](#istypeddatasignaturecorrect). Returns true if account abstraction EIP712 signature is -correct. - -#### Inputs - -| Parameter | Type | Description | -| ----------- | --------------- | ------------------------ | -| `provider` | `Provider` | Provider. | -| `address` | `string` | Sender address. | -| `msgHash` | `string` | The hash of the message. | -| `signature` | `SignatureLike` | Ethers signature. | - -```ts -async function isSignatureCorrect( - provider: Provider, - address: string, - msgHash: string, - signature: SignatureLike -): Promise; -``` - -### `isTypedDataSignatureCorrect` - -Returns true if account abstraction EIP712 signature is correct. - -#### Inputs - -| Parameter | Type | Description | -| ----------- | ----------------------------- | ------------------------------------------------------ | -| `provider` | `Provider` | Provider. | -| `address` | `string` | Sender address. | -| `domain` | `TypedDataDomain` | Domain data. | -| `types` | `Map` | Map of records pointing from field name to field type. | -| `value` | `Record` | A single record value. | -| `signature` | `SignatureLike` | Ethers signature. | - -```ts -export async function isTypedDataSignatureCorrect( - provider: Provider, - address: string, - domain: TypedDataDomain, - types: Record>, - value: Record, - signature: SignatureLike -): Promise; -``` - -#### Example - -```ts -import { Wallet, utils, Provider, EIP712Signer } from 'zksync-ethers'; - -const ADDRESS = ''; -const PRIVATE_KEY = ''; -const provider = Provider.getDefaultProvider(types.Network.Sepolia); - -const tx: types.TransactionRequest = { - type: 113, - chainId: 270, - from: ADDRESS, - to: '0xa61464658AfeAf65CccaaFD3a512b69A83B77618', - value: BigInt(7_000_000), -}; - -const eip712Signer = new EIP712Signer( - new Wallet(PRIVATE_KEY), // or new ethers.Wallet(PRIVATE_KEY), - Number((await provider.getNetwork()).chainId) -); - -const signature = await eip712Signer.sign(tx); - -const isValidSignature = await utils.isTypedDataSignatureCorrect( - provider, - ADDRESS, - await eip712Signer.getDomain(), - utils.EIP712_TYPES, - EIP712Signer.getSignInput(tx), - signature -); -// isValidSignature = true -``` - -### `parseEip712` - -Parses an EIP712 transaction from a payload. - -#### Inputs - -| Parameter | Type | Description | -| --------- | ----------- | ----------- | -| `payload` | `BytesLike` | Payload. | - -```ts -export function parseEip712(payload: ethers.BytesLike): TransactionLike; -``` - -### Example - -```ts -import { types } from 'zksync-ethers'; - -const serializedTx = - '0x71f87f8080808094a61464658afeaf65cccaafd3a512b69a83b77618830f42408001a073a20167b8d23b610b058c05368174495adf7da3a4ed4a57eb6dbdeb1fafc24aa02f87530d663a0d061f69bb564d2c6fb46ae5ae776bbd4bd2a2a4478b9cd1b42a82010e9436615cf349d7f6344891b1e7ca7c72883f5dc04982c350c080c0'; -const tx: types.TransactionLike = utils.parseEip712(serializedTx); -/* -tx: types.TransactionLike = { - type: 113, - nonce: 0, - maxPriorityFeePerGas: BigInt(0), - maxFeePerGas: BigInt(0), - gasLimit: BigInt(0), - to: "0xa61464658AfeAf65CccaaFD3a512b69A83B77618", - value: BigInt(1000000), - data: "0x", - chainId: BigInt(270), - from: "0x36615Cf349d7F6344891B1e7CA7C72883F5dc049", - customData: { - gasPerPubdata: BigInt(50000), - factoryDeps: [], - customSignature: "0x", - paymasterParams: null, - }, - hash: "0x9ed410ce33179ac1ff6b721060605afc72d64febfe0c08cacab5a246602131ee", -}; - */ -``` - -### `serializeEip712` - -Serializes an EIP712 transaction and include a signature if it is provided. Throws an error if: - -- `transaction.customData.customSignature` is an empty `string`. The transaction should be signed and the - `transaction.customData.customSignature` field should be populated with the signature. It should not be specified if - the transaction is not signed. -- `transaction.chainId` is not provided. -- `transaction.from` is not provided. - -#### Inputs - -| Parameter | Type | Description | -| ------------- | ----------------- | ---------------------------------------------------------------------- | -| `transaction` | `TransactionLike` | Transaction that needs to be serialized. | -| `signature?` | `SignatureLike` | Ethers signature that needs to be included in transactions (optional). | - -```ts -export function serializeEip712(transaction: TransactionLike, signature?: ethers.SignatureLike): string; -``` - -#### Examples - -Serialize EIP712 transaction without signature. - -```ts -const serializedTx = utils.serializeEip712({ chainId: 270, from: '0x36615Cf349d7F6344891B1e7CA7C72883F5dc049' }, null); - -// serializedTx = "0x71ea8080808080808082010e808082010e9436615cf349d7f6344891b1e7ca7c72883f5dc04982c350c080c0" -``` - -Serialize EIP712 transaction with signature. - -```ts -const signature = ethers.Signature.from( - '0x73a20167b8d23b610b058c05368174495adf7da3a4ed4a57eb6dbdeb1fafc24aaf87530d663a0d061f69bb564d2c6fb46ae5ae776bbd4bd2a2a4478b9cd1b42a' -); - -const serializedTx = utils.serializeEip712( - { - chainId: 270, - from: '0x36615Cf349d7F6344891B1e7CA7C72883F5dc049', - to: '0xa61464658AfeAf65CccaaFD3a512b69A83B77618', - value: 1_000_000, - }, - signature -); -// serializedTx = "0x71f87f8080808094a61464658afeaf65cccaafd3a512b69a83b77618830f42408001a073a20167b8d23b610b058c05368174495adf7da3a4ed4a57eb6dbdeb1fafc24aa02f87530d663a0d061f69bb564d2c6fb46ae5ae776bbd4bd2a2a4478b9cd1b42a82010e9436615cf349d7f6344891b1e7ca7c72883f5dc04982c350c080c0" -``` - -### `sleep` - -Common sleep function that pauses execution for a number of milliseconds. - -#### Inputs - -| Parameter | Type | Description | -| --------- | ------ | ----------------------- | -| `millis` | number | Number of milliseconds. | - -```ts -export function sleep(millis: number); -``` - -### `undoL1ToL2Alias` - -Converts and returns the `msg.sender` viewed on L2 to the address that submitted a transaction to the inbox on L1. - -#### Inputs - -| Parameter | Type | Description | -| --------- | ------ | --------------- | -| `address` | string | Sender address. | - -```ts -export function undoL1ToL2Alias(address: string): string; -``` - -#### Example - -```ts -const l2ContractAddress = '0x813A42B8205E5DedCd3374e5f4419843ADa77FFC'; -const l1ContractAddress = utils.undoL1ToL2Alias(l2ContractAddress); -// const l1ContractAddress = "0x702942B8205E5dEdCD3374E5f4419843adA76Eeb" -``` - -See also [`applyl1tol2alias`](#applyl1tol2alias). diff --git a/content/20.build/sdks/python/accounts-l1-l2.md b/content/20.build/sdks/python/accounts-l1-l2.md deleted file mode 100644 index afbb629a..00000000 --- a/content/20.build/sdks/python/accounts-l1-l2.md +++ /dev/null @@ -1,234 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Python SDK L1/L2 Transactions | zkSync Docs ---- - -# Accounts: L1->L2 Transactions - -This section explores the methods which allow the [account](./accounts.md) classes to send transactions from L1 to L2. - -If you want to get some background on how L1->L2 interaction works on zkSync Era, go through the -[introduction](../../developer-reference/l1-l2-interop.md). - -The zkSync Python SDK account is compatible with the `eth_account` package, and in most cases users can have their -private key and get account instances by using it. - -> Example - -```python - -from eth_account import Account -from eth_account.signers.local import LocalAccount -... -account: LocalAccount = Account.from_key("PRIVATE_KEY") - -``` - -The base property that is used directly with account is: `Account.address`. - -## Approving deposit of tokens - -Bridging ERC20 tokens from Ethereum requires approving the tokens to the zkSync Ethereum smart contract. - -```python -def approve_erc20(self, - token: HexStr, - amount: int, - bridge_address: HexStr = None, - gas_limit: int = None) -> TxReceipt: -``` - -### Inputs and outputs - -| Name | Description | -| -------------- | ---------------------------------------------- | -| token | The Ethereum address of the token. | -| amount | The amount of the token to be approved. | -| bridge_address | Custom address of l1 bridge (optional). | -| gas_limit | Gas limit (optional). | -| returns | `ethers.providers.TransactionResponse` object. | - -> Example - -```python -from eth_account import Account -from eth_account.signers.local import LocalAccount -from web3 import Web3 -from zksync2.account.wallet import Wallet -from zksync2.module.module_builder import ZkSyncBuilder - -ZKSYNC_PROVIDER = "https://sepolia.era.zksync.dev" -ETH_PROVIDER = "https://rpc.ankr.com/eth_sepolia" - -zk_web3 = ZkSyncBuilder.build(ZKSYNC_PROVIDER) -eth_web3 = Web3(Web3.HTTPProvider(ETH_PROVIDER)) - -account: LocalAccount = Account.from_key("PRIVATE_KEY") -wallet = Wallet(zksync, eth_web3, account) - -amount_usdc = 5 -is_approved = wallet.approve_erc20("USDC_ADDRESS", amount_usdc) - -await txHandle.wait(); -``` - -## Depositing tokens to zkSync - -```python -def deposit(self, transaction: DepositTransaction): -``` - -#### Inputs and outputs - -| Name | Description | -| ----------- | ----------------------------------------------------- | -| transaction | [`Deposittransaction`](./types.md#deposittransaction) | -| returns | `Hash` of the transaction. | - -> Example - -```python -from eth_account import Account -from eth_account.signers.local import LocalAccount -from web3 import Web3 -from zksync2.account.wallet import Wallet -from zksync2.module.module_builder import ZkSyncBuilder -from zksync2.core.types import TransactionOptions, DepositTransaction, ADDRESS_DEFAULT - - -ZKSYNC_PROVIDER = "https://sepolia.era.zksync.dev" -ETH_PROVIDER = "https://rpc.ankr.com/eth_sepolia" - -zk_web3 = ZkSyncBuilder.build(ZKSYNC_PROVIDER) -eth_web3 = Web3(Web3.HTTPProvider(ETH_PROVIDER)) - -account: LocalAccount = Account.from_key("PRIVATE_KEY") -wallet = Wallet(zksync, eth_web3, account) - -USDC_ADDRESS = ""; -l1_hash_usdc = wallet.deposit(DepositTransaction(Web3.to_checksum_address(USDC_ADDRESS), - amount_usdc, - account.address, - approve_erc20=True)) - -l1_tx_receipt_usdc = self.eth_web3.eth.wait_for_transaction_receipt(l1_hash_usdc) - -l1_hash_eth = self.wallet.deposit(DepositTransaction(token=Token.create_eth().l1_address, - amount=amount, - to=self.wallet.address)) - -l1_tx_receipt_usdc = self.eth_web3.eth.wait_for_transaction_receipt(l1_hash_eth) - -await ethDepositHandle.wait(); -``` - -## Adding native token to zkSync - -New tokens are added automatically the first time they are deposited. - -## Finalizing withdrawals - -Withdrawals are executed in 2 steps - initiated on L2 and finalized on L1. - -```python -def finalize_withdrawal(self, withdraw_hash, index: int = 0): -``` - -#### Inputs and outputs - -| Name | Description | -| -------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | -| withdrawalHash | Hash of the L2 transaction where the withdrawal was initiated. | -| index | In case there were multiple withdrawals in one transaction, you may pass an index of the withdrawal you want to finalize (defaults to 0). | - -## Force-executing transactions on L2 - -### Getting the base cost for L2 transaction - -```python -def get_base_cost(self, - l2_gas_limit: int, - gas_per_pubdata_byte: int = DEPOSIT_GAS_PER_PUBDATA_LIMIT, - gas_price: int = None): -``` - -#### Inputs and outputs - -| Name | Description | -| -------------------- | ------------------------------------------------------------------------------------- | -| l2_gas_limit | The `gasLimit` for the L2 contract call. | -| gas_per_pubdata_byte | The L2 gas price for each published L1 calldata byte. | -| gas_price | The L1 gas price of the L1 transaction that will send the request for an execute call | -| returns | The base cost in ETH for requesting the L2 contract call. | - -## Claim Failed Deposit - -The `claimFailedDeposit` method withdraws funds from the initiated deposit, which failed when finalizing on L2. -If the deposit L2 transaction has failed, it sends an L1 transaction calling `claimFailedDeposit` method of the L1 -bridge, which results in returning L1 tokens back to the depositor, otherwise throws the error. - -```python -def claim_failed_deposit(self, deposit_hash: HexStr): -``` - -### Input Parameters - -| Parameter | Type | Description | -| ----------- | -------- | ---------------------------------------------- | -| depositHash | `HexStr` | The L2 transaction hash of the failed deposit. | - -### Requesting transaction execution - -```python -def request_execute(self, transaction: RequestExecuteCallMsg): - transaction = self.get_request_execute_transaction(transaction) - tx = self.contract.functions.requestL2Transaction(transaction.contract_address, - transaction.call_data, - transaction.l2_value, - transaction.l2_gas_limit, - transaction.gas_per_pubdata_byte, - transaction.factory_deps, - transaction.refund_recipient).build_transaction(prepare_transaction_options(transaction.options, transaction.from_)) - signed_tx = self._l1_account.sign_transaction(tx) - return self._eth_web3.eth.send_raw_transaction(signed_tx.rawTransaction) -``` - -#### Inputs and outputs - -| Name | Description | -| ----------- | ------------------------------------------------------------------ | -| transaction | [`RequestExecuteCallMsg`](./types.md#requestexecutecallmsg) object | -| returns | `Hash`. | - -> Example - -```python -from eth_account import Account -from eth_account.signers.local import LocalAccount -from web3 import Web3 -from eth_typing import HexStr -from zksync2.account.wallet import Wallet -from zksync2.module.module_builder import ZkSyncBuilder -from zksync2.core.types import TransactionOptions, DepositTransaction, ADDRESS_DEFAULT, RequestExecuteCallMsg - - -ZKSYNC_PROVIDER = "https://sepolia.era.zksync.dev" -ETH_PROVIDER = "https://rpc.ankr.com/eth_sepolia" - -zk_web3 = ZkSyncBuilder.build(ZKSYNC_PROVIDER) -eth_web3 = Web3(Web3.HTTPProvider(ETH_PROVIDER)) - -account: LocalAccount = Account.from_key("PRIVATE_KEY") -wallet = Wallet(zksync, eth_web3, account) - -amount = 7_000_000_000 -l2_balance_before = self.wallet.get_balance() - -l1_tx_receipt = self.wallet.request_execute(RequestExecuteCallMsg(contract_address=Web3.to_checksum_address(self.zksync.zksync.main_contract_address),call_data=HexStr("0x"),l2_value=amount,l2_gas_limit=900_000)) - -l2_hash = self.zksync.zksync.get_l2_hash_from_priority_op(l1_tx_receipt, self.zksync_contract) -self.zksync.zksync.wait_for_transaction_receipt(l2_hash) -l2_balance_after = self.wallet.get_balance() -``` diff --git a/content/20.build/sdks/python/accounts.md b/content/20.build/sdks/python/accounts.md deleted file mode 100644 index 9c5e1f29..00000000 --- a/content/20.build/sdks/python/accounts.md +++ /dev/null @@ -1,428 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Python SDK Accounts | zkSync Docs ---- - -# Accounts - -## Overview - -The zkSync Python SDK has a method that generates a signature and a method that verifies messages. - -- `Wallet` -- `sign_typed_data` : used to sign EIP712-typed zkSync transactions. -- `verify_typed_data` : used to verify the signed EIP712-typed zkSync transactions. - -### construction - -For constructing the instance it needs only `account` and `chain_id`. - -> Example: - -```python -from zksync2.signer.eth_signer import PrivateKeyEthSigner -from eth_account import Account -from zksync2.module.module_builder import ZkSyncBuilder - - -account = Account.from_key("PRIVATE_KEY") -zksync_web3 = ZkSyncBuilder.build("ZKSYNC_NETWORK_URL") - -chain_id = zksync_web3.zksync.chain_id -signer = PrivateKeyEthSigner(account, chain_id) - -``` - -## sign_typed_data - -The signer is used to generate the signature of the provided transaction based on your account(your private key). - -### Parameters - -| Parameters | Return value | Description | -| --------------------------------- | --------------------- | --------------------------------------------------------------------------- | -| EIP712 Structure, optional domain | Web3 py SignedMessage | Builds `SignedMessage` based on the encoded in `EIP712` format Transaction. | - -## verify_typed_data - -It's used to verify the provided transaction, whose signature is added to the final `EIP712` transaction for its -validation. - -### Parameters - -| Parameters | Return value | Description | -| -------------------------------------------- | ------------ | ------------------------------------------------------------------------------ | -| signature, EIP712 structure, optional domain | bool | Returns **True** if the encoded transaction is signed with provided signature. | - -The signer class also has the following properties: - -| Attribute | Description | -| --------- | ------------------------------------------------------------------------------- | -| address | Account address | -| domain | Domain that is used to generate signature. It depends on `chain_id` of network. | - -## `Wallet` - -### Creating wallet from a private key - -The `Wallet` object can be created from 'BaseAccount'. - -```python -def __init__(self, - zksync_web3: Web3, - eth_web3: Web3, - l1_account: BaseAccount): -``` - -#### Inputs and outputs - -| Name | Description | -| ----------- | ----------------------------------------------------------- | -| zksync_web3 | A zkSync node provider. Needed for interaction with zkSync. | -| eth_web3 | An Ethereum node provider. Needed for interaction with L1. | -| l1_account | Base account used to associate with wallet. | -| returns | The new `Wallet` object. | - -> Example - -```python -from eth_account import Account -from eth_account.signers.local import LocalAccount -from web3 import Web3 - -from zksync2.account.wallet import Wallet -from zksync2.module.module_builder import ZkSyncBuilder - -if __name__ == "__main__": - ZKSYNC_PROVIDER = "https://sepolia.era.zksync.dev" - ETH_PROVIDER = "https://rpc.ankr.com/eth_sepolia" - zk_web3 = ZkSyncBuilder.build(ZKSYNC_PROVIDER) - eth_web3 = Web3(Web3.HTTPProvider(ETH_PROVIDER)) - account: LocalAccount = Account.from_key(private_key) - wallet = Wallet(zk_web3, eth_web3, account) -``` - -### Getting the zkSync L1 smart contract - -```python -def main_contract(self): -``` - -#### Inputs and outputs - -| Name | Description | -| ------- | ---------------------------------------- | -| returns | `Contract` of the zkSync smart contract. | - -> Example - -```python -from eth_account import Account -from eth_account.signers.local import LocalAccount -from web3 import Web3 - -from zksync2.account.wallet import Wallet -from zksync2.module.module_builder import ZkSyncBuilder - -if __name__ == "__main__": - ZKSYNC_PROVIDER = "https://sepolia.era.zksync.dev" - ETH_PROVIDER = "https://rpc.ankr.com/eth_sepolia" - - zk_web3 = ZkSyncBuilder.build(ZKSYNC_PROVIDER) - eth_web3 = Web3(Web3.HTTPProvider(ETH_PROVIDER)) - - account: LocalAccount = Account.from_key(private_key) - wallet = Wallet(zk_web3, eth_web3, account) - - contract = wallet.main_contract - print(contract.address); -``` - -### Getting token balance - -```python -def get_balance(self, block_tag = ZkBlockParams.COMMITTED.value, token_address: HexStr = None) -> int: -``` - -#### Inputs and outputs - -| Name | Description | -| ------------- | ------------------------------------------------------------------------------------------------------------- | -| block_tag | The block the balance should be checked on. `committed`, i.e. the latest processed one is the default option. | -| token_address | The address of the token. ETH by default. | -| returns | The amount of the token the `Wallet` has. | - -> Example - -```python -from eth_account import Account -from eth_account.signers.local import LocalAccount -from web3 import Web3 - -from zksync2.account.wallet import Wallet -from zksync2.module.module_builder import ZkSyncBuilder - -if __name__ == "__main__": - ZKSYNC_PROVIDER = "https://sepolia.era.zksync.dev" - ETH_PROVIDER = "https://rpc.ankr.com/eth_sepolia" - - zk_web3 = ZkSyncBuilder.build(ZKSYNC_PROVIDER) - eth_web3 = Web3(Web3.HTTPProvider(ETH_PROVIDER)) - - account: LocalAccount = Account.from_key(private_key) - wallet = Wallet(zk_web3, eth_web3, account) - - - balance = self.wallet.get_balance() - print(balance); -``` - -### Getting token balance on L1 - -```python -def get_l1_balance(self, token: HexStr = ADDRESS_DEFAULT, block: EthBlockParams = EthBlockParams.LATEST) -> int: -``` - -#### Inputs and outputs - -| Name | Description | -| ------- | ------------------------------------------------------------------------------------------- | -| token | The address of the token. ETH by default. | -| block | The block the balance should be checked on. The latest processed one is the default option. | -| returns | The amount of the token the `Wallet` has on Ethereum. | - -> Example - -```python -from eth_account import Account -from eth_account.signers.local import LocalAccount -from web3 import Web3 - -from zksync2.account.wallet import Wallet -from zksync2.module.module_builder import ZkSyncBuilder - -if __name__ == "__main__": - ZKSYNC_PROVIDER = "https://sepolia.era.zksync.dev" - ETH_PROVIDER = "https://rpc.ankr.com/eth_sepolia" - - zk_web3 = ZkSyncBuilder.build(ZKSYNC_PROVIDER) - eth_web3 = Web3(Web3.HTTPProvider(ETH_PROVIDER)) - - account: LocalAccount = Account.from_key(private_key) - wallet = Wallet(zk_web3, eth_web3, account) - - - balance = self.wallet.get_l1_balance() - print(balance); -``` - -### Transferring tokens inside zkSync Era - -For convenience, the `Wallet` class has `transfer` method, which can transfer `ETH` or any `ERC20` token within the same -interface. - -```python -def transfer(self, tx: TransferTransaction) -> HexStr: -``` - -#### Inputs and outputs - -| Name | Description | -| ------- | -------------------------------------------------------- | -| tx | [`TransferTransaction`](./types.md#transfertransaction). | -| returns | A `HexStr` of transaction. | - -> Example - -```python -from eth_account import Account -from eth_account.signers.local import LocalAccount -from web3 import Web3 - -from zksync2.account.wallet import Wallet -from zksync2.module.module_builder import ZkSyncBuilder - -if __name__ == "__main__": - ZKSYNC_PROVIDER = "https://sepolia.era.zksync.dev" - ETH_PROVIDER = "https://rpc.ankr.com/eth_sepolia" - - zk_web3 = ZkSyncBuilder.build(ZKSYNC_PROVIDER) - eth_web3 = Web3(Web3.HTTPProvider(ETH_PROVIDER)) - - account: LocalAccount = Account.from_key("PRIVATE_KEY") - wallet = Wallet(zk_web3, eth_web3, account) - - amount = 7_000_000_000 - tx_hash = self.wallet.transfer(TransferTransaction(to=Web3.to_checksum_address("TO_ADDRESS"), - token_address=ADDRESS_DEFAULT, - amount=amount)) - - tx_receipt = self.zk_web3.zksync.wait_for_transaction_receipt( - tx_hash, timeout=240, poll_latency=0.5 - ) -``` - -### Initiating a withdrawal to L1 - -```python -def withdraw(self, tx: WithdrawTransaction): -``` - -| Name | Description | -| ------- | ------------------------------------------------------- | -| tx | [`WithdrawTransaction`](./types.md#withdrawtransaction) | -| returns | A `Hash` of the transaction | - -### Transferring tokens inside zkSync - -Please note that for now, unlike Ethereum, zkSync does not support native transfers, i.e. the `value` field of all -transactions is equal to `0`. All the token transfers are done through ERC20 `transfer` function calls. - -But for convenience, the `Wallet` class has `transfer` method, which can transfer any `ERC20` tokens. - -```python -def transfer(self, tx: TransferTransaction) -> HexStr: -``` - -#### Inputs and outputs - -| Name | Description | -| ------- | ------------------------------------------------------- | -| tx | ['TransferTransaction'](./types.md#transfertransaction) | -| returns | An `Hash` of the transaction | - -> Example - -```python -from web3 import Web3 - -from zksync2.core.types import TransferTransaction, ADDRESS_DEFAULT - -ZKSYNC_PROVIDER = "https://sepolia.era.zksync.dev" -ETH_PROVIDER = "https://rpc.ankr.com/eth_sepolia" - -zk_web3 = ZkSyncBuilder.build(ZKSYNC_PROVIDER) -eth_web3 = Web3(Web3.HTTPProvider(ETH_PROVIDER)) - -account: LocalAccount = Account.from_key("PRIVATE_KEY") -wallet = Wallet(zksync, eth_web3, account) - -tx_hash = self.wallet.transfer(TransferTransaction(to=Web3.to_checksum_address("TO_ADDRESS"),token_address=ADDRESS_DEFAULT,amount=amount)) - -self.zksync.zksync.wait_for_transaction_receipt( - tx_hash, timeout=240, poll_latency=0.5 -) -``` - -### Getting the zkSync L1 smart contract - -```python -def main_contract(self) -> Union[Type[Contract], Contract]: -``` - -#### Inputs and outputs - -| Name | Description | -| ------- | ----------------------------------------------- | -| returns | `Contract` object of the zkSync smart contract. | - -> Example - -```python -from eth_account import Account -from eth_account.signers.local import LocalAccount -from web3 import Web3 -from zksync2.account.wallet import Wallet -from zksync2.module.module_builder import ZkSyncBuilder - -ZKSYNC_PROVIDER = "https://sepolia.era.zksync.dev" -ETH_PROVIDER = "https://rpc.ankr.com/eth_sepolia" - -zk_web3 = ZkSyncBuilder.build(ZKSYNC_PROVIDER) -eth_web3 = Web3(Web3.HTTPProvider(ETH_PROVIDER)) - -account: LocalAccount = Account.from_key("PRIVATE_KEY") -wallet = Wallet(zksync, eth_web3, account) - -main_contract = wallet.main_contract -``` - -### Getting bridge contracts - -ERC-20 bridge `Contract` object: - -```python -def get_l1_bridge_contracts(self) -> L1BridgeContracts: -``` - -#### Inputs and outputs - -| Name | Description | -| ------- | ----------------------------------------------------------- | -| returns | [`L1BridgeContracts`](./types.md#l1bridgecontracts) object. | - -> Example - -```python -from eth_account import Account -from eth_account.signers.local import LocalAccount -from web3 import Web3 -from zksync2.account.wallet import Wallet -from zksync2.module.module_builder import ZkSyncBuilder - -ZKSYNC_PROVIDER = "https://sepolia.era.zksync.dev" -ETH_PROVIDER = "https://rpc.ankr.com/eth_sepolia" - -zk_web3 = ZkSyncBuilder.build(ZKSYNC_PROVIDER) -eth_web3 = Web3(Web3.HTTPProvider(ETH_PROVIDER)) - -account: LocalAccount = Account.from_key("PRIVATE_KEY") -wallet = Wallet(zksync, eth_web3, account) - -l1_bridge_contracts = wallet.get_l1_bridge_contracts() -``` - -:::note - -there is no separate Ether bridge contract, [Main contract](./accounts.md#getting-the-zksync-l1-smart-contract) is used -instead. - -::: - -### Getting token balance on L1 - -```python -def get_l1_balance(self, token: HexStr = ADDRESS_DEFAULT, block: EthBlockParams = EthBlockParams.LATEST) -> int: - -``` - -#### Inputs and outputs - -| Name | Description | -| ------- | ------------------------------------------------------------------------------------------- | -| token | The address of the token. ETH by default. | -| block | The block the balance should be checked on. The latest processed one is the default option. | -| returns | The amount of the token the `BaseAccount` has on Ethereum. | - -> Example - -```python -from eth_account import Account -from eth_account.signers.local import LocalAccount -from web3 import Web3 -from zksync2.account.wallet import Wallet -from zksync2.module.module_builder import ZkSyncBuilder - -ZKSYNC_PROVIDER = "https://sepolia.era.zksync.dev" -ETH_PROVIDER = "https://rpc.ankr.com/eth_sepolia" - -zk_web3 = ZkSyncBuilder.build(ZKSYNC_PROVIDER) -eth_web3 = Web3(Web3.HTTPProvider(ETH_PROVIDER)) - -account: LocalAccount = Account.from_key("PRIVATE_KEY") -wallet = Wallet(zksync, eth_web3, account) - -balance = self.wallet.get_l1_balance() -``` diff --git a/content/20.build/sdks/python/contracts.md b/content/20.build/sdks/python/contracts.md deleted file mode 100644 index 709f206c..00000000 --- a/content/20.build/sdks/python/contracts.md +++ /dev/null @@ -1,52 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Python SDK Contract | zkSync Docs ---- - -# Contract Interfaces - -There is a set of system contract that helps with the interaction with zkSync Era network. Most of them are called using -abi. - -> Example - -```python -from web3 import Web3 - -from zksync2.manage_contracts.utils import zksync_abi_default -from zksync2.module.module_builder import ZkSyncBuilder - -zksync = ZkSyncBuilder.build(self.env.zksync_server) -zksync_contract = self.eth_web3.eth.contract(Web3.to_checksum_address(zksync.zksync.main_contract_address), abi=zksync_abi_default()) -``` - -### ContractDeployer - -ContractDeployer is a utility system contract, represented as a type to cover the following functionality: - -- encode binary contract representation by `create` method for further deploying. -- encode binary contract representation by `create2` method for further deploying. -- Precompute contract address for `create` and `create2` methods. - -Construction: needs only web3 object with appended zksync module - -Example: - -```python -from zksync2.manage_contracts.contract_deployer import ContractDeployer -from zksync2.module.module_builder import ZkSyncBuilder - -zksync_web3 = ZkSyncBuilder.build("ZKSYNC_NETWORK_URL") -deployer = ContractDeployer(zksync_web3) -``` - -**Parameter and Methods:** - -| Method | Parameters | Return value | Description | -| -------------------------- | ------------------------------------------ | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| encode_create | bytecode, optional `call_data` & `salt` | HexStr | Creates binary representation of a contract in an internal deploying format.
bytecode - contract binary representation, `call_data` is used for `ctor` bytecode only, `salt` is used to generate unique identifier of deploying contract. | -| encode_create2 | bytecode, optional `call_data` & `salt` | HexStr | Creates binary representation of contract in an internal deploying format.
bytecode - contract binary representation, `call_data` is used for `ctor` bytecode only, `salt` is used to generate unique identifier of deploying contract. | -| compute_l2_create_address | Address, Nonce | Address | Accepts address of deployer and current deployed nonce and returns address of contract that is going to be deployed by the`encode_create` method. | -| compute_l2_create2_address | Address, bytecode, `ctor` bytecode, `salt` | Address | Accepts address of the deployer, binary representation of contract, its constructor in binary format and salt. By default constructor can be `b'0'` value. It returns the address of the contract that is going to be deployed by an`encode_create2` method. | diff --git a/content/20.build/sdks/python/getting-started.md b/content/20.build/sdks/python/getting-started.md deleted file mode 100644 index 7ff0f027..00000000 --- a/content/20.build/sdks/python/getting-started.md +++ /dev/null @@ -1,163 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Python SDK Getting Started | zkSync Docs ---- - -# Getting Started - -## Concept - -While most of the existing SDKs should work out of the box, deploying smart contracts or using unique zkSync features, -like account abstraction, requires providing additional fields to those that Ethereum transactions have by default. - -To provide easy access to all the features of zkSync Era, the `zksync2` Python SDK was created, which is made in a way -that has an interface very similar to those of [web3.py](https://web3py.readthedocs.io/en/latest/index.html). In fact, -`web3.py` is a peer dependency of our library and most of the objects exported by `zksync2` inherit from the -corresponding `web3.py` objects and override only the fields that need to be changed. - -## Prerequisites - -- Python: >=3.8 ([installation guide](https://www.python.org/downloads/)) -- Pip: 23.1.2 ([installation guide](https://pip.pypa.io/en/stable/installation/)) - -## Adding dependencies - -To install zkSync Era, run the command below in your terminal. - -```shell -pip install zksync2 -``` - -## Connecting to zkSync Era - -Once you have all the necessary dependencies, connect to zkSync Era using the endpoint of the operator node. - -```python -from zksync2.module.module_builder import ZkSyncBuilder -... -sdk = ZkSyncBuilder.build("https://sepolia.era.zksync.dev") -``` - -## Examples - -Full code for all examples is available [here](https://github.com/zksync-sdk/zksync2-examples/tree/main/python). -Examples are configured to interact with `zkSync`, and `Sepolia` test networks. - -## Creating a wallet - -To control your account in zkSync, use the `Wallet` object. It can sign transactions with keys stored in `Wallet` and -send transaction to the zkSync network using `zksync_module`. - -```python -# Derive Wallet from ethereum private key. -account: LocalAccount = Account.from_key() -wallet = Wallet(zksync, eth_web3, account) -``` - -## Depositing funds - -Let's deposit `1.0 ETH` to our zkSync account. - -```python -tx_hash = self.wallet.deposit( - DepositTransaction(token=Token.create_eth().l1_address, amount=amount) -) -``` - -**NOTE:** Each token inside zkSync has an address. If `ERC-20` tokens are being bridged, you should supply the token's -L1 address in the `deposit` function, or zero address (`0x0000000000000000000000000000000000000000`) if you want to -deposit ETH. Note, that for the `ERC-20` tokens the address of their corresponding L2 token will be different from the -one on Ethereum. - -After the transaction is submitted to the Ethereum node, its status can be tracked using the transaction handle: - -```python -# Waiting for receipt on L1 -tx_receipt = self.eth_web3.eth.wait_for_transaction_receipt(tx_hash) -``` - -```python -l2_hash = self.zksync.zksync.get_l2_hash_from_priority_op( - tx_receipt, self.zksync_contract -) -# Waiting for receipt on L2 -self.zksync.zksync.wait_for_transaction_receipt( - transaction_hash=l2_hash, timeout=360, poll_latency=10 -) -``` - -## Checking zkSync account balance - -```python -#Retrieving the current (committed) zkSync ETH balance of an account -balance = self.wallet.get_balance() -``` - -```python -# Retrieving the ETH balance of an account in the last finalized zkSync block. -balance = self.wallet.get_balance(block_tag=ZkBlockParams.FINALIZED.value) -``` - -## Performing a transfer - -Now, let's create a second wallet and transfer some funds into it. Note that it is possible to send assets to any fresh -Ethereum account, without preliminary registration! - -```python -wallet_2 = Wallet(zksync, eth_web3, account_2) -``` - -Let's transfer `1 ETH` to another account: - -The `transfer` method is a helper method that enables transferring `ETH` or any `ERC-20` token within a single -interface. - -```python -tx_hash = self.wallet.transfer( - TransferTransaction( - to=Web3.to_checksum_address("), - token_address=ADDRESS_DEFAULT, - amount=amount, -``` - -To track the status of this transaction: - -```python -# Wait for tx receipt -tx_receipt = zksync.zksync.wait_for_transaction_receipt( - tx_hash, timeout=240, poll_latency=0.5 -) -``` - -## Withdrawing funds - -There are two ways to withdraw funds from zkSync to Ethereum, calling the operation through L2 or L1. If the withdrawal -operation is called through L1, then the operator has a period of time during which he must process the transaction, -otherwise `PriorityMode` will be turned on. This ensures that the operator cannot stage the transaction. But in most -cases, a call via L2 is sufficient. - -```python -withdraw_tx_hash = wallet.withdraw( - WithdrawTransaction( - token = Token.create_eth().l1_address, - amount = Web3.to_wei(amount, "ether"))) -``` - -Assets will be withdrawn to the target wallet(if do not define the `to` address in the `withdraw` method's argument - -the sender address will be chosen as a destination) after the validity proof of the zkSync block with this transaction -is generated and verified by the mainnet contract. - -It is possible to wait until the validity proof verification is complete: - -```python -tx_receipt = zksync.zksync.wait_for_transaction_receipt( - withdraw_tx_hash, (timeout = 240), (poll_latency = 0.5)) -``` - -## Adding tokens to the standard bridge - -Adding tokens to the zkSync standard bridge can be done in a permissionless way. After adding a token to zkSync, it can -be used in all types of transactions. The documentation on adding tokens to zkSync can be found -[here](./accounts-l1-l2.md#adding-native-token-to-zksync). diff --git a/content/20.build/sdks/python/paymaster-utils.md b/content/20.build/sdks/python/paymaster-utils.md deleted file mode 100644 index 9aa0e339..00000000 --- a/content/20.build/sdks/python/paymaster-utils.md +++ /dev/null @@ -1,66 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Python SDK Paymaster Utilities | zkSync Docs ---- - -# Paymaster Utilities - -The -[paymaster utilities library](https://github.com/zksync-sdk/zksync2-python/blob/master/zksync2/manage_contracts/paymaster_utils.py) -contains essential utilities for using paymasters on zkSync Era. - -## Contract interfaces - -### `PaymasterFlowEncoder` - -Constant ABI definition for the -[Paymaster Flow Interface](https://github.com/matter-labs/era-contracts/blob/87cd8d7b0f8c02e9672c0603a821641a566b5dd8/l2-contracts/contracts/interfaces/IPaymasterFlow.sol). - -```python -encoder = PaymasterFlowEncoder(zk_web3) -``` - -## Functions - -### `encode_approval_based` - -Returns encoded input for an approval-based paymaster. - -#### Inputs - -| Parameter | Type | Description | -| --------------- | -------- | -------------------------------------------------------- | -| `address` | `HexStr` | The token address of the paymaster. | -| `min_allowance` | `int` | The minimal amount of token that can be used to pay fee. | -| `inner_input` | `bytes` | The input data to the paymaster. | - -```python -paymaster_params = PaymasterParams(**{ - "paymaster": paymaster_address, - "paymaster_input": zk_web3.to_bytes( - hexstr=PaymasterFlowEncoder(zk_web3).encode_approval_based(token_address, 1, b'')) -}) -``` - -### `encode_general` - -As above but for general-based paymaster. - -#### Inputs - -| Parameter | Type | Description | -| --------- | ------- | -------------------------------- | -| `inputs` | `bytes` | The input data to the paymaster. | - -```python -paymaster_params = PaymasterParams(**{ - "paymaster": paymaster_address, - "paymaster_input": zk_web3.to_bytes( - hexstr=PaymasterFlowEncoder(zk_web3).encode_general( b'')) -}) -``` - -Find out more about the [`PaymasterParams` type](./types.md). Check out the -[example](https://github.com/zksync-sdk/zksync2-examples/blob/main/python/15_use_paymaster.py) how to use paymaster. diff --git a/content/20.build/sdks/python/providers.md b/content/20.build/sdks/python/providers.md deleted file mode 100644 index 3238a6a2..00000000 --- a/content/20.build/sdks/python/providers.md +++ /dev/null @@ -1,384 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Python SDK Providers | zkSync Docs ---- - -# Providers - -A Web3 Provider object provides application-layer access to underlying blockchain networks. - -The [`zksync2`](https://pypi.org/project/zksync2/) library supports provider methods from the -[`web3.py`](https://web3py.readthedocs.io/en/stable/providers.html) library and supplies additional functionality. - -## `Provider` - -:::info - -- This doc details zkSync Era specific methods. -- `web3.py` implementations link to the - [web3.py Providers documentation](https://web3py.readthedocs.io/en/stable/providers.html). ::: - -### `init` - -Returns a zkSync Era `Provider` object. - -#### Inputs - -| Parameter | Type | Description | -| --------- | ---------------------------------------------------------------------------------------------------------------------- | -------------------------- | -| `web3` | string or [`ConnectionInfo`](https://web3py.readthedocs.io/en/stable/providers.html#provider-via-environment-variable) | Network RPC URL (optional) | - -```python -def __init__(self, web3: "Web3"): - super(ZkSync, self).__init__(web3) - self.main_contract_address = None - self.bridge_addresses = None -``` - -#### Example - -```python -from zksync2.module.module_builder import ZkSyncBuilder - -zksync = ZkSyncBuilder.build("https://sepolia.era.zksync.dev") -``` - -### `estimate_fee` - -Returns an estimated [`Fee`](./types.md#fee) for requested transaction. - -#### Inputs - -| Parameter | Type | Description | -| ------------- | --------------------------------------- | -------------------- | -| `transaction` | [`Transaction`](./types.md#transaction) | Transaction request. | - -```python -nonce = self.web3.zksync.get_transaction_count(self.account.address, ZkBlockParams.COMMITTED.value) - gas_price = self.web3.zksync.gas_price - - func_call = TxFunctionCall(chain_id=self.chain_id, - nonce=nonce, - from_=self.account.address, - to=self.account.address, - gas_limit=0, - gas_price=gas_price) - estimated_fee = self.web3.zksync.zks_estimate_fee(func_call.tx) -``` - -### `eth_estimate_gas` - -Returns an estimate(`int`) of the amount of gas required to submit a transaction to the network. | Parameter | Type | -Description | | ------------- | ----------------------------------------------------------------------------------------------------- | --------------------- | | `transaction` | [`Transaction`](./types.md#transaction) | Transaction request. | -[web3.py implementation.](https://web3py.readthedocs.io/en/stable/web3.eth.html#web3.eth.Eth.estimate_gas) - -### `zks_estimate_gas_l1_to_l2` - -Returns an estimate of the amount of gas required to submit a transaction from L1 to L2 as a `int` object. - -Calls the [`zks_estimateL1ToL2`](../../api.md#zks-estimategasl1tol2) JSON-RPC method. - -### `estimateGasTransfer` - -Returns the gas estimation for a transfer transaction. - -Calls internal method [`getTransferTx`](https://github.com/zksync-sdk/zksync-ethers/blob/ethers-v5/src/utils.ts) to get -the transfer transaction and sends it to the [`eth_estimate_gas`](#eth-estimate-gas) method. - -#### Inputs - -| Parameter | Type | Description | -| ------------- | --------------------------------------- | ------------------------- | -| `transaction` | [`Transaction`](./types.md#transaction) | Transaction. | -| `token` | Address string | Token address (optional). | - -```python -def zks_estimate_gas_transfer(self, transaction: Transaction, token_address: HexStr = ADDRESS_DEFAULT) -> int: - - if token_address is not None and not is_eth(token_address): - transfer_params = (transaction["to"], transaction["value"]) - transaction["value"] = 0 - contract = self.contract(Web3.to_checksum_address(token_address), abi=get_erc20_abi()) - transaction["data"] = contract.encodeABI("transfer", args=transfer_params) - transaction["nonce"] = self.get_transaction_count(transaction["from_"], ZkBlockParams.COMMITTED.value) - - return self.eth_estimate_gas(transaction) -``` - -### `estimateL1ToL2Execute` - -Returns gas estimation for an L1 to L2 execute operation. - -#### Inputs - -| Parameter | Type | -| ------------- | --------------------------------------- | -| `Transaction` | [`Transaction`](./types.md#transaction) | - -```python -def zks_estimate_l1_to_l2_execute(self, transaction: Transaction) -> int: - if transaction["from"] is None: - transaction["from"] = self.account.create().address - - return self.zks_estimate_gas_l1_to_l2(transaction) -``` - -### `zks_get_all_account_balances` - -Returns all balances for confirmed tokens given by an account address. - -Calls the [`zks_getAllAccountBalances`](../../api.md#zks-getallaccountbalances) JSON-RPC method. - -### `zks_get_balance` - -Returns the user's balance as a `int` object for an (optional) block tag and (optional) token. - -When block and token are not supplied, `committed` and `ETH` are the default values. - -#### Inputs - -| Name | Description | -| ------------- | -------------------------------------------------------------------------- | -| address | User's address. | -| block_tag | Block tag for getting the balance on. Latest `committed` block is default. | -| token_address | The address of the token. ETH is default. | - -```python - def zks_get_balance(self, address: HexStr, block_tag = ZkBlockParams.COMMITTED.value, token_address: HexStr = None) -> int: - if token_address is None or is_eth(token_address): - return self.get_balance(to_checksum_address(address), block_tag) - - try: - token = self.contract(Web3.to_checksum_address(token_address), abi=get_erc20_abi()) - return token.functions.balanceOf(address).call() - except: - return 0 -``` - -#### Example - -```python -zksync_web3 = ZkSyncBuilder.build("https://sepolia.era.zksync.dev") - -#Find the USDC ADDRESS in https://zksync2-testnet.zkscan.io/address/0x0faF6df7054946141266420b43783387A78d82A9/transactions -USDC_L2_ADDRESS = "" -# Get the USDC balance from your account using your address. Get your address from https://zksync2-testnet.zkscan.io/txs -usdc_balance = zksync_web3.zksync.zks_get_balance("", "latest", USDC_L2_ADDRESS) - -// Getting ETH balance -eth_balance = zksync_web3.zksync.zks_get_balance("") -``` - -### `get_block` - -Returns block from the network.Throws `BlockNotFound` error if the block is not found - -[web3.py implementation.](https://web3py.readthedocs.io/en/stable/web3.eth.html#web3.eth.Eth.get_block) - -### `zks_get_block_details` - -Returns additional zkSync-specific information about the L2 block. - -Calls the [`zks_getBlockDetails`](../../api.md#zks-getblockdetails) JSON-RPC method. - -### `getContractAccountInfo` - -Returns the version of the supported account abstraction and nonce ordering from a given contract address. - -#### Inputs - -| Name | Description | -| ------- | ---------------- | -| address | Contract address | - -```python -def get_contract_account_info(self, address: HexStr) -> ContractAccountInfo: - deployer = self.contract(address=Web3.to_checksum_address(ZkSyncAddresses.CONTRACT_DEPLOYER_ADDRESS.value), abi=icontract_deployer_abi_default()) - - data = deployer.functions.getAccountInfo(Web3.to_checksum_address(address)).call() - - return ContractAccountInfo(account_abstraction_version=data[0],account_nonce_ordering=data[1]) -``` - -### `zks_get_bridge_contracts` - -Returns the addresses of the default zkSync Era bridge contracts on both L1 and L2. - -```python -def zks_get_bridge_contracts(self) -> BridgeAddresses: - if self.bridge_addresses is None: - self.bridge_addresses = self._zks_get_bridge_contracts() - return self.bridge_addresses -``` - -### `getL1BatchBlockRange` - -Returns the range of blocks contained within a batch given by batch number. - -Calls the [`zks_getL1BatchBlockRange`](../../api.md#zks-getl1batchblockrange) JSON-RPC method. - -```python -def zks_get_l1_batch_block_range(self, l1_batch_number: int) -> BlockRange: - return self._zks_get_l1_batch_block_range(l1_batch_number) -``` - -### `zks_get_l1_batch_details` - -Returns data pertaining to a given batch. - -Calls the [`zks_getL1BatchDetails`](../../api.md#zks-getl1batchdetails) JSON-RPC method. - -### `zks_l1_batch_number` - -Returns the latest L1 batch number. - -Calls the [`zks_getL1BatchNumber`](../../api.md#zks-l1batchnumber) JSON-RPC method. - -### `getL2TransactionFromPriorityOp` - -Returns a transaction object from a given Ethers -[`TransactionResponse`](https://docs.ethers.org/v5/api/providers/types/#providers-TransactionResponse) object. - -#### Inputs - -| Name | Description | -| ------------- | -------------------- | -| tx_receipt | Transaction receipt. | -| main_contract | ZkSync main contract | - -```python -def get_l2_transaction_from_priority_op(self, tx_receipt, main_contract: Contract): - l2_hash = self.get_l2_hash_from_priority_op(tx_receipt, main_contract) - self.wait_for_transaction_receipt(l2_hash) - return self.get_transaction(l2_hash) -``` - -### `zks_get_log_proof` - -Returns the proof for a transaction's L2 to L1 log sent via the L1Messenger system contract. - -Calls the [`zks_getL2ToL1LogProof`](../../api.md#zks-getl2tol1logproof) JSON-RPC method. - -### `zks_main_contract` - -Returns the main zkSync Era smart contract address. - -Calls the [`zks_getMainContract`](../../api.md#zks-getmaincontract) JSON-RPC method. - -```python -def zks_main_contract(self) -> HexStr: - if self.main_contract_address is None: - self.main_contract_address = self._zks_main_contract() - return self.main_contract_address -``` - -### `zks_get_l2_to_l1_msg_proof` - -Returns the proof for a message sent via the L1Messenger system contract. - -Calls the [`zks_getL2ToL1MsgProof`](../../api.md#zks-getl2tol1msgproof) JSON-RPC method. - -```python -def zks_get_l2_to_l1_msg_proof(self, - block: int, - sender: HexStr, - message: str, - l2log_pos: Optional[int]) -> ZksMessageProof: - return self._zks_get_l2_to_l1_msg_proof(block, sender, message, l2log_pos) -``` - -### `zks_get_testnet_paymaster_address` - -Returns the [testnet paymaster](../../quick-start/useful-address.md#sepolia-contract-addresses) address if available, or -null. - -```python -def zks_get_testnet_paymaster_address(self) -> HexStr: - return Web3.to_checksum_address(self._zks_get_testnet_paymaster_address()) -``` - -### `zks_get_transaction_details` - -Returns data from a specific transaction given by the transaction hash. - -Calls the [`getTransactionDetails`](../../api.md#zks-gettransactiondetails) JSON-RPC method. - -### `eth_get_transaction_receipt` - -Returns the transaction receipt from a given hash number. - -### `zks_l1_chain_id` - -Returns the chain id of the underlying L1. - -Calls the [`zks_L1ChainId`](../../api.md#zks-l1chainid) JSON-RPC method. - -### `l1TokenAddress` - -Returns the L1 token address equivalent for a L2 token address as they are not equal. ETH's address is set to zero -address. - -:::warning Only works for tokens bridged on default zkSync Era bridges. ::: - -#### Inputs - -| Name | Description | -| ----- | ------------------------------- | -| token | The address of the token on L2. | - -```python -def l1_token_address(self, token: HexStr) -> HexStr: - if is_eth(token): - return ADDRESS_DEFAULT - bridge_address = self.zks_get_bridge_contracts() - l2_weth_bridge = self.contract(Web3.to_checksum_address(bridge_address.weth_bridge_l2), - abi=l2_bridge_abi_default()) - try: - l1_weth_token = l2_weth_bridge.functions.l1TokenAddress(token).call() - if not is_eth(l1_weth_token): - return l1_weth_token - except: - pass - - erc20_bridge = self.contract(Web3.to_checksum_address(bridge_address.erc20_l2_default_bridge), - abi=l2_bridge_abi_default()) - - return erc20_bridge.functions.l1TokenAddress(token).call() -``` - -### `l2TokenAddress` - -Returns the L2 token address equivalent for a L1 token address as they are not equal. ETH's address is set to zero -address. - -:::warning Only works for tokens bridged on default zkSync Era bridges. ::: - -#### Inputs - -| Name | Description | -| ----- | ------------------------------- | -| token | The address of the token on L1. | - -```python -def l2_token_address(self, token: HexStr) -> HexStr: - if is_eth(token): - return ADDRESS_DEFAULT - bridge_address = self.zks_get_bridge_contracts() - l2_weth_bridge = self.contract(Web3.to_checksum_address(bridge_address.weth_bridge_l2), - abi=l2_bridge_abi_default()) - try: - l1_weth_token = l2_weth_bridge.functions.l2TokenAddress(token).call() - if not is_eth(l1_weth_token): - return l1_weth_token - except: - pass - - erc20_bridge = self.contract(Web3.to_checksum_address(bridge_address.erc20_l2_default_bridge), - abi=l2_bridge_abi_default()) - - return erc20_bridge.functions.l2TokenAddress(token).call() -``` diff --git a/content/20.build/sdks/python/types.md b/content/20.build/sdks/python/types.md deleted file mode 100644 index f8c88b46..00000000 --- a/content/20.build/sdks/python/types.md +++ /dev/null @@ -1,191 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Python SDK Types | zkSync Docs ---- - -# Types - -All the types which are used in the SDK are referenced here: - -```python -ADDRESS_DEFAULT = HexStr("0x" + "0" * 40) - -TokenAddress = NewType('token_address', HexStr) -TransactionHash = Union[Hash32, HexBytes, HexStr] -L2WithdrawTxHash = Union[Hash32, HexBytes, HexStr] -From = NewType("from", int) -Limit = NewType('limit', int) - - -class ZkBlockParams(Enum): - COMMITTED = "committed" - FINALIZED = "finalized" - - -class EthBlockParams(Enum): - PENDING = "pending" - LATEST = "latest" - - -@dataclass -class Token: - l1_address: HexStr - l2_address: HexStr - symbol: str - decimals: int - - def format_token(self, amount) -> str: - return str(Decimal(amount) / Decimal(10) ** self.decimals) - - def is_eth(self) -> bool: - return self.l1_address == ADDRESS_DEFAULT and self.symbol == "ETH" - - def into_decimal(self, amount: int) -> Decimal: - return Decimal(amount).scaleb(self.decimals) // Decimal(10) ** self.decimals - - def to_int(self, amount: Union[Decimal, int]) -> int: - if isinstance(amount, int): - amount = Decimal(amount) - return int(amount * (Decimal(10) ** self.decimals)) - - @staticmethod - def create_eth() -> 'Token': - return Token(ADDRESS_DEFAULT, ADDRESS_DEFAULT, "ETH", 18) - - -@dataclass -class BridgeAddresses: - l1_eth_default_bridge: HexStr - l2_eth_default_bridge: HexStr - l1_erc20_default_bridge: HexStr - l2_erc20_default_bridge: HexStr - - -@dataclass -class PaymasterParams(dict): - paymaster: HexStr - paymaster_input: bytes -``` - -# Transaction - -```python -Transaction = TypedDict( - "Transaction", - { - "chain_id": int, - "nonce": int, - "from": HexStr, - "to": HexStr, - "gas": int, - "gasPrice": int, - "maxPriorityFeePerGas": int, - "value": int, - "data": HexStr, - "transactionType": int, - "accessList": Optional[AccessList], - "eip712Meta": EIP712Meta, - }, - total=False, -) -``` - -# Fee - -```python -@dataclass -class Fee: - gas_limit: int = 0 - max_fee_per_erg: int = 0 - max_priority_fee_per_erg : int = 0 - gas_per_pub_data_limit: int = 0 -``` - -# TransferTransaction - -```python -@dataclass -class TransferTransaction: - to: HexStr - amount: int = 0 - token_address: HexStr = None - chain_id: int = None - nonce: int = None - gas_limit: int = 0 - gas_price: int = 0 - max_priority_fee_per_gas = 100_000_000 - gas_per_pub_data: int = 50000 -``` - -# WithdrawTransaction - -```python -@dataclass -class WithdrawTransaction: - token: HexStr - amount: int - to: HexStr = None - bridge_address: HexStr = None - options: TransactionOptions = None -``` - -# L1BridgeContracts - -```python -@dataclass -class L1BridgeContracts: - erc20: Contract - weth: Contract -``` - -# TransactionOptions - -```python -@dataclass -class TransactionOptions: - chain_id: int = None - nonce: int = None - value: int = None - gas_price: int = None - max_fee_per_gas: int = None - max_priority_fee_per_gas: int = None - gas_limit: int = None -``` - -# DepositTransaction - -```python -@dataclass -class DepositTransaction: - token: HexStr - amount: int = None - to: HexStr = None - operator_tip: int = 0 - bridge_address: HexStr = None - approve_erc20: bool = False - l2_gas_limit: int = None - gas_per_pubdata_byte: int = DEPOSIT_GAS_PER_PUBDATA_LIMIT - custom_bridge_data: bytes = None - refund_recipient: HexStr = None - l2_value: int = 0 - options: TransactionOptions = None -``` - -# RequestExecuteCallMsg - -```python -@dataclass -class RequestExecuteCallMsg: - contract_address: HexStr - call_data: Union[bytes, HexStr] - from_: HexStr = None - l2_gas_limit: int = 0 - l2_value: int = 0 - factory_deps: List[bytes] = None - operator_tip: int = 0 - gas_per_pubdata_byte: int = DEPOSIT_GAS_PER_PUBDATA_LIMIT - refund_recipient: HexStr = None - options: TransactionOptions = None -``` diff --git a/content/20.build/sdks/rust/contract-deployment-and-interaction.md b/content/20.build/sdks/rust/contract-deployment-and-interaction.md deleted file mode 100644 index 06159ec7..00000000 --- a/content/20.build/sdks/rust/contract-deployment-and-interaction.md +++ /dev/null @@ -1,208 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Contract Deployment and Interaction | zkSync Docs ---- - -# Contract Deployment and Interaction - -This guide shows you how to deploy a smart contract to zkSync and call its methods using the [`zksync-web3-rs`][repo] -SDK. - -This is what we're going to do: - -- Deploy, and verify a smart contract on zkSync Era testnet that stores a greeting message. -- Call a `view` method that retrieves the greeting message. -- Perform a transaction that updates the greeting message. - -:::info Project available as an example in the SDK REPO This entire tutorial can be easily run using -`cargo run --example contract-deployment` which is [available under the `examples/` directory][code] in the -[`zksync-web3-rs`][repo]. ::: - -## Prerequisites - -This tutorial assumes that you know how to create a rust project and add [`zksync-web3-rs`][repo] as a dependency. We -recommend having followed the [Rust SDK Getting started](./getting-started.md) tutorial first. - -Also, since our SDK does not provide wrappers for the compiler, building the `Greeter` contract is out of the scope of -this tutorial. We will provide the ABI and compilation output together with the source code for the smart contract. - -## The Greeter contract - -In this tutorial, we are going to work with the `Greeter.sol` contract. - -```solidity -//SPDX-License-Identifier: Unlicense -pragma solidity ^0.8.8; - -contract Greeter { - string private greeting; - - constructor(string memory _greeting) { - greeting = _greeting; - } - - function greet() public view returns (string memory) { - return greeting; - } - - function setGreeting(string memory _greeting) public { - greeting = _greeting; - } -} -``` - -## Connecting to zkSync Era - -To interact with the zkSync network users need to know the endpoint of the operator node. In this tutorial, we will be -using the _zkSync Era In-Memory Node_ from [`matter-labs/era-test-node`][test-node]. The test node a zkSync Era node -(L2) on port `8011`. You can connect to the zkSync Era network using the following code: - -```rust -use std::str::FromStr; -use zksync_web3_rs::providers::{Middleware, Provider}; -use zksync_web3_rs::signers::{LocalWallet, Signer}; -use zksync_web3_rs::ZKSWallet; - -// This is the default url for a local `era-test-node` instance. -static ERA_PROVIDER_URL: &str = "http://127.0.0.1:8011"; - -// This is the private key for one of the rich wallets that come bundled with the era-test-node. -static PRIVATE_KEY: &str = "7726827caac94a7f9e1b160f7ea819f172f7b6f9d2a97f992c38edeab82d4110"; - -let zk_wallet = { - let era_provider = Provider::try_from(ERA_PROVIDER_URL).unwrap(); - - let chain_id = era_provider.get_chainid().await.unwrap(); - let l2_wallet = LocalWallet::from_str(PRIVATE_KEY) - .unwrap() - .with_chain_id(chain_id.as_u64()); - ZKSWallet::new(l2_wallet, None, Some(era_provider.clone()), None).unwrap() -}; -``` - -## Deploy the Greeter contract - -Before we begin, you'll need the compiled contract bytecode [`./Greeter.bin`][bin] and its Application Binary Interface -(ABI) [`./Greeter.abi`][abi]. These files define the contract's code and its interface, respectively. - -1. The ABI file defines the interface and methods of the smart contract. Download it from [here][abi] and place it on - `./Greeter.abi`. - -2. The bytecode file contains the compiled binary code of the Greeter smart contract. Download it from [here][bin] and - place it on `./Greeter.bin`. - -3. Use the following snippet to deploy the contract to zkSync Era. - -```rust -use ethers::abi::Abi; -use zksync_web3_rs::zks_wallet::DeployRequest; - -static CONTRACT_BIN: &str = include_str!("./Greeter.bin"); -static CONTRACT_ABI: &str = include_str!("./Greeter.abi"); - -// Deploy contract: -let contract_address = { - // Read both files from disk: - let abi = Abi::load(CONTRACT_ABI.as_bytes()).unwrap(); - let contract_bin = hex::decode(CONTRACT_BIN).unwrap().to_vec(); - - // DeployRequest sets the parameters for the constructor call and the deployment transaction. - let request = DeployRequest::with(abi, contract_bin, vec!["Hey".to_owned()]) - .from(zk_wallet.l2_address()); - - // Send the deployment transaction and wait until we receive the contract address. - let address = zk_wallet.deploy(&request).await.unwrap(); - - println!("Contract address: {:#?}", address); - - address -}; -``` - -**Congratulations! You have deployed and verified a smart contract to zkSync Era Testnet** 🎉 - -## Calling the `greet()` view method - -In this section, we'll show you how to interact with the Greeter smart contract that you previously deployed to zkSync -Era. Specifically, we'll demonstrate how to call the `greet()` view method of the contract, which allows you to retrieve -a greeting message from the blockchain. - -The following Rust code snippet demonstrates how to call the `greet()` method and display the returned message: - -```rust -use zksync_web3_rs::zks_wallet::CallRequest; - -// Call the greet view method: -{ - let era_provider = zk_wallet.get_era_provider().unwrap(); - let call_request = CallRequest::new(contract_address, "greet()(string)".to_owned()); - - let greet = ZKSProvider::call(era_provider.as_ref(), &call_request) - .await - .unwrap(); - - println!("greet: {}", greet[0]); -} -``` - -## Updating the Greeting Message with `setGreeting` - -In this section, we'll guide you through the process of updating the greeting message stored in the Greeter smart -contract. The `setGreeting` method is used to change the `greeting` message. Since it alters the state of the contract -on the blockchain, it requires a signed transaction. - -The following code snippet sends a signed transaction that calls the `setGreeting` method. The transaction is signed -using the `l2_wallet` stored in the `ZKSWallet`. - -```rust -// Perform a signed transaction calling the setGreeting method -{ - let receipt = zk_wallet - .get_era_provider() - .unwrap() - .clone() - .send_eip712( - &zk_wallet.l2_wallet, - contract_address, - "setGreeting(string)", - Some(["Hello".into()].into()), - None, - ) - .await - .unwrap() - .await - .unwrap() - .unwrap(); - - println!( - "setGreeting transaction hash {:#?}", - receipt.transaction_hash - ); -}; -``` - -After successfully updating the greeting message, you may want to confirm that the change has taken effect. To do this, -we call the greet() method again and display the updated greeting message: - -```rust -{ - let era_provider = zk_wallet.get_era_provider().unwrap(); - let call_request = CallRequest::new(contract_address, "greet()(string)".to_owned()); - - let greet = ZKSProvider::call(era_provider.as_ref(), &call_request) - .await - .unwrap(); - - println!("greet: {}", greet[0]); -} -``` - -[repo]: https://github.com/lambdaclass/zksync-web3-rs/ -[code]: https://github.com/lambdaclass/zksync-web3-rs/tree/main/examples/contract-deployment -[test-node]: https://github.com/matter-labs/era-test-node/ -[abi]: - https://raw.githubusercontent.com/lambdaclass/zksync-web3-rs/7ae7bec0323d878beac2b74f00256f8589b4a206/examples/contract-deployment/Greeter.abi -[bin]: - https://raw.githubusercontent.com/lambdaclass/zksync-web3-rs/7ae7bec0323d878beac2b74f00256f8589b4a206/examples/contract-deployment/Greeter.bin diff --git a/content/20.build/sdks/rust/getting-started.md b/content/20.build/sdks/rust/getting-started.md deleted file mode 100644 index 4dc00fb5..00000000 --- a/content/20.build/sdks/rust/getting-started.md +++ /dev/null @@ -1,314 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Rust SDK Getting Started | zkSync Docs ---- - -# Getting Started - -## Concept - -While most of the existing SDKs should work out of the box, deploying smart contracts or using unique zkSync features, -like paying fees in other tokens, requires providing additional fields to those that Ethereum transactions have by -default. - -To provide easy access to all of the features of zkSync Era, the [`zksync-web3-rs`][sdk] Rust SDK was created, which -builds upon the [`ethers`][ethers] library. This section serves as its reference. - -## Adding dependencies - -Add the following dependencies to your `Cargo.toml` file: - -```toml -zksync-web3-rs = "0.1.1" -``` - -Consider adding [`tokio`][tokio] as dependency since we are using a lot of async/await functions. If this example is -meant to be done in the main function the `#[tokio::main]` annotation is needed. - -```toml -tokio = { version = "1", features = ["macros", "process"] } -``` - -```rust -#[tokio::main(flavor = "current_thread")] -async fn main() { - // ... -} -``` - -## Connecting to zkSync Era - -To interact with the zkSync network users need to know the endpoint of the operator node. In this tutorial, we will be -using the `localnet` from [`matter-labs/local-setup`][localnet]. The localnet runs both an Ethereum node (L1) on port -`8545` and an Era node (L2) on port `3050`. You can connect to the zkSync Era network using the following code: - -```rust -use zksync_web3_rs::providers::{Http, Middleware, Provider}; -// The trait `ZKSProvider` extends `Provider` with specific methods for zkSync Era. -use zksync_web3_rs::zks_provider::ZKSProvider; - -static L2_URL: &str = "http://localhost:3050"; - -#[tokio::main(flavor = "current_thread")] -async fn main() { - let l2_provider: Provider = - Provider::try_from(L2_URL).expect("could not instantiate HTTP Provider"); - - // Test the connection with the zkSync Era node: - let l2_chain_id = l2_provider - .get_chainid() - .await - .expect("Could not retrieve L2 chain id"); - println!("l2_chain_id = {l2_chain_id}"); - - let l1_chain_id = l2_provider - .get_l1_chain_id() - .await - .expect("Could not retrieve L1 chain id from zkSync Era node"); - println!("l1_chain_id = {l1_chain_id}"); -} -``` - -Which should print: - -``` -l2_chain_id = 270 -l1_chain_id = 9 -``` - -Here, the trait `ZKSProvider` extended the `Provider` struct adding zkSync Era specific functionality. In this -case, the method `.get_chainid()` comes from `ethers` while the method `get_l1_chain_id` comes from the `ZKSProvider` -and hits an era-specific API. - -## Connecting to Ethereum layer-1 - -To perform operations that interact with both layers, we will also need to instantiate a provider for the Ethereum -layer-1 associated with our zkSync Era blockchain. - -```rust -static L1_URL: &str = "http://localhost:8545"; - -let l1_provider = - Provider::::try_from(L1_URL).expect("Could not instantiate L1 Provider"); -``` - -## Creating a wallet - -To control an account in zkSync, use the `zksync_web3_rs::ZKSWallet` struct. It can sign transactions with keys stored -in `zksync_web3_rs::signers::{LocalWallet, Signer}` and send transactions to the zkSync network using a `Provider`. - -```rust -use std::str::FromStr; -use zksync_web3_rs::signers::LocalWallet; -use zksync_web3_rs::signers::Signer; -use zksync_web3_rs::ZKSWallet; - -static WALLET_1_PRIVATE_KEY: &str = - "0x7726827caac94a7f9e1b160f7ea819f172f7b6f9d2a97f992c38edeab82d4110"; - -let zk_wallet_1 = { - let l2_wallet = LocalWallet::from_str(WALLET_1_PRIVATE_KEY) - .expect("Invalid private key") - .with_chain_id(l2_chain_id.as_u64()); - - ZKSWallet::new( - l2_wallet, - None, - Some(l2_provider.clone()), - Some(l1_provider.clone()), - ) - .unwrap() -}; -``` - -## Checking zkSync account balance - -You can use `ZKSWallet` `eth_balance` and `era_balance` to get L1 and L2 balances respectively: - -```rust -println!( - "Wallet-1 balance (L1): {}", - zk_wallet_1.eth_balance().await.unwrap() -); -println!( - "Wallet-1 balance (L2): {}", - zk_wallet_1.era_balance().await.unwrap() -); -``` - -## Depositing funds - -Let's deposit `1.0 ETH` to our zkSync account. - -```rust -use zksync_web3_rs::utils::parse_units; -use zksync_web3_rs::zks_wallet::DepositRequest; - -let deposit_transaction_hash = { - let amount = parse_units("0.1", "ether").unwrap(); - let request = DepositRequest::new(amount.into()); - zk_wallet_1 - .deposit(&request) - .await - .expect("Failed to perform deposit transaction") -}; - -println!("Deposit transaction hash: {:?}", deposit_transaction_hash); -``` - -**NOTE:** Each token inside zkSync has an address. If `ERC-20` tokens are being bridged, you should supply the token's -L1 address by calling the `token` method from `DepositRequest`, or zero address -(`0x0000000000000000000000000000000000000000`) if you want to deposit ETH. Note, that for the `ERC-20` tokens the -address of their corresponding L2 token will be different from the one on Ethereum. - -After the transaction is submitted to the Ethereum node, its status can be tracked using the transaction hash: - -```rust -let deposit_l1_receipt = l1_provider - .get_transaction_receipt(deposit_transaction_hash) - .await - .unwrap() - .unwrap(); - -println!( - "Deposit L1 receipt status: {}", - deposit_l1_receipt.status.unwrap() -); -``` - -Then, we can check the resulting account balances: - -```rust -println!( - "Wallet-1 balance (L1): {}", - zk_wallet_1.eth_balance().await.unwrap() -); -println!( - "Wallet-1 balance (L2): {}", - zk_wallet_1.era_balance().await.unwrap() -); -``` - -## Performing a transfer - -Now, let's create a second wallet and transfer some funds into it. Note that it is possible to send assets to any fresh -Ethereum account, without preliminary registration! - -```rust -static WALLET_2_PRIVATE_KEY: &str = - "0xac1e735be8536c6534bb4f17f06f6afc73b2b5ba84ac2cfb12f7461b20c0bbe3"; - -let zk_wallet_2 = { - let l2_wallet = LocalWallet::from_str(WALLET_2_PRIVATE_KEY) - .expect("Invalid private key") - .with_chain_id(l2_chain_id.as_u64()); - - ZKSWallet::new( - l2_wallet, - None, - Some(l2_provider.clone()), - Some(l1_provider.clone()), - ) - .unwrap() -}; -``` - -We can check it's balances to verify that it has no funds: - -```rust -println!( - "L1 balance for the new wallet: {}", - zk_wallet_2.eth_balance().await.unwrap() -); -println!( - "L2 balance for the new wallet: {}", - zk_wallet_2.era_balance().await.unwrap() -); -``` - -``` -L1 balance for the new wallet: 0 -L2 balance for the new wallet: 0 -``` - -Let's transfer `1 ETH` to the new account: - -The `transfer` method from the `ZSKWallet` structure is a helper method that enables transferring `ETH` or any `ERC-20` -token within a single interface on the layer 2. - -```rust -use zksync_web3_rs::zks_wallet::TransferRequest; - -let transfer_transaction_hash = { - let transfer_amount = parse_units("0.05", "ether").unwrap(); - let transfer_request = TransferRequest::new(transfer_amount.into()) - .to(zk_wallet_2.l2_address()) - .from(zk_wallet_1.l2_address()); - zk_wallet_1.transfer(&transfer_request, None).await.unwrap() -}; -``` - -``` -Transfer transaction hash: 0x84d3…8ced -``` - -After the transfer transaction is submitted to the zkSync Era node, its status can be tracked using the transaction -hash: - -```rust -let transfer_receipt = l2_provider - .get_transaction_receipt(transfer_transaction_hash) - .await - .unwrap() - .unwrap(); - -println!( - "Transfer receipt status: {}", - transfer_receipt.status.unwrap() -); -``` - -``` -Transfer receipt status: 1 -``` - -## Withdrawing funds - -```rust -use zksync_web3_rs::zks_wallet::WithdrawRequest; - -let withdraw_transaction_hash_l2 = { - let amount = parse_units("0.025", "ether").unwrap(); - let request = WithdrawRequest::new(amount.into()).to(zk_wallet_2.l1_address()); - zk_wallet_2.withdraw(&request).await.unwrap() -}; - -let withdraw_receipt_l2 = l2_provider - .wait_for_finalize(withdraw_transaction_hash_l2, None, None) - .await - .unwrap(); -``` - -Assets will be withdrawn to the target wallet after the validity proof of the zkSync block with this transaction is -generated and verified by the mainnet contract. - -It is possible to wait until the validity proof verification is complete using the `finalize_withdraw` method: - -```typescript -let withdraw_transaction_hash_l1 = zk_wallet_2.finalize_withdraw(withdraw_transaction_hash_l2).await.unwrap(); - -// Then, get the transaction receipt: -let withdraw_receipt_l1 = zk_wallet_2 - .get_eth_provider() - .unwrap() - .get_transaction_receipt(withdraw_transaction_hash_l1) - .await.unwrap() - .unwrap(); -``` - -[sdk]: https://github.com/lambdaclass/zksync-web3-rs/ -[ethers]: https://crates.io/crates/ethers -[tokio]: https://tokio.rs/ -[localnet]: https://github.com/matter-labs/local-setup diff --git a/content/20.build/sdks/swift/accounts-l1-l2.md b/content/20.build/sdks/swift/accounts-l1-l2.md deleted file mode 100644 index ffef7041..00000000 --- a/content/20.build/sdks/swift/accounts-l1-l2.md +++ /dev/null @@ -1,41 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Swift SDK L1/L2 Transactions | zkSync Docs ---- - -# Accounts: L1<->L2 Transactions - -This section explores the methods which allow the [account](./accounts.md) to send transactions among both L1 to L2 -networks. - -If you want some background on how L1<->L2 interaction works on zkSync, go through the -[introduction](../../developer-reference/l1-l2-interop.md). - -Full examples of actions below are available on the [getting started](./getting-started.md) page. - -## Deposit - -`WalletL1` and `Wallet` objects provide a deposit workflow. For more information, please refer to the method -specification [`Deposit`](accounts.md#deposit). - -## Request execute - -`WalletL1` and `Wallet` objects provide an option to request execution of L2 transaction from L1. For more information, -please refer to the method specification [`RequestExecute`](accounts.md#requestexecute). - -## Base cost - -`WalletL1` and `Wallet` objects provide an option to calculate base cost for L2 transaction. For more information, -please refer to the method specification [`BaseCost`](accounts.md#basecost). - -## Claim failed deposit - -`WalletL1` and `Wallet` objects provide a claim fail deposit workflow. For more information, please refer to the method -specification [`ClaimFailedDeposit`](accounts.md#claimfaileddeposit). - -## Withdrawal - -`WalletL2` and `Wallet` objects provide a withdrawal workflow. For more information, please refer to the method -specification [`Withdraw`](accounts.md#withdraw). diff --git a/content/20.build/sdks/swift/accounts.md b/content/20.build/sdks/swift/accounts.md deleted file mode 100644 index 4545e6f8..00000000 --- a/content/20.build/sdks/swift/accounts.md +++ /dev/null @@ -1,711 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Swift SDK Accounts | zkSync Docs ---- - -# Accounts - -## Overview - -The `accounts` package provides abstractions that wrap operations that interact with an account. An account typically -contains a private key, allowing it to sign various types of payloads. These are the following interfaces that provide -account operations for different purposes: - -- `Signer` provides support for signing EIP-712 transactions as well as other types of transactions -- `AdapterL1` is associated with an account and provides common operations on the L1 network for the associated account. -- `AdapterL2` is associated with an account and provides common operations on the L2 network for the associated account. -- `Deployer` is associated with an account and provides deployment of smart contracts and smart accounts on the L2 - network for the associated account. -- `Adapter` consists of `AdapterL1`, `AdapterL2`, and `Deployer` interfaces. - -These are the following objects that provide account operations: - -- `BaseSigner` implements the `Signer` interface. -- `WalletL1` implements the `AdapterL1` interface. -- `WalletL2` implements the `AdapterL2` interface. -- `BaseDeployer` implements the `Deployer` interface. -- `Wallet` implements the `Adapter` interface. - -In most cases, `Wallet` should be used because it provides all the necessary operations. Other objects and interfaces -are separated to make the SDK more flexible and extensible. - -## `BaseSigner` - -### `Init` - -Creates a new instance of `BaseSigner` based on the credentials. - -```swift -BaseSigner(credentials, chainId: chainId) -``` - -### `Address` - -Returns the address associated with the signer. - -```swift -signer.address: String -``` - -### `Domain` - -Returns the EIP-712 domain used for signing. - -```swift -signer.domain: EIP712Domain -``` - -### `PrivateKey` - -Returns the private key associated with the signer. - -```swift -signer.credentials.privateKey: Data -``` - -### `SignHash` - -Signs the given hash using the signer's private key and returns the signature. The hash should be the 32-byte hash of -the data to be signed. - -```swift -signer.signMessage(message) -``` - -### `SignTypeData` - -Signs the given EIP-712 typed data using the signer's private key and returns the signature. The domain parameter is the -EIP-712 domain separator, and the data parameter is the EIP-712 typed data. - -```swift -signer.signTypedData(domain, typedData: typeddata) -``` - -## `WalletL1` - -### `Init` - -Creates an instance of WalletL1 associated with the account provided by the signer. - -```swift -WalletL1(zkSync, ethClient: ethClient, web3: web3, ethSigner: signer) -``` - -#### Example - -```swift -let credentials = Credentials() -let chainId = try! zkSync.web3.eth.getChainIdPromise().wait() -let zkSync: ZkSync = ZkSyncImpl(URL(string: "https://sepolia.era.zksync.dev")!) -let ethereum: web3 = try! Web3.new(URL(string: "https://rpc.ankr.com/eth_sepolia")!) -let signer = BaseSigner(credentials, chainId: chainId) -let wallet = WalletL1(zkSync, ethClient: ethClient, web3: web3, ethSigner: signer) -``` - -### `MainContract` - -Returns the zkSync L1 smart contract. - -```swift -func mainContract() async throws -> String -``` - -#### Example - -```swift -try await self.zkSync.mainContract() -``` - -### `L1BridgeContracts` - -Returns L1 bridge contracts. - -```swift -func L1BridgeContracts() async throws -> BridgeAddresses -``` - -#### Example - -```swift -try await wallet.L1BridgeContracts() -``` - -### `BalanceL1` - -Returns the balance of the specified token on L1 that can be either ETH or any ERC20 token. - -#### Inputs - -| Parameter | Type | Description | -| --------- | ------- | ----------- | -| `token` | `Token` | Token. | - -```swift -func balanceL1(token: Token) async -> BigUInt -``` - -#### Example - -```swift -try await wallet.BalanceL1(Token.ETH) -``` - -### `AllowanceL1` - -Returns the amount of approved tokens for a specific L1 bridge. - -#### Inputs - -| Parameter | Type | Description | -| --------------- | ----------------- | --------------- | -| `token` | `Token` | Token. | -| `bridgeAddress` | `EthereumAddress` | Bridge address. | - -```swift -func allowanceL1(token: Token, bridgeAddress: EthereumAddress) async -> BigUInt -``` - -### `L2TokenAddress` - -Returns the corresponding address on the L2 network for the token on the L1 network. - -#### Inputs - -| Parameter | Type | Description | -| --------- | ------- | ----------- | -| `token` | `Token` | L1 token. | - -```swift -try await L2TokenAddress(token: Token) async throws -> EthereumAddress -``` - -### `BaseCost` - -Returns base cost for L2 transaction. - -#### Inputs - -| Parameter | Type | Description | -| ------------------- | -------------------- | -------------------------------------------------------------------------------------- | -| `gasLimit` | `BigUInt` | The gasLimit for the the L2 contract call. | -| `gasPerPubdataByte` | `BigUInt` | The L2 gas price for each published L1 calldata byte. | -| `gasPrice` | `BigUInt` (optional) | The L1 gas price of the L1 transaction that will send the request for an execute call. | - -```swift -func baseCost(_ gasLimit: BigUInt, gasPerPubdataByte: BigUInt, gasPrice: BigUInt?) async throws -> [String: Any] -``` - -### `Deposit` - -Transfers the specified token from the associated account on the L1 network to the target account on the L2 network. The -token can be either ETH or any ERC20 token. For ERC20 tokens, enough approved tokens must be associated with the -specified L1 bridge (default one or the one defined in `BridgeAddress`). In this case, `ApproveERC20` can be enabled to -perform token approval. If there are already enough approved tokens for the L1 bridge, token approval will be skipped. -To check the amount of approved tokens for a specific bridge, use the [`AllowanceL1`](#allowancel1) method. - -#### Inputs - -| Parameter | Type | Description | -| --------- | -------------------- | ------------------ | -| `to` | `String` | To address. | -| `amount` | `BigUInt` | Amount to deposit. | -| `token` | `Token` (optional) | Token. | -| `nonce` | `BigUInt` (optional) | Nonce. | - -```swift -func deposit(_ to: String, amount: BigUInt, token: Token?, nonce: BigUInt?) async throws -> TransactionSendingResult -``` - -#### Example - -```swift -let amount = BigUInt(1_000_000_000_000) - -_ = try! await walletL1.deposit( - signer.address, - amount: amount, - token: Token.ETH -) -``` - -### `ClaimFailedDeposit` - -Withdraws funds from the initiated deposit, which failed when finalizing on L2. If the deposit L2 transaction has -failed, it sends an L1 transaction calling `ClaimFailedDeposit` method of the L1 bridge, which results in returning L1 -tokens back to the depositor, otherwise throws the error. - -```swift -func claimFailedDeposit(_ l1BridgeAddress: String, depositSender: String, l1Token: String, l2TxHash: Data, l2BlockNumber: BigUInt, l2MessageIndex: BigUInt, l2TxNumberInBlock: UInt, proof: [Data]) async throws -> TransactionSendingResult -``` - -### `RequestExecute` - -Request execution of L2 transaction from L1. - -#### Inputs - -| Parameter | Type | Description | -| ----------------- | -------------------- | -------------------- | -| `contractAddress` | `String` | Transaction options. | -| `l2Value` | `BigUInt` | L2 value. | -| `calldata` | `Token` (optional) | Calldata. | -| `gasLimit` | `BigUInt` (optional) | Gas limit. | -| `factoryDeps` | `BigUInt` (optional) | Factory deps. | -| `operatorTips` | `BigUInt` (optional) | Operator tips. | -| `gasPrice` | `BigUInt` (optional) | Gas price. | -| `refundRecipient` | `BigUInt` (optional) | Refund recipient. | - -```swift -func requestExecute(_ contractAddress: String, l2Value: BigUInt, calldata: Data, gasLimit: BigUInt, factoryDeps: [Data]?, operatorTips: BigUInt?, gasPrice: BigUInt?, refundRecipient: String) async throws -> TransactionSendingResult -``` - -## `WalletL2` - -### `Init` - -Creates an instance of WalletL2 associated with the account provided by the signer. - -```swift -WalletL2(zkSync, ethClient: ethClient, web3: web3, ethSigner: signer) -``` - -#### Example - -```swift -let credentials = Credentials() -let chainId = try! zkSync.web3.eth.getChainIdPromise().wait() -let zkSync: ZkSync = ZkSyncImpl(URL(string: "https://sepolia.era.zksync.dev")!) -let ethereum: web3 = try! Web3.new(URL(string: "https://rpc.ankr.com/eth_sepolia")!) -let signer = BaseSigner(credentials, chainId: chainId) -let wallet = WalletL2(zkSync, ethClient: ethClient, web3: web3, ethSigner: signer) -``` - -### `Address` - -Returns the address of the associated account. - -```swift -let address: EthereumAddress -``` - -#### Example - -```swift -wallet.address -``` - -### `Signer` - -Returns the signer of the associated account. - -```swift -let signer: ETHSigner -``` - -#### Example - -```swift -wallet.signer -``` - -### `Balance` - -Returns the balance of the specified token that can be either ETH or any ERC20 token. The block number can be `nil`, in -which case the balance is taken from the latest known block. - -#### Inputs - -| Parameter | Type | Description | -| ------------- | ------------- | ----------------- | -| `token` | `Token` | L2 token address. | -| `blockNumber` | `BlockNumber` | Block number. | - -```swift -func balance(token: Token, blockNumber: BlockNumber) async throws -> BigUInt -``` - -#### Example - -```swift -try await walletL2.balance(token: Token.ETH, blockNumber: .latest) -``` - -### `AllBalances` - -Returns all balances for confirmed tokens given by an associated account. - -#### Inputs - -| Parameter | Type | Description | -| --------- | -------- | ----------- | -| `address` | `String` | Address. | - -```swift -func allBalances(_ address: String) async throws -> Dictionary -``` - -#### Example - -```swift -try await walletL2.allBalances(address:
) -``` - -### `Withdraw` - -Initiates the withdrawal process which withdraws ETH or any ERC20 token from the associated account on L2 network to the -target account on L1 network. - -#### Inputs - -| Parameter | Type | Description | -| --------- | -------------------- | ------------------- | -| `to` | `String` | To address. | -| `amount` | `BigUInt` | Amount to withdraw. | -| `token` | `Token` (optional) | Token. | -| `nonce` | `BigUInt` (optional) | Nonce. | - -```swift -func withdraw(_ to: String, amount: BigUInt, token: Token?, nonce: BigUInt?) async throws -> TransactionSendingResult -``` - -#### Example - -```swift -let amount = BigUInt(1_000_000_000_000) - -_ = try! await walletL2.withdraw( - signer.address, - amount: amount, - token: Token.ETH -) -``` - -### `EstimateGasWithdraw` - -Estimates the amount of gas required for a withdrawal transaction. - -#### Inputs - -| Parameter | Type | Description | -| ------------- | ------------------------------- | ----------------------- | -| `transaction` | `CodableTransaction` (optional) | Withdrawal transaction. | - -```swift -func estimateGasWithdraw(_ transaction: CodableTransaction) async throws -> BigUInt -``` - -#### Example - -```swift -try await walletL2.estimateGasWithdraw(transaction) -``` - -### `Transfer` - -Moves the ETH or any ERC20 token from the associated account to the target account. - -#### Inputs - -| Parameter | Type | Description | -| --------- | -------------------- | ------------------- | -| `to` | `String` | To address. | -| `amount` | `BigUInt` | Amount to transfer. | -| `token` | `Token` (optional) | Token. | -| `nonce` | `BigUInt` (optional) | Nonce. | - -```swift -func transfer(_ to: String, amount: BigUInt, token: Token?, nonce: BigUInt?) async -> TransactionSendingResult -``` - -#### Example - -```swift -let amount = BigUInt(1_000_000_000_000) - -_ = try! await walletL2.transfer( - signer.address, - amount: amount, - token: Token.ETH -) -``` - -### `EstimateGasTransfer` - -Estimates the amount of gas required for a transfer transaction. - -#### Inputs - -| Parameter | Type | Description | -| ------------- | -------------------- | ------------ | -| `transaction` | `CodableTransaction` | Transaction. | - -```swift -func estimateGasTransfer(_ transaction: CodableTransaction) async throws -> BigUInt -``` - -#### Example - -```swift -try await walletL2.estimateGasTransfer(transaction) -``` - -### `CallContract` - -Executes a message call for EIP-712 transaction, which is directly executed in the VM of the node, but never mined into -the blockchain. - -#### Inputs - -| Parameter | Type | Description | -| ------------- | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `transaction` | `CodableTransaction` | Transaction. | -| `blockNumber` | `BigUInt` (optional) | Selects the block height at which the call runs. It can be `nil`, in which case the code is taken from the latest known block. Note that state from very old blocks might not be available. | - -```swift -func callContract(_ transaction: CodableTransaction, blockNumber: BigUInt?) async throws -> Data -``` - -#### Example - -```swift -try await walletL2.callContract(transaction, blockNumber: .latest) -``` - -### PopulateTransaction - -Designed for users who prefer a simplified approach by providing only the necessary data to create a valid EIP-712 -transaction. The only required fields are `Transaction.To` and either `Transaction.Data` or `Transaction.Value` (or -both, if the method is payable). Any other fields that are not set will be prepared by this method. - -#### Inputs - -| Parameter | Type | Description | -| ------------- | -------------------- | ------------ | -| `transaction` | `CodableTransaction` | Transaction. | - -```swift -func populateTransaction(_ transaction: inout CodableTransaction) async -``` - -#### Example - -```swift -await walletL2.populateTransaction(transaction) -``` - -### `SignTransaction` - -Returns a signed transaction that is ready to be broadcast to the network. The input transaction must be a valid -transaction with all fields having appropriate values. To obtain a valid transaction, you can use the -[`PopulateTransaction`](#populatetransaction) method. - -#### Inputs - -| Parameter | Type | Description | -| ------------- | -------------------- | ------------ | -| `transaction` | `CodableTransaction` | Transaction. | - -```swift -func signTransaction(_ transaction: inout CodableTransaction) -``` - -#### Example - -```swift -await walletL2.populateTransaction(transaction) -``` - -### `SendTransaction` - -Injects a transaction into the pending pool for execution. Any unset transaction fields are prepared using the -PopulateTransaction method. - -#### Inputs - -| Parameter | Type | Description | -| ------------- | -------------------- | ------------ | -| `transaction` | `CodableTransaction` | Transaction. | - -```swift -func sendTransaction(_ transaction: CodableTransaction) async throws -> TransactionSendingResult -``` - -#### Example - -```swift -try await walletL2.sendTransaction(transaction) -``` - -## `BaseDeployer` - -### `Init` - -Creates an instance of `BaseDeployer` based on provided `AdapterL2`. - -```swift -BaseDeployer(adapterL2: walletL2, signer: signer) -``` - -### `Deploy` - -Deploys smart contract using CREATE2 opcode. - -#### Inputs - -| Parameter | Type | Description | -| ---------- | ----------------- | ------------------------ | -| `bytecode` | `Data` | Smart contract bytecode. | -| `calldata` | `Data` (optional) | Calldata. | -| `nonce` | `Data` (optional) | Nonce. | - -```swift -func deploy(_ bytecode: Data, calldata: Data?, nonce: BigUInt?) async -> TransactionSendingResult -``` - -#### Example - -```swift -let url = Bundle.main.url(forResource: "Storage", withExtension: "zbin")! -let bytecodeData = try! Data(contentsOf: url) - -_ = try await deployer.deploy(bytecodeData, calldata: nil, nonce: nil) -``` - -### `DeployWithCreate` - -Deploys smart contract using CREATE opcode. - -#### Inputs - -| Parameter | Type | Description | -| ---------- | ----------------- | ------------------------ | -| `bytecode` | `Data` | Smart contract bytecode. | -| `calldata` | `Data` (optional) | Calldata. | -| `nonce` | `Data` (optional) | Nonce. | - -```swift -func deployWithCreate(_ bytecode: Data, calldata: Data?, nonce: BigUInt?) async -> TransactionSendingResult -``` - -#### Example - -```swift -let url = Bundle.main.url(forResource: "Storage", withExtension: "zbin")! -let bytecodeData = try! Data(contentsOf: url) - -_ = try await deployer.deployWithCreate(bytecodeData, calldata: nil, nonce: nil) -``` - -### `DeployAccount` - -Deploys smart account using CREATE2 opcode. - -#### Inputs - -| Parameter | Type | Description | -| ---------- | ----------------- | ----------------------- | -| `bytecode` | `Data` | Smart account bytecode. | -| `calldata` | `Data` (optional) | Calldata. | -| `nonce` | `Data` (optional) | Nonce. | - -```swift -func deployAccount(_ bytecode: Data, calldata: Data?, nonce: BigUInt?) async -> TransactionSendingResult -``` - -#### Example - -```swift -let url = Bundle.main.url(forResource: "Storage", withExtension: "zbin")! -let bytecodeData = try! Data(contentsOf: url) - -_ = try await deployer.deployAccount(bytecodeData, calldata: nil, nonce: nil) -``` - -### `DeployAccountWithCreate` - -Deploys smart account using CREATE opcode. - -#### Inputs - -| Parameter | Type | Description | -| ---------- | ----------------- | ----------------------- | -| `bytecode` | `Data` | Smart account bytecode. | -| `calldata` | `Data` (optional) | Calldata. | -| `nonce` | `Data` (optional) | Nonce. | - -```swift -func deployAccountWithCreate(_ bytecode: Data, calldata: Data?, nonce: BigUInt?) async -> TransactionSendingResult -``` - -#### Example - -```swift -let url = Bundle.main.url(forResource: "Storage", withExtension: "zbin")! -let bytecodeData = try! Data(contentsOf: url) - -_ = try await deployer.deployAccountWithCreate(bytecodeData, calldata: nil, nonce: nil) -``` - -## `Wallet` - -It contains the same functions as [`WalletL1`](#walletl1), [`WalletL2`](#walletl2), and [`BaseDeployer`](#basedeployer) -since it implements the Adapter interface, and the usage of those methods is the same. - -### `Init` - -Creates an instance of Wallet associated with the account provided by the signer. The `clientL2` and `clientL1` -parameters are optional; if not provided, only `SignTransaction`, `Address` and `Signer` methods can be used, as the -rest of the functionalities require communication with the network. - -```swift -WalletL2(zkSync, ethClient: ethClient, web3: web, ethSigner: signer) -``` - -#### Example - -```swift -let credentials = Credentials() -let chainId = try! zkSync.web3.eth.getChainIdPromise().wait() -let zkSync: ZkSync = ZkSyncImpl(URL(string: "https://sepolia.era.zksync.dev")!) -let ethereum: web3 = try! Web3.new(URL(string: "https://rpc.ankr.com/eth_sepolia")!) -let signer = BaseSigner(credentials, chainId: chainId) -let wallet = Wallet(zkSync, ethClient: ethClient, web3: web3, ethSigner: signer) -``` - -### `Nonce` - -Returns the account nonce of the associated account. The block number can be `nil`, in which case the nonce is taken -from the latest known block. - -#### Inputs - -| Parameter | Type | Description | -| ------------- | ------------------------ | ------------- | -| `blockNumber` | `BlockNumber` (optional) | Block number. | - -```swift -func nonce(at block: BlockNumber = .latest) async throws -> BigUInt -``` - -#### Example - -```swift -try await wallet.nonce(at: .exact(9000)) -``` - -### `PendingNonce` - -Returns the account nonce of the associated account in the pending state. This is the nonce that should be used for the -next transaction. - -```swift -func pendingNonce() async throws -> BigUInt -``` - -#### Example - -```swift -try await wallet.pendingNonce() -``` diff --git a/content/20.build/sdks/swift/getting-started.md b/content/20.build/sdks/swift/getting-started.md deleted file mode 100644 index 5cf3e9f0..00000000 --- a/content/20.build/sdks/swift/getting-started.md +++ /dev/null @@ -1,69 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Swift SDK Getting Started | zkSync Docs ---- - -# Getting Started - -This is a short introduction to `zksync2-swift` SDK, but covers many of the most common operations that developers -require and provides a starting point for those newer to zkSync Era. - -## Overview - -While most of the existing SDKs should work out of the box, deploying smart contracts or using unique zkSync features, -like account abstraction, requires providing additional fields to those that Ethereum transactions have by default. - -To begin, it is useful to have a basic understanding of the types of objects available and what they are responsible -for, at a high level: - -- `Client` provides connection to the zkSync Era blockchain, which allows querying the blockchain state, such as - account, block or transaction details, querying event logs or evaluating read-only code using call. Additionally, the - client facilitates writing to the blockchain by sending transactions. -- `Signer` wraps all operations that interact with an account. An account generally has a private key, which can be used - to sign a variety of types of payloads. -- `Wallet` is a wrapper around `Client` and `Signer` that provides easy usage of the most common features. - -## Getting zksync2-swift - -### Prerequisites - -- IOS: >=13.0 -- MacOS: >=11.0 - -## CocoaPods Integration - -To install zkSync via CocoaPods, add zkSync2 pod to the Podfile: - -``` - pod 'zkSync2-swift' -``` - -## Swift Package Manager Integration - -To install zkSync via Swift Package Manager, add zkSync2 to the Package Dependencies: - -``` - 'github.com/zksync-sdk/zksync2-swift' -``` - -## Connecting to ZkSync - -Once you have integrated zkSync2 dependencies, connect to zkSync using the endpoint of the operator node. - -```swift -let zkSync: ZkSync = ZkSyncImpl(URL(string: "https://sepolia.era.zksync.dev")!) -``` - -## Connecting to Ethereum - -Also connect to Ethereum using the endpoint of the eth_sepolia node. - -```swift -let ethereum: web3 = try! Web3.new(URL(string: "https://rpc.ankr.com/eth_sepolia")!) - -let credentials = Credentials() -let keystoreManager = KeystoreManager([credentials]) -ethereum.addKeystoreManager(keystoreManager) -``` diff --git a/content/20.build/sdks/swift/paymaster-utils.md b/content/20.build/sdks/swift/paymaster-utils.md deleted file mode 100644 index 472d65cb..00000000 --- a/content/20.build/sdks/swift/paymaster-utils.md +++ /dev/null @@ -1,50 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Swift SDK Paymaster Utilities | zkSync Docs ---- - -# Paymaster Utilities - -The -[paymaster utilities library](https://github.com/zksync-sdk/zksync2-swift/blob/main/Sources/ZkSync2/Utils/Paymaster.swift) -contains essential utilities for using paymasters on zkSync Era. - -## Contract interfaces - -### `IPaymasterFlow` - -Constant ABI definition for the -[Paymaster Flow Interface](https://github.com/matter-labs/era-contracts/blob/f06a58360a2b8e7129f64413998767ac169d1efd/zksync/contracts/interfaces/IPaymasterFlow.sol). - -## Functions - -### `Approval-based` Paymaster - -Returns encoded input for an `approval-based` paymaster. - -#### Inputs - -| Parameter | Type | Description | -| ------------------ | --------- | --------------------------------- | -| `paymasterAddress` | `Address` | The non-zero `paymaster` address. | -| `paymasterInput` | `Data` | The input data to the paymaster. | - -```swift -func encodeApprovalBased(_ tokenAddress: EthereumAddress, minimalAllowance: BigUInt, paymasterInput: Data) -> Data -``` - -### `General` Paymaster - -Returns encoded input for a `general` paymaster. - -#### Inputs - -| Parameter | Type | Description | -| ---------------- | ------ | -------------------------------- | -| `paymasterInput` | `Data` | The input data to the paymaster. | - -```swift -func encodeGeneral(_ paymasterInput: Data) -> Data -``` diff --git a/content/20.build/support/audit-bug-bounty.md b/content/20.build/support/audit-bug-bounty.md deleted file mode 100644 index 8eb9b557..00000000 --- a/content/20.build/support/audit-bug-bounty.md +++ /dev/null @@ -1,103 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Audits and Bug Bounty Program | zkSync Docs ---- - -# Audits and bug bounty program - -zkSync Era takes security seriously and as such, we have completed multiple audits in all critical parts of the -protocol. On top of that, there is an ongoing massive bug bounty program. - -## Audits - -We always ensure that all code deployed to production has been thoroughly tested before release. Our auditing and review -processes begin well before any code is deployed. We conduct internal audits, followed by independent external audits -from reputable auditors. If applicable, we also hold a public auditing contest and top it off with another independent -external audit. - -Here is the list of **completed audits**: - -- Layer 1 Smart Contracts, Internal Audit, from 2022-06-14 to 2022-08-17. -- [Layer 1 Smart Contracts](https://blog.openzeppelin.com/zksync-layer-1-audit/), OpenZeppelin, from 2022-09-05 to - 2022-09-30. -- [Layer 1 Diff Audit (Upgrade Audit)](https://blog.openzeppelin.com/zksync-layer-1-diff-audit/), OpenZeppelin, from - 2022-11-21 to 2022-11-25. -- [Layer 1 Diff Audit (Upgrade Audit)](https://blog.openzeppelin.com/zksync-l1-diff-audit-february-2023/), OpenZeppelin, - from 2023-02-06 to 2023-02-17. -- [Layer 1 Public Contest](https://code4rena.com/reports/2022-10-zksync/), Code4rena, from 2022-10-28 to 2022-11-09. -- [Layer 1 Smart Contracts](https://github.com/Secure3Audit/Secure3Academy/blob/main/audit_reports/zkSync/zkSync_L1_final_Secure3_Audit_Report.pdf), - Secure3, from 2022-10-22 to 2022-11-06. -- [WETH Bridge Audit](https://blog.openzeppelin.com/zksync-weth-bridge-audit), OpenZeppelin, from 2023-03-27 to - 2023-03-31. -- [Bridge and .transfer & .send](https://blog.openzeppelin.com/zksync-bridge-and-.transfer-.send-diff-audit), - OpenZeppelin, from 2023-04-24 to 2023-05-01. -- [GnosisSafeZk Assessment](https://blog.openzeppelin.com/zksync-gnosissafezk-assessment-1), OpenZeppelin, from - 2023-05-22 to 2023-05-26. -- [Upgrade System](https://blog.openzeppelin.com/zksync-upgrade-system-audit), OpenZeppelin, from 2023-06-26 to - 2023-06-30. -- [Layer 1 Messenger Upgrade](https://blog.openzeppelin.com/zksync-l1messenger-upgrade-audit), OpenZeppelin, from - 2023-08-30 to 2023-09-14. -- [Diff and Governance Audit](https://blog.openzeppelin.com/december-diff-and-governance-audit), OpenZeppelin, from - 2023-12-04 to 2023-12-22. -- Layer 2, Internal Audit, from 2022-08-17 to 2022-10-24. -- [Layer 2 Bootloader](https://blog.openzeppelin.com/zksync-bootloader-audit-report/), OpenZeppelin, from 2022-11-28 to - 2022-12-23. -- [Layer 2 Fee Model and Token Bridge](https://blog.openzeppelin.com/zksync-fee-model-and-token-bridge-audit/), - OpenZeppelin, from 2023-01-23 to 2023-02-17. -- [Layer 2 System Contracts Public Contest](https://code4rena.com/contests/2023-03-zksync-era-system-contracts-contest), - Code4rena, from 2023-03-10 to 2023-03-19. -- [Layer 2 Block Refactor](https://blog.openzeppelin.com/zksync-l2-block-refactor-audit), OpenZeppelin, from 2023-07-25 - to 2023-07-31. -- [Keccak256 Upgrade](https://blog.openzeppelin.com/zksync-keccak256-upgrade-audit), OpenZeppelin, from 2023-10-23 to - 2023-10-27. -- [Layer 1 & 2 Diff Audit](https://blog.openzeppelin.com/november-diff-audit), OpenZeppelin, from 2023-11-27 to - 2023-12-05. -- [Short-Term Fee Model Changes](https://blog.openzeppelin.com/short-term-fee-model-changes-audit), OpenZeppelin, from - 2023-12-06 to 2023-12-13. -- ZK Proof System, Internal Audit, from 2022-10-24 to 2022-11-18. -- [ZK Proof System](https://github.com/HalbornSecurity/PublicReports/blob/master/ZK%20Audits/MatterLabs_zkSync_Era_Circuits_Zero_Knowledge_Security_Audit_Report_Halborn_Final..pdf), - Halborn, from 2023-01-09 to 2023-03-08. -- [Smart Contract Security Assessment](https://github.com/HalbornSecurity/PublicReports/blob/master/Solidity%20Smart%20Contract%20Audits/MatterLabs_Verifier_Smart_Contract_Security_Assessment_Report_Halborn_Final.pdf), - Halborn, from July 12th, 2023 - July 20th, 2023. -- [SNARK Wrapper](https://github.com/spearbit/portfolio/blob/master/pdfs/Matter-labs-snark-wrapper-Spearbit-Security-Review.pdf), - Spearbit, November 2023 -- [EIP-4844 Support](https://blog.openzeppelin.com/eip-4844-support-audit), OpenZeppelin, February 2024 - -## Bug Bounty Program - -zkSync Era has a very detailed **[Bug bounty Program on Immunefi](https://immunefi.com/bounty/zksyncera/)**. In the -listing, you can find all the information related to assets in scope, reporting, and the payout process. - -### Scope - -The bug bounty program for zkSync Era aims to identify and resolve security vulnerabilities in our system before they -can be exploited by malicious actors. The program is open to all individuals and teams who are interested in -participating and are willing to comply with the program's rules and guidelines. The scope of the program covers all -aspects of our blockchain products, including smart contracts, protocols, portals, and any other components that are -part of our ecosystem. - -### Requirements - -1. Eligibility: The bug bounty program is open to anyone who is interested in participating and who complies with the - program's rules and guidelines. -2. Responsible Disclosure: All participants must agree to follow the responsible disclosure policy and report any - security vulnerabilities they discover to our security team in a timely and responsible manner. -3. Rewards: The bug bounty program offers rewards to participants who discover and report security vulnerabilities. The - rewards are determined based on the severity of the vulnerability and are paid in USDC. -4. Reporting Guidelines: Participants must follow the reporting guidelines specified by the program. -5. No Public Disclosure: Participants must not publicly disclose any vulnerabilities they discover until after they have - been resolved by our security team. -6. No Exploitation: Attacks that the reporter has already exploited themselves, leading to damage are not eligible for a - reward. -7. Legal Compliance: Participants must comply with all applicable laws and regulations, including data privacy and - security laws. -8. Program Changes: We reserve the right to modify or terminate the program at any time and without prior notice. We - also reserve the right to disqualify any participant who violates the program's rules and guidelines. - -### Unscoped Bug - -If you think you have found a critical or major bug that is not covered by our existing bug bounty, please report it to -us [via the Immunefi program](https://immunefi.com/bounty/zksyncera/) regardless. We will seriously consider the impact -of any issues and may award a bounty even for out of scope assets or impacts. diff --git a/content/20.build/support/community-channels.md b/content/20.build/support/community-channels.md deleted file mode 100644 index d9c7ccea..00000000 --- a/content/20.build/support/community-channels.md +++ /dev/null @@ -1,66 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Community Channels | zkSync Docs ---- - -# Community Channels - -Engage with our vibrant community and stay updated on the latest news, insights, and discussions through our diverse -channels. Here's a quick overview: - -#### **1. Developer Discussions** - -A dedicated space in GitHub for developers to discuss, collaborate, and brainstorm on technical topics. - -[Engage in GitHub Discussions](https://github.com/zkSync-Community-Hub/zksync-developers/discussions) - -
- -#### **2. Discord** - -Join real-time conversations, ask questions, and connect with both the team and fellow community members. - -[Join our Discord server](https://join.zksync.dev/) - -
- -#### **3. Twitter/X** - -Follow us for quick updates, announcements, and trends related to our platform, updates for developers, and the broader -industry. - -[Follow us on Twitter](https://twitter.com/zksync) - -[Follow our developer-focused Twitter ](https://twitter.com/zkSyncDevs) - -
- -#### **4. Blog** - -Delve deep into comprehensive articles, tutorials, and insights penned by our team. - -[Read our Blog](https://zksync.mirror.xyz/) - -
- -#### **5. GitHub Issues** - -The most effective way to seek technical support is by raising an issue on GitHub. Ensure you provide a comprehensive -description, relevant details, and steps to reproduce for prompt assistance. - -- **zkSync Era Issues**: Address all queries and concerns related to zkSync Era here. - [Report zkSync Era Issue](https://github.com/matter-labs/zksync-era/issues) -- **era-test-node Issues**: If you're facing challenges with the era-test-node, this is the place to raise them. - [Report era-test-node Issue](https://github.com/matter-labs/era-test-node/issues) -- **SDKs Issues**: For any issues related to our Software Development Kits, kindly head over to this section. - [Report SDKs Issue](https://github.com/zksync-sdk) - -
- -#### **6. Telegram** - -Get instant updates and participate in mobile-friendly discussions on our official Telegram channel. - -[Join us on Telegram](https://t.me/zksync) diff --git a/content/20.build/support/contribution-track.md b/content/20.build/support/contribution-track.md deleted file mode 100644 index 10ee8cc8..00000000 --- a/content/20.build/support/contribution-track.md +++ /dev/null @@ -1,117 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Community Channels | zkSync Docs ---- - -# Contribution Track - -### Introduction - -Welcome to the zkSync Contributors Track! The purpose of this track is to accelerate your journey into the thriving -zkSync development landscape. As a fully open-source project, we believe in community-driven development, and that means -anyone from anywhere can contribute to shaping the future of zkSync. - -This track aims to guide you in discovering various aspects of our project, inspire you to contribute in the ways that -interest you most, and provide a pathway to connect with the zkSync community. - -### Open-Source Repositories - -Here's a list of our key open-source repositories that you can contribute to: - -#### zkSync Era - -- [**zkSync Era**](https://github.com/matter-labs/zksync-era): Node implementation for zkSync Era. - -#### Smart Contracts - -- [**era-contracts**](https://github.com/matter-labs/era-contracts): Submodule containing the smart contracts for zkSync - Era. - -#### Circuit Implementation - -- [**era-sync_vm**](https://github.com/matter-labs/era-sync_vm): Houses the circuit implementation of zkVM specifically - for zkSync Era. - -#### Testing and Debugging - -- [**era-test-node**](https://github.com/matter-labs/era-test-node): An in-memory node designed for integration testing - and debugging. - -#### Development Tools - -- [**zksync-cli**](https://github.com/matter-labs/zksync-cli): CLI tool that aims to simplify the development process on - zkSync. -- [**hardhat-zksync**](https://github.com/matter-labs/hardhat-zksync): Hardhat plugins tailored for the zkSync Network. - -#### Documentation - -- [**zksync-web-era-docs**](https://github.com/matter-labs/zksync-web-era-docs): The go-to source for official zkSync - documentation. - -#### SDK and Explorers - -- [**block-explorer**](https://github.com/matter-labs/block-explorer): The official block explorer for navigating the - zkSync network. -- [**zksync-sdk**](https://github.com/zksync-sdk): Software Development Kit for ease of integration with the zkSync - network. - -Feel free to explore these repositories, and don't hesitate to contribute! - -### Why the Contributors Track? - -**Purpose** - -- Facilitate easy entry for external contributors into zkSync's development ecosystem. -- Offer a structured approach to involvement, reducing the initial overwhelm of diving into a new project. -- Build a strong, diverse, and global community of developers who are excited about zkSync. - -**Who is it for?** - -- Developers interested in blockchain and layer 2 solutions. -- Open-source enthusiasts looking to contribute to a growing project. -- Those interested in contract development, dApp development, zkSync Era, and more. - -### The Track - -#### Getting Started - -**1. Introduce Yourself on** [**zkSync Discord**](https://discord.com/invite/QKSsp7tC2x) - -- Join our Discord channel and say 'hi' in the `#introductions` thread. Share what interests you and what you're hoping - to learn or contribute. - -**2. Follow** [**zkSync Developers**](https://twitter.com/zkSyncDevs) **on X (formerly Twitter)** - -- Keep up to date with the latest news, updates, and releases by following us on X. - -**3.Dive into our** [**official documentation**](../../) - -- Immerse yourself in our comprehensive official documentation to acquire essential knowledge on zkSync. If you discover - a typo, syntax error, or see room for improvement, submit a Pull Request to contribute to its enhancement. - -#### Dive Into Development - -**4. Deploy Your First Contract Using** [**zkSync-CLI**](https://github.com/matter-labs/zksync-cli) - -- Familiarize yourself with the zkSync-CLI tool and deploy your first contract on the zkSync Era testnet. Checkout the - zkSync-cli documentation [here](../../build/tooling/zksync-cli/getting-started.md). - -**5. Tackle a 'Good First Issue'** - -- Start contributing immediately by taking on a "Good First Issue" from any of our GitHub repositories. This is a great - way to get hands-on experience and a feel for the project. - -#### Community Engagement - -**6. Participate in** -[**zkSync Developer Discussions**](https://github.com/zkSync-Community-Hub/zkync-developers/discussions) - -- Join the discourse on GitHub discussions or other community forums to provide answers, ask questions, or share - insights. - -**7. Submit a** [**Community Tutorial**](https://github.com/zkSync-Community-Hub/tutorials) **or Guide** - -- Help others by sharing your knowledge. Write a tutorial or guide, then submit it to our community contributions - repository or community forums diff --git a/content/20.build/support/faq.md b/content/20.build/support/faq.md deleted file mode 100644 index 219f55d0..00000000 --- a/content/20.build/support/faq.md +++ /dev/null @@ -1,281 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: FAQ | zkSync Docs ---- - -# FAQ - -Here you will find some of the most common questions we receive about zkSync Era. - -## What is zkSync Era? - -zkSync Era is a Zero Knowledge (ZK) rollup that supports generalized EVM compatibility for the Ethereum blockchain. The -primary benefit of zkSync Era is that developers who have created EVM dApps can port to zkSync Era effortlessly and -realize significantly lower gas fees and more transactions per second while inheriting Ethereum's security and -decentralization. - -## Why zkSync Era? - -zkSync Era is a gigantic leap forward in Layer 2 technologies. It is a long-awaited improvement that offers many never -before enjoyed benefits for Ethereum developers. - -- **EVM Compatible** - zkSync is an EVM-compatible zero knowledge rollup that supports generalized EVM smart contracts. - This means if you already have EVM smart contracts, it’s super easy to port your dApp to zkSync Era. -- **Ethos Compatible** - we are very aligned with the ethos of decentralization and open source. All of our code will - strive to be fully open-source and zkSync will be executing a roadmap that will fully decentralize the sequencer and - proof generation, and we will be executing a roadmap of organizational subtractive management - that is, we will be - decentralizing our organization as well. -- **Certainty** - Unlike previous methods attempting to scale Ethereum which have in some cases offered weaker security - guarantees than for L1 (e.g. sidechains, plasma, and optimistic) zkSync Era uses zero-knowledge proofs which offer - _certainty_ of security. -- **Future Proof** - Ecosystem projects that adopt zkSync Era now will enjoy all future improvements without the need to - change their code, in particular coming from: - - The prover technology: hardware acceleration and - [new proof systems](https://zksync.mirror.xyz/HJ2Pj45EJkRdt5Pau-ZXwkV2ctPx8qFL19STM5jdYhc). - - The compiler: integration of LLVM-enabled modern programming languages. - [Learn more about our compiler toolchain](../../zk-stack/components/compiler/toolchain/overview.md). - - Other innovations like - [Hyperchains, Hyperbridges and ZK Stack](../../zk-stack/concepts/hyperchains-hyperscaling.md). - -## What is the zkEVM? - -zkEVM is the name of the architecture that enables zero-knowledge proof generation for the execution trace of smart -contracts originally written for EVM. - -Its architecture is based on the following components: - -- zkVM, a Turing-complete RISC-like virtual machine optimized for proving in a ZKP circuit. It has several different - implementations: - - Executor: fast native execution on CPU. - - Witness generator: native executor to generate ZKP witness. - - Prover: the actual ZKP circuit implementation. -- LLVM-based compiler with: - - Solidity frontend (more precisely: Yul frontend). - - Vyper frontend. - - zkVM backend. -- Special-purpose circuits (heavily relying on PLONK’s custom gates and lookup tables) as “precompiles” for - computationally intensive operations, such as: - - Non-algebraic hashes (Keccak, SHA256, Blake2). - - Storage access (Merkle paths). - - Elliptic curve pairing. -- Recursive aggregation circuit (combines the proofs from the above-mentioned parts). - -### zkEVM vs EVM - -Apart from the opcodes and gas metering disparity, zkVM strictly inherits the EVM programming model and its invariants, -including the ABI calling conventions. One important thing to emphasize is that the zkVM supports rollbacks and provably -revertible transactions. It guarantees mutual protection: users can not stall the network with bombardment by revertible -transactions, and the escape hatch (priority queue) protects the user’s ability to include any transactions into the -blocks. - -As a result, developers can fully rely on the censorship-resistance provided by L1 without having to introduce any -changes related to the escape-hatch mechanism. This means that assets in a zkRollup account on zkSync will have exactly -the same security guarantees as on L1. - -### EVM Improvements - -While maintaining maximum compatibility, the zkSync Era's zkEVM has significant improvements over the EVM that increase -adoption and benefit our ecosystem projects. - -- **Our compiler is based on LLVM**. LLVM-based compilers (Low-Level Virtual Machine) have become the default compiler - for Mac OS X, iOS, FreeBSD, and Android systems and are among the most widely used because they: - - Enable us to improve the efficiency over the original EVM bytecode because with LLVM we can take advantage of the - many optimizations and tools available in this mature ecosystem. - - Pave the way for us to add support for integrating codebases written in other programming languages with LLVM - frontend. By doing so, developers can build dApps and use blockchains in ways that are currently not possible. -- **Account Abstraction is implemented natively in our zkEVM**. This is a long-anticipated feature in the Ethereum dev - community which improves developer adoption and user experience in a number of ways: - - Native support for smart contracts wallets (like Clave), which is critical for onboarding mainstream users. - - Much better UX for multisigs. - - Transaction fees can be paid in any token using - [paymasters](../../build/developer-reference/account-abstraction.md#paymasters). - - Protocols can now subsidize gas for users from their smart contracts or even enable gasless transactions. - - Transaction batches (multicall) can be confirmed in one click (big UX problem on Ethereum today). - - Learn more about - [account abstraction support in zkSync Era](../../build/developer-reference/account-abstraction.md). - -### EVM Compatibility - -There is a lot of confusion amongst the community with regard to the impacts of being EVM Compatible versus EVM -Equivalent. First, let’s define what is meant by the two. - -- **EVM Equivalent** means that a given protocol supports every opcode of Ethereum’s EVM down to the bytecode. Thus, any - EVM smart contract works with 100% assurance out of the box. -- **EVM Compatible** means that a percentage of the opcodes of Ethereum’s EVM are supported; thus, a percentage of smart - contracts work out of the box. - -zkSync is optimized to be EVM _compatible_ not EVM _equivalent_ for three primary reasons: - -1. Creating a generalized circuit for EVM equivalence down to the bytecode would be prohibitively expensive and - time-consuming. -2. Building on what we learned with zkSync Lite, we were able to design a system optimized for performance and - provability in ZK. -3. The opcodes we’ve chosen NOT to support are deprecated by Ethereum itself, or rarely used. In the case a project - needs them, modifications to work with zkSync are minimal and do not generate a need for a new security audit. - -Almost every smart contract written for EVM will be supported by zkSync Era and will hold all key security invariants so -that no additional security re-auditing will be required in most cases. - -::: info Differences with Ethereum You can find more information about the -[differences between Ethereum and zkSync Era in this section of the docs](../../build/developer-reference/differences-with-ethereum.md). -::: - -There are a few other distinctions, for example, gas metering will be different (as is the case for other L2s as well). -Some EVM’s cryptographic precompiles (notably pairings and RSA) won’t be available in the very first release but will be -implemented soon after the launch, with pairing being a priority to allow both Hyperchains and protocols like Aztec/Dark -Forest to be deployed without modifications too. - -## Security expectations - -zkSync Era’s data availability layer is Ethereum. All ecosystem projects that build on zkSync Era will inherit the full -security benefits of Ethereum. - -This is obviously a critically important topic for us, and the system has gone through several security audits and -maintains a very detailed bug bounty program. You can read more about -[zkSync Era security in this section of the docs](./audit-bug-bounty.md). - -### Triggering Security audits - -While there are a few, rarely used opcodes that we do not support, we have not found any instances with our ecosystem -projects where a breaking change was anything other than a simple refactoring of a few lines of code. None of our -ecosystem projects who have ported to zkSync have reported that any change has caused a need for a security audit. - -## What is Account Abstraction? - -At a very high level, Account Abstraction allows us to make authorizations _programmable_, enabling a greater diversity -of wallet and protocol design with use cases including: - -- The implementation of smart contract wallets that improve the user experience of private key storage and recovery (eg. - [social recovery](https://vitalik.eth.limo/general/2021/01/11/recovery.html), multisig). -- The ability to natively pay gas fees in tokens other than ETH. -- The ability for accounts to change public and private keys. -- The addition of non-cryptographic modifications, where users can require transactions to have expiry times, confirm - slightly out-of-order, and more. -- Diversity in signature verification systems from the current ECDSA, including post-quantum safe signature algorithms - (eg. Lamport, Winternitz). - -In other words, Account Abstraction brings about major improvements to the overall user experience, and expands the -application design space for developers. Learn more in -[this blog post](https://www.argent.xyz/blog/wtf-is-account-abstraction/) by Argent. - -In zkSync Era Account Abstraction is natively implemented, meaning accounts can initiate transactions, like an EOA, but -can also have arbitrary logic implemented in them, like a smart contract. - -If you want to better understand what Account Abstraction on zkSync looks like, you can read -[this section of the docs](../../build/developer-reference/account-abstraction.md), or try out our tutorial -[here](../../build/tutorials/smart-contract-development/account-abstraction/custom-aa-tutorial.md). - -## zkSync Era vs Optimistic Rollups - -Optimistic rollups utilize an optimistic approach to secure their networks. At the time of their development, they -represented an important incremental improvement over other available options. However, a widely held opinion -([including Vitalik Buterin's](https://coinculture.com/au/people/vitalik-buterin-zk-rollups-to-outperform-optimistic-rollups/)) -is that optimistic methods represent yet another temporary solution and in the long run the only permanent and truly -scalable solution will be blockchains based on Zero-Knowledge proofs. - -Optimistic rollups suffer from the following key downsides: - -- **Optimistic rollups are secured via game theory.** This method assumes all transactions are valid and then utilizes - an after-the-fact game theory mechanism to pay participants to discover fraudulent or otherwise invalid (e.g. because - of bugs) transactions. Game theory is never perfect and as with the game theory that broke with stablecoins and other - systems, we just don’t think it can be relied on in the long term and at true scale to offer the security the - ecosystem needs. zkSync Era, on the other hand, relies on math, not game theory, to provide the absolute certainty of - proof that every single transaction is valid and not fraudulent. - -- **Optimistic methods take 7 days to settle**. Settlement time is becoming an increasingly important feature for - ecosystem projects. As ecosystem projects’ needs mature, the need for as close to instant settlement will rise. With - optimistic methods, this settlement problem will not go away. It's always going to be a 7-day settlement time because - optimistic methods need 7 days for their after-the-fact game theory to conclude its challenge window. The only way - around this is to bring in third parties that provide some liquidity - but then again this is a potential security - risk in trusting the liquidity providers. - - zkSync Era provides settlement in hours but with optimizations in the system we'll reduce the settlement time without - the need of projects to update their code. - -- **Optimistic rollups have no method of scaling beyond where they are now.** When optimistic methods first came out, - they became popular because they scaled Ethereum (e.g. they enabled the processing of 10x Ethereum transactions - _without degradation of security and decentralization_). The problem is that while they can scale Ethereum by 10x now, - they have no mechanism to go beyond 10x without degrading security and decentralization. - - In contrast, zkSync Era is based on zero-knowledge proofs which have important characteristics that optimistic methods - do not - they can hyperscale. - -::: tip Hyperscalability Read more about -[Hyperscalability and ZK Stack here](../../zk-stack/concepts/hyperchains-hyperscaling.md). ::: - -## Which Wallets are supported? - -At the moment, we support any Ethereum-based wallet like Metamask, BitKeep, TrustWallet or Zerion. You can add zkSync -network to your Metamask manually by following the instructions in the -[interact with zkSync Era](../../build/quick-start/add-zksync-to-metamask.md) page. - -## Token Listing - -We source our token information from [Coingecko](https://www.coingecko.com/en/categories/zksync-ecosystem). - -- **Adding a Token**: all tokens are identified automatically. If you wish to include a logo, pricing, or other details - for your token, ensure it is listed on Coingecko. Once listed, these details will automatically appear on Block - Explorer and Bridge. It may take up to 24 hours for updates to be reflected. -- **Top Tokens List**: Tokens are arranged in descending order based on liquidity. We do not control the order of the - tokens. - -## How do I Request Funds for Testnet? - -To access Sepolia testnet funds, [you can use one of our third party faucets](../tooling/network-faucets.md). - -## How long does it take to complete a deposit transaction? - -The transactions on zkSync Era should not take more than 5 minutes. - -## Where can I see the transactions I submitted? - -Our [Block Explorer](https://explorer.zksync.io) will show everything you may need about a transaction. - -## Can someone claim the address I have for my contract in other EVM networks in zkSync Era? - -The contract address derivation formula is different from the regular EVM approach. Even if a contract is deployed from -the same account address with the same nonce, the zkSync Era contract address will not be the same as it is in another -EVM network. This means, for example, that no one will be able to claim an existing Ethereum address of your protocol to -try to trick users into interacting with a malicious version of it. - -## What is the storage limit for smart contracts on zkSync Era? - -The current limit is 3600000000 gas. - -## What is Block Gas Limit on zkSync Era? - -The current value is currently set at roughly 2^32 gas.
**Note**: This value is temporal and will be updated soon. - -## Can I withdraw my funds back to Ethereum? - -Yes, the bridge is two-way. You can withdraw your funds back to Ethereum. The withdrawal transaction -[will take ~24 hours, depending on the usage of the zkSync Era network](./withdrawal-delay.md). - -## What is a testnet regenesis? - -Sometimes, the team working on zkSync Era will initiate a regenesis on testnet - a restart of the blockchain which will -introduce upgrades and return the state to the initial point. - -## Why do my contracts not compile in Windows? - -If you're using Windows, make sure to use WSL 2, since WSL 1 is known to cause trouble. - -Additionally, if you use WSL 2, make sure that your project is located in the Linux filesystem, since accessing NTFS -partitions from WSL is very slow. - -## Proof sampling on testnet - -zkSync Era testnet is experiencing immense demand, but its permissionless nature leaves our developer infrastructure -vulnerable to potential DoS attack vectors. Generating ZK proofs inherently incurs costs, and a determined attacker -could exploit this by submitting a massive number of transactions, resulting in significant expenses for us. As we -currently lack a more effective method for rationing resources, we have opted to prove a random subset of batches on the -testnet – the subset fluctuates with demand but maintains a high minimal threshold. This approach ensures the detection -of errors probabilistically while conserving valuable GPU resources. - -This resource optimization not only supports a more efficient allocation of resources but also promotes a more -environmentally-friendly process compared to proving every batch on the testnet. - -Moving forward, we aim to develop better mechanisms to prevent Sybil attacks on our infrastructure, with the ultimate -goal of enabling the proof of all batches on the testnet. diff --git a/content/20.build/support/withdrawal-delay.md b/content/20.build/support/withdrawal-delay.md deleted file mode 100644 index 710d73ce..00000000 --- a/content/20.build/support/withdrawal-delay.md +++ /dev/null @@ -1,93 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Withdrawal Delay | zkSync Docs ---- - -# Withdrawal delay - -In order to prevent a quick drain of the protocol in the case a critical bug is discovered and exploited, we are -introducing a block execution delay. Each L2 block committed to L1 will have a time lock before it is executed and -finalized. This means that there is enough time to verify the effects of the transactions included in a block before the -block becomes final. The zkSync team will be monitoring each block and investigating any anomaly (e.g. rapid outflow, -unusually large withdrawals, etc). - -To introduce this time lock, no changes were made to the audited smart contracts. Instead, we have used an existing -Validator role that we control and that we further restricted by pointing it to an intermediate smart contract with a -time lock. The time lock is initially configured for a **24-hour** delay, which will gradually decrease as the system -matures. Changing the delay requires multiple signatures collected from several cold wallets owned by zkSync leadership. - -This design has the following advantages: - -- Even if an attacker finds a critical bug in ZK circuits and also successfully compromises the servers running our - sequencer, there is plenty of time to detect an exploit, investigate, and freeze the protocol via governance. -- No changes were introduced to the zkSync Era contracts, so even if the intermediate contract is compromised we revert - back to the original state. -- Delayed execution affects not only the standard zkSync ETH and ERC20 bridges but also any custom bridge built by a - different team. -- Implementing the logic in an external governor-controlled contract makes it easy to remove this limitation later. - -## Why can't I find my withdrawal on Etherscan? - -There are several reasons why your withdrawal may be successful but you cannot see your tokens, or the transaction, on -Etherscan. For example: - -1. **Delay in block confirmation**: as mentioned in the [withdrawal delay](#withdrawal-delay) section above, successful - withdrawals may be subject to an ongoing confirmation process. Consequently, you won't be able to see your - transaction on Etherscan until the confirmation process completes. - -2. **Transaction reverted**: a withdrawal may fail to appear on Etherscan if the transaction is reverted due to a - conflict or issue with the smart contract that executed the transaction. In such cases, the transaction is canceled - and it won't be included on Etherscan. - -3. **Wrong address**: if a user mistakenly sends tokens to an incorrect address, the transaction will not be visible on - Etherscan, and the tokens will not arrive in the intended recipient's wallet. - -### Transactions in Etherscan - -The **Transactions** section in Etherscan displays transactions between two Ethereum addresses. Each transaction has -details such as the transaction hash, the block number, the timestamp, the sender and receiver addresses, the amount of -Ether or tokens involved, and the transaction fee. These transactions are confirmed by the network and are typically -sent from one external address to another. - -On the other hand, **Internal Transactions** are initiated by a smart contract or other internal code execution within -the Ethereum network. Although these transactions can be prompted by user activity, they are not sent directly from one -address to another but are instead part of the internal workings of a smart contract. Internal transactions may involve -the transfer of ETH or ERC20 tokens between different addresses within the contract. - -::: tip Withdrawals from the zkSync Era network are typically internal transactions managed by the -[zkSync Era Diamond Proxy](https://etherscan.io/address/0x32400084c286cf3e17e7b677ea9583e60a000324) contract. These -transactions are recorded in the **Internal Transactions** section in Etherscan due to their internal nature. ::: - -In summary, the **Transactions** section in Etherscan displays transactions between external addresses, while the -**Internal Transactions** section displays transactions that occur within smart contracts. - -### How to check your internal transactions - -1. Launch your web browser and visit [Etherscan.io](https://etherscan.io/). - -2. In the search bar at the top of the page, enter the Ethereum wallet address you used to withdraw funds. This should - be the address you withdrew funds from, not the destination address. - -![Etherscan search bar](../../assets/images/ether-search.png 'Search for transactions') - -3. Click **Enter**. - -4. Scroll down to the **Internal Transactions** section. - -![Internal transaction](../../assets/images/internal-trx.png 'Internal transactions in Etherscan') - -5. Look for the internal transaction that corresponds to your withdrawal. You should see a transaction that shows the - withdrawal amount coming from the bridge. - -::: tip Withdrawal transactions from zkSync Era appear as transactions from **zkSync Era: Diamond Proxy** to your wallet -address. ::: - -6. Once you've located the transaction, click on the **Parent Tx Hash** to view more details about the transaction, - including the block number, gas used, and sender and recipient addresses. - -![Parent transaction hash](../../assets/images/parent-hash.png 'Parent transaction hash in Etherscan') - -If for any reason you're still unable to see your withdrawal transaction after following these steps, please contact us -on Discord and we will look into it. diff --git a/content/20.build/test-and-debug/continuous-integration.md b/content/20.build/test-and-debug/continuous-integration.md deleted file mode 100644 index e26d4140..00000000 --- a/content/20.build/test-and-debug/continuous-integration.md +++ /dev/null @@ -1,163 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Continuous Integration | zkSync Docs ---- - -# Continuous Integration - -A GitHub Action is available for integrating `era-test-node` into your CI/CD environments. This action offers high -configurability and streamlines the process of testing your applications in an automated way. - -You can find the GitHub Action in the marketplace [here](https://github.com/marketplace/actions/era-test-node-action). - -:::info In CI tests, use `127.0.0.1` as the URL in hardhat.config.ts or for the provider to avoid '**Cannot connect to -network**' errors. ::: - -### Configuration Options - -
OptionDescriptionRequiredDefaultOptions
modeOperation mode.Norunrun, fork
networkNetwork selection.No--
forkAtHeightBlock height to fork at.No--
portListening port.No8011-
showCallsCall debug visibility.Nononenone, user, system, all
showStorageLogsStorage log visibility.Nononenone, read, write, all
showVmDetailsVM details visibility.Nononenone, all
showGasDetailsGas details visibility.Nononenone, all
resolveHashesEnable hash resolution.Nofalse-
logLog filter level.Noinfodebug, info, warn, error
logFilePathPath for the log file.Noera_test_node.log-
targetTarget architecture.Nox86_64-unknown-linux-gnux86_64-unknown-linux-gnu, x86_64-apple-darwin, aarch64-apple-darwin
versionVersion of era_test_node.Nolatest-
- -### Usage Examples - -Below provides usage examples for quick and more advanced setups. - -#### Quickstart - -```yaml -name: Run Era Test Node Action - -on: - push: - branches: [main] - -jobs: - build: - runs-on: ubuntu-latest - - steps: - - name: Checkout code - uses: actions/checkout@v3 - - - name: Run Era Test Node - uses: dutterbutter/era-test-node-action@latest -``` - -#### Advanced - -With configuration options: - -```yaml -name: Run Era Test Node Action - -on: - push: - branches: [main] - -jobs: - build: - runs-on: ubuntu-latest - - steps: - - name: Checkout code - uses: actions/checkout@v3 - - - name: Run Era Test Node - uses: dutterbutter/era-test-node-action@latest - with: - mode: 'run' - showCalls: 'user' - showStorageLogs: 'read' - showVmDetails: 'all' - showGasDetails: 'all' - resolveHashes: 'true' - log: 'info' - logFilePath: 'era_test_node.log' - target: 'x86_64-unknown-linux-gnu' -``` - -With upload log file to artifacts: - -```yaml -name: Run Era Test Node Action - -on: - pull_request: - branches: [main] - workflow_dispatch: -jobs: - test: - name: unit-tests - strategy: - matrix: - platform: [ubuntu-latest] - runs-on: ${{ matrix.platform }} - - steps: - - name: Checkout Code - uses: actions/checkout@v3 - - - name: Run Era Test Node - uses: dutterbutter/era-test-node-action@latest - with: - mode: 'fork' - network: 'mainnet' - forkAtHeight: '1855248' - showCalls: 'user' - showStorageLogs: 'read' - showVmDetails: 'all' - showGasDetails: 'all' - resolveHashes: 'true' - log: 'info' - logFilePath: 'era_test_node.log' - target: 'x86_64-unknown-linux-gnu' - releaseTag: 'latest' - - - name: Install Dependencies - run: yarn install - - - name: Run Tests - run: | - yarn test:contracts - - - name: Upload era_test_node log - uses: actions/upload-artifact@v3 - with: - name: era_test_node-log - path: era_test_node.log -``` - -With Fork: - -```yaml -name: Run Era Test Node Action - -on: - push: - branches: [main] - -jobs: - build: - runs-on: ubuntu-latest - - steps: - - name: Checkout code - uses: actions/checkout@v3 - - - name: Run Era Test Node - uses: dutterbutter/era-test-node-action@latest - with: - mode: 'fork' - network: 'mainnet' - forkAtHeight: '1855248' - showCalls: 'user' - showStorageLogs: 'read' - showVmDetails: 'all' - showGasDetails: 'all' - resolveHashes: 'true' - log: 'info' - logFilePath: 'era_test_node.log' - target: 'x86_64-unknown-linux-gnu' - releaseTag: 'latest' -``` diff --git a/content/20.build/test-and-debug/dockerized-l1-l2-nodes.md b/content/20.build/test-and-debug/dockerized-l1-l2-nodes.md deleted file mode 100644 index 279d8e99..00000000 --- a/content/20.build/test-and-debug/dockerized-l1-l2-nodes.md +++ /dev/null @@ -1,99 +0,0 @@ ---- -description: Guide to setup dockerized containers of L1 and L2 nodes. ---- - -# Dockerized L1 - L2 Nodes - -Welcome to this step-by-step guide on establishing a local testing environment using Docker for zkSync development. With -this guide, you can effortlessly emulate the zkSync environment on your local system, making it simpler to test and -develop features. Let's get started! - -**Prerequisites**: - -1. **Docker and docker-compose**: Ensure that Docker and docker-compose are installed on your machine. If you haven't - already installed them, follow the installation [guide](https://docs.docker.com/get-docker/). -2. **zkSync Hardhat plugins**: A foundational understanding of the zkSync Hardhat plugins will be beneficial. New to - zkSync development with Hardhat? Explore the getting started section. - -### **Setting Up the Testing Environment** - -Clone the dockerized zkSync project repository to your local machine: - -```bash -git clone https://github.com/matter-labs/local-setup.git -``` - -#### **Starting the Local Node** - -Navigate to the cloned directory: - -```bash -cd local-setup -``` - -Launch the zkSync Era node locally using the `start.sh` script: - -```bash -./start.sh -``` - -This script spins up three essential docker containers: - -1. **Postgres**: The database supporting zkSync. -2. **Local Geth node**: Acts as the Layer 1 (L1) for zkSync. -3. **zkSync node**: The core component. - -:::info The first execution of the `start.sh` script should proceed without interruptions. If it halts unexpectedly, you -might need to reset the local zkSync state and retry. The initialization might take up to 10 minutes initially. ::: - -### **Understanding Network Details** - -- **HTTP JSON-RPC API**: Accessible via port 3050. -- **WebSocket (WS) API**: Accessible through port 3051. - - Default endpoints: - -- **L1 RPC**: -- **L2 RPC**: -- **WS API**: - - **Network Id**: 270 - -### **Resetting the zkSync State** - -If you need to revert the zkSync state to its initial configuration, execute the `clear.sh` script: - -```bash -./clear.sh -``` - -In the event of a "permission denied" error, run the script with root access: - -```bash -sudo ./clear.sh -``` - -#### **Leveraging Rich Wallets** - -The local zkSync setup generously equips some wallets with ample amounts of ETH on both L1 and L2, making testing -easier. Access the list of preloaded accounts to obtain the addresses and corresponding private keys -[here](https://github.com/matter-labs/local-setup/blob/main/rich-wallets.json). - -### **Custom Configurations (Advanced)** - -To operate with a custom Postgres database or a distinct Layer 1 node, you'll need to adjust environment variables -within the `docker-compose` file: - -```yaml -environment: - - DATABASE_URL=postgres://postgres@postgres/zksync_local - - ETH_CLIENT_WEB3_URL=http://geth:8545 -``` - -Here, `DATABASE_URL` is the connection URL to the Postgres database, and `ETH_CLIENT_WEB3_URL` is the endpoint URL for -the HTTP JSON-RPC interface of the L1 node. - -### Conclusion - -By now, you should have a fully operational zkSync local testing environment. Dive into testing and development with the -assurance that you're operating within a controlled, emulated zkSync environment. Happy coding! diff --git a/content/20.build/test-and-debug/era-test-node.md b/content/20.build/test-and-debug/era-test-node.md deleted file mode 100644 index f5a22fd5..00000000 --- a/content/20.build/test-and-debug/era-test-node.md +++ /dev/null @@ -1,459 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: In-memory Node | zkSync Era Docs ---- - -# In-memory node - -This documentation provides instructions on setting up and using the In-Memory Node, `era-test-node`, for local testing. -It covers installation, network forking, transaction details viewing, replaying transactions, and testing local -bootloader and system contracts. - -:::warning Tool in alpha stage Please keep in mind that `era-test-node` is still in its **alpha** stage, so some -features might not be fully supported yet and may not work as fully intended. It is -[open-sourced](https://github.com/matter-labs/era-test-node) and contributions are welcomed. ::: - -## Understanding the In-Memory Node - -The In-memory node uses an in-memory database for storing state information and simplified hashmaps for tracking blocks -and transactions. In fork mode, it retrieves missing storage data from a remote source when not available locally. -Moreover it also uses the remote server (openchain) to resolve the ABI and topics to human readable names. - -You can visit the `era-test-node` repository [here](https://github.com/matter-labs/era-test-node) to learn more. - -## Running with `zksync-cli` - -You can setup In-Memory Node quickly with `npx zksync-cli dev start`. Note: at the moment this method won't allow you to -use additional features like forking networks or replaying transactions. - -## Installing and setting up `era-test-node` - -1. Download `era-test-node` from latest [Release](https://github.com/matter-labs/era-test-node/releases/latest) - -2. Extract the binary and mark as executable: - - ```bash - tar xz -f /path/to/downloaded/binary/era_test_node.tar.gz -C /usr/local/bin/ - chmod +x /usr/local/bin/era_test_node - ``` - -3. Start the node: - - ```bash - era_test_node run - ``` - -The expected output will be as follows: - -```shell -12:34:56 [INFO] Starting network with chain id: L2ChainId(260) -12:34:56 [INFO] Rich Accounts -12:34:56 [INFO] ============= -12:34:56 [INFO] Account #0: 0x36615Cf349d7F6344891B1e7CA7C72883F5dc049 (1_000_000_000_000 ETH) -12:34:56 [INFO] Private Key: 0x7726827caac94a7f9e1b160f7ea819f172f7b6f9d2a97f992c38edeab82d4110 -12:34:56 [INFO] -12:34:56 [INFO] Account #1: 0xa61464658AfeAf65CccaaFD3a512b69A83B77618 (1_000_000_000_000 ETH) -12:34:56 [INFO] Private Key: 0xac1e735be8536c6534bb4f17f06f6afc73b2b5ba84ac2cfb12f7461b20c0bbe3 - -... - -12:34:56 [INFO] Account #9: 0xE90E12261CCb0F3F7976Ae611A29e84a6A85f424 (1_000_000_000_000 ETH) -12:34:56 [INFO] Private Key: 0x3eb15da85647edd9a1159a4a13b9e7c56877c4eb33f614546d4db06a51868b1c -12:34:56 [INFO] -12:34:56 [INFO] ======================================== -12:34:56 [INFO] Node is ready at 127.0.0.1:8011 -12:34:56 [INFO] ======================================== -``` - -:::warning When utilizing `era-test-node` with MetaMask, it's essential to note that any restart of the in-memory node -will necessitate a reset of MetaMask's cached account data (nonce, etc). To do this, navigate to 'Settings', then -'Advanced', and finally, select 'Clear activity tab data'. ::: - -### Network details - -The `era_test_node` has the following default network configurations: - -- **L2 RPC:** `http://localhost:8011` -- **Network Id:** 260 - -These can be configured to your preference. - -::: warning Please note that the existing implementation does not facilitate communication with Layer 1. As a result, an -L1 RPC is not available. ::: - -## Forking networks - -To fork the mainnet, use the following command: - -```bash -era_test_node fork mainnet -``` - -:::tip You can also fork the zkSync Sepolia testnet with `era_test_node fork sepolia-testnet` ::: - -The expected output will be similar to the following: - -```shell -14:50:12 INFO Creating fork from "https://mainnet.era.zksync.io:443" L1 block: L1BatchNumber(356201) L2 block: 21979120 with timestamp 1703083811, L1 gas price 41757081846 and protocol version: Some(Version18) -14:50:12 INFO Starting network with chain id: L2ChainId(260) -14:50:12 INFO -14:50:12 INFO Rich Accounts -14:50:12 INFO ============= -14:50:16 INFO Account #0: 0xBC989fDe9e54cAd2aB4392Af6dF60f04873A033A (1_000_000_000_000 ETH) -14:50:16 INFO Private Key: 0x3d3cbc973389cb26f657686445bcc75662b415b656078503592ac8c1abb8810e -14:50:16 INFO Mnemonic: mass wild lava ripple clog cabbage witness shell unable tribe rubber enter -14:50:16 INFO -14:50:16 INFO Account #1: 0x55bE1B079b53962746B2e86d12f158a41DF294A6 (1_000_000_000_000 ETH) -14:50:16 INFO Private Key: 0x509ca2e9e6acf0ba086477910950125e698d4ea70fa6f63e000c5a22bda9361c -14:50:16 INFO Mnemonic: crumble clutch mammal lecture lazy broken nominee visit gentle gather gym erupt - -... - -14:50:19 INFO Account #9: 0xe2b8Cb53a43a56d4d2AB6131C81Bd76B86D3AFe5 (1_000_000_000_000 ETH) -14:50:19 INFO Private Key: 0xb0680d66303a0163a19294f1ef8c95cd69a9d7902a4aca99c05f3e134e68a11a -14:50:19 INFO Mnemonic: increase pulp sing wood guilt cement satoshi tiny forum nuclear sudden thank -14:50:19 INFO -14:50:19 INFO ======================================== -14:50:19 INFO Node is ready at 127.0.0.1:8011 -14:50:19 INFO ======================================== -``` - -This command starts the node, forked at the current head of the testnet. - -You also have the option to specify a custom http endpoint and a custom forking height, like so: - -```bash -# Usage: era_test_node fork --fork-at -era_test_node fork --fork-at 7000000 mainnet http://172.17.0.3:3060 -``` - -## Replay remote transactions locally - -If you wish to replay a remote transaction locally for deep debugging, use the following command: - -```bash -# Usage: era_test_node replay_tx -era_test_node replay_tx sepolia-testnet 0x7119045573862797257e4441ff48bf5a3bc4d133a00d167c18dc955eda12cfac -``` - -For more detailed transaction information, such as call traces, add the `--show-calls` flag. If you want to see ABI -names, add the `--resolve-hashes` flag. Here's an example: - -```bash -# Usage: era_test_node replay_tx -era_test_node --show-calls=user --resolve-hashes replay_tx sepolia-testnet 0x7119045573862797257e4441ff48bf5a3bc4d133a00d167c18dc955eda12cfac -``` - -Alternatively (if your node is already running) you can use `config_setShowCalls` and `config_setResolveHashes` RPC -endpoints to configure these values. Here's an example: - -```bash -# era_test_node already running... - -# Set show-calls to User -curl --request POST \ - --url http://localhost:8011/ \ - --header 'content-type: application/json' \ - --data '{"jsonrpc": "2.0","id": "1","method": "config_setShowCalls","params": ["user"]}' - -# Enable resolve-hashes -curl --request POST \ - --url http://localhost:8011/ \ - --header 'content-type: application/json' \ - --data '{"jsonrpc": "2.0","id": "1","method": "config_setResolveHashes","params": [true]}' -``` - -Here's an example of what you should expect to see when `show-calls` and `resolve-hashes` are configured: - -```shell -Creating fork from "https://sepolia.era.zksync.dev:443" L1 block: L1BatchNumber(4513) L2 block: 14945 with timestamp 1703064786, L1 gas price 61083275326 and protocol version: Some(Version19) -Starting network with chain id: L2ChainId(300) -Running 1 transactions (one per batch) - -Validating 0x7119045573862797257e4441ff48bf5a3bc4d133a00d167c18dc955eda12cfac -Executing 0x7119045573862797257e4441ff48bf5a3bc4d133a00d167c18dc955eda12cfac -┌─────────────────────────┐ -│ TRANSACTION SUMMARY │ -└─────────────────────────┘ -Transaction: SUCCESS -Initiator: 0x4eaf936c172b5e5511959167e8ab4f7031113ca3 -Payer: 0x4eaf936c172b5e5511959167e8ab4f7031113ca3 -Gas - Limit: 2_487_330 | Used: 969_330 | Refunded: 1_518_000 -Use --show-gas-details flag or call config_setShowGasDetails to display more info - -==== Console logs: - -==== 22 call traces. Use --show-calls flag or call config_setShowCalls to display more info. - Call(Normal) 0x4eaf936c172b5e5511959167e8ab4f7031113ca3 validateTransaction(bytes32, bytes32, tuple) 1830339 - Call(Normal) 0x0000000000000000000000000000000000000001 0x89c19e9b 1766835 - Call(Normal) 0x4eaf936c172b5e5511959167e8ab4f7031113ca3 payForTransaction(bytes32, bytes32, tuple) 1789767 - Call(Normal) 0x4eaf936c172b5e5511959167e8ab4f7031113ca3 executeTransaction(bytes32, bytes32, tuple) 1671012 - Call(Mimic) 0x5d4fb5385ed95b65d1cd6a10ed9549613481ab2f 0x 1443393 - -==== 4 events -EthToken System Contract - Topics: - Transfer(address,address,uint256) - 0x0000000000000000000000004eaf936c172b5e5511959167e8ab4f7031113ca3 - 0x0000000000000000000000000000000000000000000000000000000000008001 - Data (Hex): 0x000000000000000000000000000000000000000000000000000c31dac51a6200 - -EthToken System Contract - Topics: - Transfer(address,address,uint256) - 0x0000000000000000000000000000000000000000000000000000000000008001 - 0x0000000000000000000000004eaf936c172b5e5511959167e8ab4f7031113ca3 - Data (Hex): 0x0000000000000000000000000000000000000000000000000009fc4d1bd4ad00 - -EthToken System Contract - Topics: - Transfer(address,address,uint256) - 0x0000000000000000000000004eaf936c172b5e5511959167e8ab4f7031113ca3 - 0x0000000000000000000000005d4fb5385ed95b65d1cd6a10ed9549613481ab2f - Data (Hex): 0x0000000000000000000000000000000000000000000000000090f705956a4008 - -EthToken System Contract - Topics: - Transfer(address,address,uint256) - 0x0000000000000000000000000000000000000000000000000000000000008001 - 0x0000000000000000000000004eaf936c172b5e5511959167e8ab4f7031113ca3 - Data (Hex): 0x000000000000000000000000000000000000000000000000000159273ab13800 -``` - -## Sending network calls - -You can send network calls against a running `era-test-node`. You can check the Sepolia testnet LINK balance or mainnet -USDT using `curl` or [foundry-zksync](https://github.com/matter-labs/foundry-zksync). - -To get started, launch the local in-memory node: - -```bash -era_test_node fork sepolia-testnet -``` - -Next, use curl to send a network call: - -```bash -curl -X POST -H "Content-Type: application/json" --data '{"jsonrpc":"2.0","method":"eth_call","params":[{"to":"0xe1134444211593Cfda9fc9eCc7B43208615556E2", "data":"0x313ce567"}, "latest"],"id":1}' http://localhost:8011 -``` - -Here's an example of what you should expect to see: - -```bash -{"jsonrpc":"2.0","result":"0x0000000000000000000000000000000000000000000000000000000000000012","id":1} -``` - -Or, if you prefer, use [`foundry-zksync`](https://github.com/matter-labs/foundry-zksync). Make sure to install and -configure `foundry-zksync` before proceeding (for installation instructions, please see this -[link](https://github.com/matter-labs/foundry-zksync/tree/main#foundry-with-zksync-era-v01)): - -```bash -zkcast call 0xe1134444211593Cfda9fc9eCc7B43208615556E2 "name()(string)" --rpc-url http://localhost:8011 -``` - -Here's an example of what you should expect to see: - -```bash -Uniswap -``` - -Retrieve the balance of a particular contract: - -```bash -zkcast call 0x40609141Db628BeEE3BfAB8034Fc2D8278D0Cc78 "balanceOf(address)(uint256)" 0x40609141Db628BeEE3BfAB8034Fc2D8278D0Cc78 --rpc-url http://localhost:8011 -``` - -Here's an example of what you should expect to see: - -```bash -28762283719941475444443116625665 -``` - -### Deploying contracts - -For the deployment of your contracts, you have the flexibility to choose between two preferred methods: either by using -Hardhat with the `hardhat-zksync-deploy` and `hardhat-zksync-solc` plugins, or via `foundry-zksync`. The following -example will detail the process using `foundry-zksync`. - -Before proceeding, ensure that you've compiled your contracts using `zkforge zk-build`. For instructions on how to do -this, please refer to this [link](https://github.com/matter-labs/foundry-zksync#compile-with-zkforge-zk-build). - -```bash -zkforge zkc contracts/Greeter.sol:Greeter --constructor-args "ZkSync and Foundry" --private-key 7726827caac94a7f9e1b160f7ea819f172f7b6f9d2a97f992c38edeab82d4110 --rpc-url http://localhost:8011 --chain 260 -``` - -Here's an example of what you should expect to see: - -```bash -Deploying contract... -+-------------------------------------------------+ -Contract successfully deployed to address: 0x0a40ecde17dc16c4001bf0e4f5d5ff1818219b3b -Transaction Hash: 0x9d59bea38ca6f3cef365c23f339547bcc8ce28abb8344999ffffa5fa62c9ff8e -Gas used: 2570407 -Effective gas price: 500 -Block Number: 8072361 -+-------------------------------------------------+ -``` - -## Testing bootloader and system contracts - -In-memory node allows testing of the currently compiled bootloader and system contracts. This makes it possible to -examine the effects of changes on already deployed contracts. - -:::warning These commands assume you have set `$ZKSYNC_HOME` in your shell profile file (e.g. ~/.bash_profile, ~/.zshrc) -to target your local copy of `era-test-node`. For instance, - -```bash -# Add path here: -export ZKSYNC_HOME=/path/to/era-test-node - -export PATH=$ZKSYNC_HOME/bin:$PATH -``` - -::: - -Firstly, you will need to preprocess and compile the contracts: - -```bash -cd etc/system-contracts -yarn preprocess && yarn hardhat run ./scripts/compile-yul.ts -``` - -To use the locally compiled bootloader and system contracts, run: - -```bash -RUST_LOG=vm=trace era_test_node --dev-use-local-contracts fork sepolia-testnet -``` - -## Use pre-configured rich wallets - -In-Memory node includes pre-configured "rich" accounts for testing: - -| Account Address | Private Key | -| -------------------------------------------- | -------------------------------------------------------------------- | -| `0x36615Cf349d7F6344891B1e7CA7C72883F5dc049` | `0x7726827caac94a7f9e1b160f7ea819f172f7b6f9d2a97f992c38edeab82d4110` | -| `0xa61464658AfeAf65CccaaFD3a512b69A83B77618` | `0xac1e735be8536c6534bb4f17f06f6afc73b2b5ba84ac2cfb12f7461b20c0bbe3` | -| `0x0D43eB5B8a47bA8900d84AA36656c92024e9772e` | `0xd293c684d884d56f8d6abd64fc76757d3664904e309a0645baf8522ab6366d9e` | -| `0xA13c10C0D5bd6f79041B9835c63f91de35A15883` | `0x850683b40d4a740aa6e745f889a6fdc8327be76e122f5aba645a5b02d0248db8` | -| `0x8002cD98Cfb563492A6fB3E7C8243b7B9Ad4cc92` | `0xf12e28c0eb1ef4ff90478f6805b68d63737b7f33abfa091601140805da450d93` | -| `0x4F9133D1d3F50011A6859807C837bdCB31Aaab13` | `0xe667e57a9b8aaa6709e51ff7d093f1c5b73b63f9987e4ab4aa9a5c699e024ee8` | -| `0xbd29A1B981925B94eEc5c4F1125AF02a2Ec4d1cA` | `0x28a574ab2de8a00364d5dd4b07c4f2f574ef7fcc2a86a197f65abaec836d1959` | -| `0xedB6F5B4aab3dD95C7806Af42881FF12BE7e9daa` | `0x74d8b3a188f7260f67698eb44da07397a298df5427df681ef68c45b34b61f998` | -| `0xe706e60ab5Dc512C36A4646D719b889F398cbBcB` | `0xbe79721778b48bcc679b78edac0ce48306a8578186ffcb9f2ee455ae6efeace1` | -| `0xE90E12261CCb0F3F7976Ae611A29e84a6A85f424` | `0x3eb15da85647edd9a1159a4a13b9e7c56877c4eb33f614546d4db06a51868b1c` | - -## Writing and running tests locally - -This section demonstrates how to author and execute tests locally against `era-test-node` using the `mocha` and `chai` -testing frameworks. - -### Project configuration - -1. Start by creating a new Hardhat project. If you need guidance, follow the - [getting started guide](../../build/tooling/hardhat/getting-started.md). - -2. To incorporate the test libraries, execute: - -```bash -yarn add -D mocha chai @types/mocha @types/chai -``` - -3. Add the following lines to your `package.json` in the root folder: - -```json -"scripts": { - "test": "NODE_ENV=test hardhat test" -} -``` - -This script makes it possible to run tests in a Hardhat environment with the `NODE_ENV` env variable set as `test`. - -### Configuring tests - -4. Adjust `hardhat.config.ts` to use the local node for testing: - -:::warning Ensure era-test-node is running in another process before executing yarn test. ::: - -```typescript -import '@matterlabs/hardhat-zksync-deploy'; -import '@matterlabs/hardhat-zksync-solc'; - -module.exports = { - zksolc: { - version: 'latest', - settings: {}, - }, - defaultNetwork: 'zkSyncTestnet', - networks: { - hardhat: { - zksync: true, - }, - zkSyncTestnet: { - url: 'http://localhost:8011', - ethNetwork: 'http://localhost:8545', - zksync: true, - }, - }, - solidity: { - version: '0.8.17', - }, -}; -``` - -### Writing test scripts - -5. Now, create your first test! Construct a `test/main.test.ts` file with the following code: - -```ts -import { expect } from 'chai'; -import { Wallet, Provider, Contract } from 'zksync-ethers'; -import * as hre from 'hardhat'; -import { Deployer } from '@matterlabs/hardhat-zksync-deploy'; - -const RICH_WALLET_PK = '0x7726827caac94a7f9e1b160f7ea819f172f7b6f9d2a97f992c38edeab82d4110'; - -describe('Greeter', function () { - it("Should return the new greeting once it's changed", async function () { - const provider = Provider.getDefaultProvider(); - - const wallet = new Wallet(RICH_WALLET_PK, provider); - const deployer = new Deployer(hre, wallet); - - const artifact = await deployer.loadArtifact('Greeter'); - const greeter = await deployer.deploy(artifact, ['Hi']); - - expect(await greeter.greet()).to.eq('Hi'); - - const setGreetingTx = await greeter.setGreeting('Hola, mundo!'); - // wait until the transaction is mined - await setGreetingTx.wait(); - - expect(await greeter.greet()).to.equal('Hola, mundo!'); - }); -}); -``` - -To run the test file, execute: - -```bash -yarn test -``` - -Well done! You've successfully run your first local tests with zkSync Era and `era-test-node`. - -## Troubleshooting - -If running `era_test_node run` provides the following error: - -```shell -“era_test_node” can’t be opened because Apple cannot check it for malicious software. -This software needs to be updated. Contact the developer for more information. -``` - -You may require the use of `sudo`. On macOS, the binary may need to have its quarantine attribute cleared: - -```bash -xattr -d com.apple.quarantine /usr/local/bin/era_test_node -``` diff --git a/content/20.build/test-and-debug/foundry.md b/content/20.build/test-and-debug/foundry.md deleted file mode 100644 index 04ffd6fb..00000000 --- a/content/20.build/test-and-debug/foundry.md +++ /dev/null @@ -1,98 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Foundry | zkSync Docs ---- - -# zkSync Foundry Testing - -For instructions on how to install `foundry-zksync` please refer to the -[Getting Started](../tooling/foundry/getting-started.md) page. - -## Overview - -`foundry-zksync`, a fork of Foundry, provides developers with a tailored testing framework designed specifically for -zkSync environments. Utilizing `zkforge test`, you can execute your smart contract tests efficiently. Tests are written -in Solidity, and the framework is designed to recognize any contract function prefixed with `test` as a test case. By -convention, tests are typically stored within the `test/` directory and have a `.t.sol` extension. - -:::info For more detailed documentation related to Foundry testing please refer to the official upstream Foundry -documentation [here](https://book.getfoundry.sh/forge/tests). ::: - -## Running Tests - -To initiate your tests, use the `zkforge test` command. This command automatically locates and executes tests across -your source directory. Here's an example of executing tests in a standard project setup: - -```bash -zkforge test - -Running 2 tests for test/Counter.t.sol:CounterTest -[PASS] testFuzz_SetNumber(uint256) (runs: 256, μ: 27553, ~: 28409) -[PASS] test_Increment() (gas: 28379) -Test result: ok. 2 passed; 0 failed; 0 skipped; finished in 96.80ms -``` - -### Filtering Tests - -You can run specific tests by filtering based on the contract or test names: - -```bash -zkforge test --match-contract CounterTest --match-test test_Increment -``` - -This command will execute only the tests within `CounterTest` that include `test_Increment` in their name. - -Similarly, you can use `--match-path` to run tests in files that match a specific glob pattern: - -```bash -zkforge test --match-path Counter.t.sol -``` - -Inverse filters are available through `--no-match-contract`, `--no-match-test`, and `--no-match-path` flags. - -## Watch Mode - -To automatically re-run tests upon any file changes, use the `zkforge test --watch --run-all` command. - -## Writing Tests - -Tests are structured as Solidity contracts, often inheriting from the Forge Standard Library's `Test` contract for -enhanced functionality, including basic assertions and logging: - -```solidity -pragma solidity 0.8.10; - -import "forge-std/Test.sol"; - -contract ContractBTest is Test { - uint256 testNumber; - - function setUp() public { - testNumber = 42; - } - - function test_NumberIs42() public { - assertEq(testNumber, 42); - } - - function testFail_Subtract43() public { - testNumber -= 43; - } -} -``` - -### Key Concepts - -- **`setUp`:** An optional function that runs before each test, used for initializing test conditions. -- **`test`:** Prefix for functions that are recognized as tests. These functions must either pass or revert to indicate - success or failure, respectively. -- **`testFail`:** A prefix for test functions expected to revert. If such a function does not revert, the test is - considered failed. - -### Cheatcodes - -Cheatcodes allow you to change the block number, your identity, and more. `foundry-zksync` supports the most common -cheatcodes. For an exhaustive list of supported cheatcodes refer to the supported table -[here](https://github.com/matter-labs/foundry-zksync/blob/main/SUPPORTED_CHEATCODES.md). diff --git a/content/20.build/test-and-debug/getting-started.md b/content/20.build/test-and-debug/getting-started.md deleted file mode 100644 index 4e24d408..00000000 --- a/content/20.build/test-and-debug/getting-started.md +++ /dev/null @@ -1,77 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Getting Started | zkSync Docs ---- - -# Getting Started - -## Testing strategies for zkSync Era - -zkSync Era provides two distinct testing environments for your development needs - -- Dockerized Local Setup -- In-Memory Node. - -Each solution boasts unique characteristics tailored to diverse use cases. This guide aims to unpack the intricacies of -these tools, aiding you in selecting the setup best suited for your development workflow. - -## In-Memory node vs Dockerized Local Setup - -The local testing process revolves around two principal options: - -1. **Dockerized local setup**: An extensive zkSync Era network simulation that comprises a Postgres database, a local - Geth node functioning as Layer 1, and the zkSync node. Opt for this setup for comprehensive simulations and testing - that require interaction with both L1 and L2. - -2. **In-Memory node**: A lightweight, speedy alternative, the in-memory node, supports forking the state from various - networks, including the mainnet and testnet. This choice is ideal for swift testing, prototyping, and bootloader and - system contract testing. - -### When to use each - -- Use the **Dockerized local setup** for in-depth simulations and tests that necessitate L1 and L2 interaction. This - complex and detailed setup mirrors how your contracts will function within the mainnet zkSync Era network. - -- Opt for the **In-Memory node** for swift testing, prototyping, or testing new changes via the local bootloader and - system contracts. This setup facilitates forking the state from the mainnet or testnet, suitable for replaying - transactions or observing the impact of modifications on existing contracts. - -:::warning Being in its alpha stage, the In-Memory Node comes with some constraints and doesn't fully support all -functionalities. For definitive testing, Dockerized Local Setup or a testnet is highly recommended. ::: - -### Feature comparison - -The following table highlights the key characteristics of each testing environment for a quick comparison: - -| Feature | In-memory node | Dockerized Local Setup | -| --------------------------------------- | ------------------- | ---------------------- | -| Quick startup | Yes | No | -| Supports forking state | Yes | No | -| Console.log debugging | Yes | No | -| Detailed call traces | Yes | No | -| Pre-configured 'rich' accounts | Yes | Yes | -| Replay existing transactions | Yes | No | -| Fast for integration testing | Yes | No | -| Communication between Layer 1 & Layer 2 | No | Yes | -| Multiple transactions per batch | No | Yes | -| Complete set of APIs | No (Basic set only) | Yes | -| Websocket support | No | Yes | - -Whether you're testing new contracts, debugging transactions, or prototyping, zkSync Era provides robust options for -local testing. Both the Dockerized local setup and the In-Memory Node offer feature-rich and quick setup options, each -with their distinct strengths and limitations. Choose the most appropriate setup based on your specific needs, and happy -testing! - -## Using zkSync CLI for Easy Setup - -The [zkSync CLI](../../build/tooling/zksync-cli/getting-started.md) makes it simple for developers to work with both -Dockerized Local Setup and In-Memory Node. Just use `zksync-cli dev start` to get your local development environment -running and choose to use additional modules like Block Explorer, Wallet and Bridge. - -## zkSync Era local testing - -- [Dockerized L1 - L2 Nodes](../../build/test-and-debug/dockerized-l1-l2-nodes.md) -- [In-memory node testing](../../build/test-and-debug/era-test-node.md) -- [zkSync CLI](../../build/tooling/zksync-cli/getting-started.md) diff --git a/content/20.build/test-and-debug/hardhat.md b/content/20.build/test-and-debug/hardhat.md deleted file mode 100644 index d8e134b5..00000000 --- a/content/20.build/test-and-debug/hardhat.md +++ /dev/null @@ -1,319 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Hardhat | zkSync Docs ---- - -# Hardhat - -### Introduction - -In the intricate world of decentralized applications, the margin for error is remarkably narrow. A single mistake in a -contract can have catastrophic implications. The immutable nature of blockchain technology makes it imperative for -developers to ensure their contracts operate flawlessly. For those seeking an efficient method to test and refine their -contracts, this guide showcases how to utilize Hardhat and `era_test_node` for all testing needs. - -### Step 1 - Understanding contract testing using HardHat - -Writing automated tests when building smart contracts is of crucial importance. - -To test our contract, we are going to use Hardhat, and `era_test_node` for rapid local development. In our tests we're -going to use `zksync-ethers` to interact with the Greeter contract, and we'll use [Mocha](https://mochajs.org/) as our -test runner. - -### Step 2 — Environment setup - -Using `zksync-cli` create a new project with the required dependencies and boilerplate paymaster implementations: - -```bash -npx zksync-cli create test-greeter -``` - -Choose `Hardhat + Solidity` to setup the project repository. The contract for this guide exists under -`/contracts/Greeter.sol`. - -Install dependencies: - -```bash -yarn install -``` - -Add the following additional dependencies: - -```bash -yarn add -D @matterlabs/hardhat-zksync-chai-matchers @nomicfoundation/hardhat-chai-matchers @nomiclabs/hardhat-ethers -``` - -Import `@matterlabs/hardhat-zksync-chai-matchers` into the `hardhat.config.ts` file: - -```typescript -import '@matterlabs/hardhat-zksync-chai-matchers'; -``` - -The `@matterlabs/hardhat-zksync-chai-matchers` plugin adds zkSync specific capabilities to the -[Chai](https://www.chaijs.com/) assertion library for testing smart contracts. It extends all the functionalities -supported by the [hardhat-chai-matchers](https://hardhat.org/hardhat-chai-matchers/docs/overview) plugin, with the idea -to preserve the same behaviour and interface. - -Before running tests, a local zkSync Era node is required. If you are unfamiliar with `era_test_node` refer to the -documentation [here](era-test-node/). Start `era_test_node`: - -```bash -./target/release/era_test_node run -``` - -### Step 3 - Running tests with Hardhat - -Under the `/test` directory there is a `main.test.ts` . The initial test checks if our `Greeter` contract returns the -set greeting. - -```typescript -import { expect } from 'chai'; -import { Wallet, Provider, Contract } from 'zksync-ethers'; -import * as hre from 'hardhat'; -import { Deployer } from '@matterlabs/hardhat-zksync-deploy'; -import { zkSyncTestnet } from '../hardhat.config'; - -const RICH_WALLET_PK = '0x7726827caac94a7f9e1b160f7ea819f172f7b6f9d2a97f992c38edeab82d4110'; - -async function deployGreeter(deployer: Deployer): Promise { - const artifact = await deployer.loadArtifact('Greeter'); - return await deployer.deploy(artifact, ['Hi']); -} - -describe('Greeter', function () { - it("Should return the new greeting once it's changed", async function () { - const provider = new Provider(zkSyncTestnet.url); - - const wallet = new Wallet(RICH_WALLET_PK, provider); - const deployer = new Deployer(hre, wallet); - - const greeter = await deployGreeter(deployer); - - expect(await greeter.greet()).to.eq('Hi'); - - const setGreetingTx = await greeter.setGreeting('Hola, mundo!'); - // wait until the transaction is mined - await setGreetingTx.wait(); - - expect(await greeter.greet()).to.equal('Hola, mundo!'); - }); -}); -``` - -To run this test: - -```bash -yarn test -``` - -You should see the following output: - -``` -$ yarn test - - Greeter - ✔ Should return the new greeting once it's changed (174ms) - - 1 passing (174ms) -``` - -This means the test passed. - -### Step 4 - Expanding test coverage - -Our aim is comprehensive coverage. Here are the test scenarios we will cover: - -1. **Testing greet() function**: Check the returned greeting. -2. **Testing setGreeting() function**: Verify the ability to update greetings. -3. **Testing Insufficient Funds**: Ensure transactions fail without enough funds. -4. **Event Emission**: Ensure an event is emitted when changing the greeting. - -Each of these test cases will rely on a common setup, which involves creating a provider connected to the `zkSync` -testnet, initializing a wallet with a known private key, and deploying the `Greeter` contract. - -Let's refactor our test file with the provided script: - -
- -main.test.ts - -```typescript -import { expect } from 'chai'; -import { Wallet, Provider, Contract } from 'zksync-ethers'; -import * as hre from 'hardhat'; -import { Deployer } from '@matterlabs/hardhat-zksync-deploy'; -import { zkSyncTestnet } from '../hardhat.config'; - -const RICH_WALLET_PK = '0x7726827caac94a7f9e1b160f7ea819f172f7b6f9d2a97f992c38edeab82d4110'; - -// Deploy the Greeter contract -async function deployGreeter(deployer: Deployer): Promise { - // Load the Greeter contract artifact - const artifact = await deployer.loadArtifact('Greeter'); - // Deploy the contract with an initial greeting - return await deployer.deploy(artifact, ['Hi']); -} - -describe('Greeter', function () { - let greeter; - let wallet; - let deployer; - - // Initialize commonly used variables before running the tests - before(async function () { - // Create a provider connected to the zkSync testnet - const provider = new Provider(zkSyncTestnet.url); - - // Create a wallet instance using the rich wallet's private key - wallet = new Wallet(RICH_WALLET_PK, provider); - // Create a deployer instance for contract deployments - deployer = new Deployer(hre, wallet); - // Deploy the Greeter contract - greeter = await deployGreeter(deployer); - }); - - // Test the greet() function - it("Should return the new greeting once it's changed", async function () { - // Ensure the greet function returns the initial greeting after deployment - expect(await greeter.greet()).to.eq('Hi'); - }); - - // Test the setGreeting() function - it('Should set a new greeting and return it', async function () { - // Set a new greeting - const setGreetingTx = await greeter.setGreeting('Hola, mundo!'); - // Wait for the transaction to be confirmed - await setGreetingTx.wait(); - - // Ensure the greet function returns the newly set greeting - expect(await greeter.greet()).to.equal('Hola, mundo!'); - }); - - // Test for lack of funds (or other tx failures) - it('Should fail when insufficient funds', async function () { - // Create an empty wallet with no funds - const userWallet = Wallet.createRandom(); - // Connect the empty wallet to the greeter contract and attempt to set a new greeting - try { - await greeter.connect(userWallet).setGreeting('fail'); - // The following line should not be reached if the transaction fails - expect(true).to.equal(false); - } catch (e) { - // Expect an error to be thrown for the transaction - expect(e).to.exist; - } - }); - - // Test event emission - it('Should emit an event when the greeting is changed', async function () { - const newGreeting = 'Bonjour, monde!'; - // Use the provided .emit method to test event emissions - await expect(greeter.setGreeting(newGreeting)).to.emit(greeter, 'GreetingChanged').withArgs(newGreeting); - }); -}); -``` - -
- -To run this test: - -```bash -yarn test -``` - -You should see the following output: - -``` -$ yarn test - - Greeter - ✔ Should return the new greeting once it's changed (211ms) - ✔ Should set a new greeting and return it (2682ms) - ✔ Should fail when insufficient funds (299ms) - ✔ Should emit an event when the greeting is changed (2939ms) - - 4 passing (6s) -``` - -### Step 5 - Reviewing the test file - -#### Initial Setup and Utilities - -```typescript -import { expect } from 'chai'; -import { Wallet, Provider, Contract } from 'zksync-ethers'; -import * as hre from 'hardhat'; -import { Deployer } from '@matterlabs/hardhat-zksync-deploy'; -import { zkSyncTestnet } from '../hardhat.config'; -``` - -This section imports all necessary utilities and configurations needed to run our tests. - -- `expect` from Chai provides assertion functionalities for our tests. -- `Wallet`, `Provider`, and `Contract` from `zksync-ethers` help us with zkSync functionalities like creating wallets - and interacting with contracts. -- `hre` and `Deployer` give us hardhat specific functionalities for deploying and interacting with our contract. -- `zkSyncTestnet` from our hardhat configuration provides network details of our running `era_test_node.` - -#### Contract Deployment Utility - -```javascript -async function deployGreeter(deployer: Deployer): Promise { ... } -``` - -This utility function simplifies deploying the Greeter contract for our tests. - -#### Main Test Suite - -```javascript -describe('Greeter', function () { ... } -``` - -Here, we've declared our main test suite. Each test or nested suite inside provides specific scenarios or -functionalities we want to test regarding the Greeter contract. - -1. **Initialization**: - - Before running any test, we initialize commonly used variables like the provider, wallet, deployer, and the greeter - contract. - -2. **Testing greet() function**: - - ```javascript - it("Should return the new greeting once it's changed", async function () { ... }); - ``` - - We check that the greet function returns the initial greeting of 'Hi' after deployment. - -3. **Testing setGreeting() function**: - - ```javascript - it("Should set a new greeting and return it", async function () { ... }); - ``` - - We test that setting a new greeting updates the contract's state as expected. - -4. **Insufficient Funds**: - - ```javascript - it("Should fail when insufficient funds", async function () { ... }); - ``` - - Here, we simulate a scenario where an empty wallet (with no funds) tries to set a new greeting. We make use of the - `connect` method on your `zksync-ethers` `Contract` object to connect it to a different account. - -5. **Event Emission**: - - ```javascript - it("Should emit an event when the greeting is changed", async function () { ... }); - ``` - - We test the emission of an event when the greeting changes in the contract making use of the - `hardhat-zksync-chai-matchers`. - -### Conclusion - -Testing contracts using Hardhat on zkSync Era provides a familiar environment for developers. With minimal changes, you -can test contracts with ease and speed. diff --git a/content/20.build/test-and-debug/testing-examples/README.md b/content/20.build/test-and-debug/testing-examples/README.md deleted file mode 100644 index 8cfa9416..00000000 --- a/content/20.build/test-and-debug/testing-examples/README.md +++ /dev/null @@ -1 +0,0 @@ -# Testing Examples diff --git a/content/20.build/test-and-debug/testing-examples/impersonate-account.md b/content/20.build/test-and-debug/testing-examples/impersonate-account.md deleted file mode 100644 index 142182dc..00000000 --- a/content/20.build/test-and-debug/testing-examples/impersonate-account.md +++ /dev/null @@ -1,68 +0,0 @@ -# Impersonate Account - -In testing and development, the need sometimes arises to impersonate or act on behalf of another account without -actually knowing its private key. Hardhat provides methods to facilitate this. Below is an example that demonstrates the -usage of these methods. - -### **Impersonating Account** - -**Test Description**: Demonstrates the capability to transfer funds from an account without knowing its private key -using account impersonation methods provided by Hardhat. - -**Arrange:** - -- Create a random user wallet and connect it to the provider. -- Fetch the balance of a rich account you want to impersonate. - -**Act:** - -1. Start account impersonation using `hardhat_impersonateAccount` method. -2. Get the signer associated with the impersonated account. -3. Send a transaction from the impersonated account to the user wallet. -4. Stop the impersonation of the account using `hardhat_stopImpersonatingAccount` method. - -**Assert:** - -- Verify the balance of the user wallet to confirm the receipt of funds. -- Check the balance of the impersonated account to confirm the deduction of sent funds. - -
- -Impersonate account test - -```typescript -describe('hardhat_impersonateAccount & hardhat_stopImpersonatingAccount', function () { - it('Should allow transfers of funds without knowing the Private Key', async function () { - // Arrange - const userWallet = Wallet.createRandom().connect(provider); - const beforeBalance = await provider.getBalance(RichAccounts[0].Account); - - // Act - // Begin account impersonation - await provider.send('hardhat_impersonateAccount', [RichAccounts[0].Account]); - - const signer = await ethers.getSigner(RichAccounts[0].Account); - const tx = { - to: userWallet.address, - value: ethers.utils.parseEther('0.42'), - }; - - // Send a transaction from the impersonated account - const receiptTx = await signer.sendTransaction(tx); - await receiptTx.wait(); - - // Stop impersonating the account - await provider.send('hardhat_stopImpersonatingAccount', [RichAccounts[0].Account]); - - // Assert - // Check that the balances have been updated accordingly - expect(await userWallet.getBalance()).to.equal(ethers.utils.parseEther('0.42')); - expect(await provider.getBalance(RichAccounts[0].Account)).to.equal(beforeBalance.sub(0.42)); - }); -}); -``` - -
- -This test effectively demonstrates the capacity to simulate actions from any account, a feature that proves invaluable -when emulating real-world interactions in a testing environment without access to account keys. diff --git a/content/20.build/test-and-debug/testing-examples/time-change.md b/content/20.build/test-and-debug/testing-examples/time-change.md deleted file mode 100644 index 4b1fe9c2..00000000 --- a/content/20.build/test-and-debug/testing-examples/time-change.md +++ /dev/null @@ -1,178 +0,0 @@ -# Time Change - -This document presents a series of test examples centred around time manipulation in the zkSync Era environment. Each -example highlights a unique scenario, ensuring developers understand how to simulate specific blockchain states. - -:::info To utilize these methods, you need to run tests against `era_test_node`. ::: - -### **Mining a Single Block** - -**Test Description**: Verifies if a single block is mined when triggering the `evm_mine` command. - -- **Arrange**: Fetch the current block from the blockchain. -- **Act**: Mine a new block using the `evm_mine` method. -- **Assert**: Confirm that the block number has incremented by one. - -
- -evm_mine test - -```typescript -describe('evm_mine', function () { - it('Should mine one block', async function () { - // Arrange - const startingBlock = await provider.getBlock('latest'); - - // Act - await provider.send('evm_mine', []); - - // Assert - const latestBlock = await provider.getBlock('latest'); - expect(latestBlock.number).to.equal(startingBlock.number + 1); - }); -}); -``` - -
- -### **Increasing Node Timestamp** - -**Test Description**: Ensures the node's timestamp increases correctly by a specified amount when invoking the -`evm_increaseTime` command. - -- **Arrange**: - - Set the time increment (13 seconds in this example). - - Configure wallets using provided private keys and a randomly generated one. - - Fetch the current timestamp and calculate the expected timestamp by adding the increment. -- **Act**: - - Increase the node's timestamp using the `evm_increaseTime` method. - - Initiate a transaction, which in turn will mine two new blocks, and thus, the expected timestamp should consider - this. -- **Assert**: Confirm that the timestamp of the latest block matches the expected timestamp. - -
- -evm_increaseTime test - -```typescript -describe('evm_increaseTime', function () { - it('Should increase current timestamp of the node', async function () { - // Arrange - const timeIncreaseInSeconds = 13; - const wallet = new Wallet(RichAccounts[0].PrivateKey, provider); - const userWallet = Wallet.createRandom().connect(provider); - let expectedTimestamp: number = await provider.send('config_getCurrentTimestamp', []); - expectedTimestamp += timeIncreaseInSeconds * 1000; - - // Act - await provider.send('evm_increaseTime', [timeIncreaseInSeconds]); - - await wallet.sendTransaction({ - to: userWallet.address, - value: ethers.utils.parseEther('0.1'), - }); - expectedTimestamp += 2; // New transaction will add two blocks - - // Assert - const newBlockTimestamp = (await provider.getBlock('latest')).timestamp; - expect(newBlockTimestamp).to.equal(expectedTimestamp); - }); -}); -``` - -
- -### **Setting Next Block Timestamp:** - -**Test Description**: Validates the ability to specifically set the timestamp for the next block via the -`evm_setNextBlockTimestamp` command. - -- **Arrange**: - - Set the desired time increment (123 milliseconds for this instance). - - Compute the expected timestamp by adding the increment to the current timestamp. - - Set up wallets for transaction purposes. -- **Act**: - - Assign the next block's timestamp using the `evm_setNextBlockTimestamp` method. - - Trigger a transaction, which will result in the mining of two new blocks. Adjust the expected timestamp accordingly. -- **Assert**: Confirm that the timestamp of the most recent block aligns with the expected timestamp. - -
- -evm_setNextBlockTimestamp - -```typescript -describe('evm_setNextBlockTimestamp', function () { - it('Should set current timestamp of the node to specific value', async function () { - // Arrange - const timeIncreaseInMS = 123; - let expectedTimestamp: number = await provider.send('config_getCurrentTimestamp', []); - expectedTimestamp += timeIncreaseInMS; - const wallet = new Wallet(RichAccounts[0].PrivateKey, provider); - const userWallet = Wallet.createRandom().connect(provider); - - // Act - await provider.send('evm_setNextBlockTimestamp', [expectedTimestamp]); - - await wallet.sendTransaction({ - to: userWallet.address, - value: ethers.utils.parseEther('0.1'), - }); - expectedTimestamp += 2; // New transaction will add two blocks - - // Assert - const newBlockTimestamp = (await provider.getBlock('latest')).timestamp; - expect(newBlockTimestamp).to.equal(expectedTimestamp); - }); -}); -``` - -
- -### **Directly Setting Node Timestamp** - -**Test Description**: Demonstrates how to set the node's timestamp to an explicit value using the `evm_setTime` command. - -- **Arrange**: - - Specify the desired time increment (123 milliseconds in this context). - - Derive the expected timestamp by adding the increment to the existing timestamp. - - Establish wallets for testing. -- **Act**: - - Directly set the node's timestamp via the `evm_setTime` method. - - Initiate a transaction which will, in turn, lead to the mining of two additional blocks. Modify the expected - timestamp to reflect this. -- **Assert**: Confirm that the latest block's timestamp corresponds with the expected value. - -
- -evm_setTime test - -```typescript -describe('evm_setTime', function () { - it('Should set current timestamp of the node to specific value', async function () { - // Arrange - const timeIncreaseInMS = 123; - let expectedTimestamp: number = await provider.send('config_getCurrentTimestamp', []); - expectedTimestamp += timeIncreaseInMS; - const wallet = new Wallet(RichAccounts[0].PrivateKey, provider); - const userWallet = Wallet.createRandom().connect(provider); - - // Act - await provider.send('evm_setTime', [expectedTimestamp]); - - await wallet.sendTransaction({ - to: userWallet.address, - value: ethers.utils.parseEther('0.1'), - }); - expectedTimestamp += 2; // New transaction will add two blocks - - // Assert - const newBlockTimestamp = (await provider.getBlock('latest')).timestamp; - expect(newBlockTimestamp).to.equal(expectedTimestamp); - }); -}); -``` - -
- -Developers can utilize these tests as templates to simulate specific time-based scenarios in zkSync. This ability is -crucial for debugging, developing time-dependent features, or understanding chain behaviors. diff --git a/content/20.build/tooling/block-explorer/block-explorer-api.md b/content/20.build/tooling/block-explorer/block-explorer-api.md deleted file mode 100644 index 83740b80..00000000 --- a/content/20.build/tooling/block-explorer/block-explorer-api.md +++ /dev/null @@ -1,36 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Block Explorer API | zkSync Docs ---- - -# Block Explorer API - -We’ve developed the [zkSync Era Block Explorer API](https://block-explorer-api.mainnet.zksync.io/docs) for developers to -access [zkSync Era Block Explorer](https://explorer.zksync.io/) data directly via HTTP requests. - -The [API](https://block-explorer-api.mainnet.zksync.io/docs) provides various endpoints for many use cases you might -want in your app. It is compatible with [Etherscan API](https://docs.etherscan.io/), which makes it easy to transition -your existing apps to zkSync Era network. - -The following modules are supported: - -- [Contract](https://block-explorer-api.mainnet.zksync.io/docs#/Contract%20API) -- [Account](https://block-explorer-api.mainnet.zksync.io/docs#/Account%20API) -- [Transaction](https://block-explorer-api.mainnet.zksync.io/docs#/Transaction%20API) -- [Logs](https://block-explorer-api.mainnet.zksync.io/docs#/Logs%20API) -- [Block](https://block-explorer-api.mainnet.zksync.io/docs#/Block%20API) - -Check out the API documentation [API docs on Mainnet](https://block-explorer-api.mainnet.zksync.io/docs) | -[API docs on Testnet](https://block-explorer-api.testnets.zksync.dev/docs) - -:::note Note - -The [API](https://block-explorer-api.mainnet.zksync.io/docs) does not fully cover all the functionality yet. ::: - -We are working on additional endpoints to cover more use cases and to make developers’ experience better. Stay tuned for -further updates. - -Feel free to contribute and create issues and feature requests in -[zkSync Era Block Explorer GitHub repo](https://github.com/matter-labs/block-explorer). diff --git a/content/20.build/tooling/block-explorer/block-explorer-menu.md b/content/20.build/tooling/block-explorer/block-explorer-menu.md deleted file mode 100644 index aeeeabd8..00000000 --- a/content/20.build/tooling/block-explorer/block-explorer-menu.md +++ /dev/null @@ -1,94 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Block Explorer Menu | zkSync Docs ---- - -# Block explorer menu - -![zkSync Era block explorer menu](../../../assets/images/block-explorer-menu.png) - -The [zkSync Era block explorer menu](https://explorer.zksync.io/) displays real-time and historical graphical data on -[blocks](#blocks), [batches](#batches), [transactions](#transactions), and [tokens](#token-list). - -## Blocks - -- Click [**Blocks**](https://explorer.zksync.io/blocks/) in the block explorer menu to go to the Blocks page. - -![zkSync Era block explorer blocks page](../../../assets/images/blocks.png) - -- Blocks are listed by block number, newest first, with status details and age. - -- Blocks are paginated in groups of 10 and you can scroll through the pages at the bottom, or add a specific block - number to the URL. - - For example [https://explorer.zksync.io/block/41849](https://explorer.zksync.io/block/41849). - -- Click on any block number to see more details about a block. - -![zkSync Era block explorer block details page](../../../assets/images/block-details.png) - -- **Block Size** denotes the number of transactions in a block. - -- **Batch** displays the batch number in which the block is submitted to L1. - -- The block details page lists all transactions included in the block. - -## Batches - -- Click [**Batches**](https://explorer.zksync.io/batches/) in the block explorer menu to go to the Batches page. - -![zkSync Era block explorer batches page](../../../assets/images/batches.png) - -- Batches are listed by batch number, newest first, with status details, size, and age. - -- Click on any batch number to see more details about a batch. - -![zkSync Era block explorer batch details page](../../../assets/images/batch-details.png) - -- **Batch Size** denotes the number of transactions in a batch. - -- **Commit tx hash** is the hash of the L1 transaction hash on Etherscan. - -- **Committed**, **Proven**, and **Executed** are verification stages the batch goes through and go to Etherscan L1 - details. - -- The batch details page lists all transactions included in the batch. - -## Transactions - -- Click [**Transactions**](https://explorer.zksync.io/transactions/) in the block explorer menu to go to the - Transactions page. - -![zkSync Era block explorer transactions page](../../../assets/images/transactions.png) - -- Transactions are listed by status and transaction hash, newest first, method, age, initiator address, recipient, value - and fee. - -- Click on a transaction hash to see more details. - -![zkSync Era block explorer transaction details page](../../../assets/images/transaction-details.png) - -| Data point | Description | -| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| Transaction Hash | Unique 66 character identifier generated when transaction submitted to L2. | -| Status | One of `Indexing`, `zkSync Era Processed, Ethereum Sending`, `zkSync Era Processed, Ethereum Validating`, `zkSync Era Processed, Ethereum Executing`, `zkSync Era Processed, Ethereum Executed` or `Failed` with links to Etherscan (if they exist already). | -| Block | Block number containing the transaction. | -| Batch | Batch number containing the transaction. | -| From | The account or smart contract address sending the transaction. | -| To | The transaction recipient. | -| Tokens Transferred | Details on all tokens transferred by the transaction. | -| Input data | Any additional data used by the transaction for verified contracts. | -| Value | Amount of Ether being transferred from one address to another within a transaction. | -| Fee | Fee for the tx in ETH and USD value. Click **More Details** to see info on refunds. | -| Nonce | Sender nonce. | -| Created | Timestamp of when the transaction was added to the block. | - -## Token list - -- Click [**Token List**](https://explorer.zksync.io/tokenlist) in the block explorer menu to go to the Token List page. - -![zkSync Era block explorer token list page](../../../assets/images/token-list.png) - -- Use the token addresses for bridging tokens. diff --git a/content/20.build/tooling/block-explorer/block-explorers.md b/content/20.build/tooling/block-explorer/block-explorers.md deleted file mode 100644 index c34ce713..00000000 --- a/content/20.build/tooling/block-explorer/block-explorers.md +++ /dev/null @@ -1,69 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Block Explorers | zkSync Docs ---- - -# Block Explorers - -A full list of zkSync block explorers can be found on [Block Explorers page](https://zksync.io/explore#explorers). - -### zkSync Era Official Block Explorer - -The official zkSync Era [block explorer](https://explorer.zksync.io/) provides insight to activities on-chain, contract -verification, and debugging assistance: - -- Search by address, transaction hash, batch, or token -- View, verify, and interact with smart contract source code. -- View detailed transaction information -- View status of transactions - -### Etherscan - zkSync Era Explorer - -Etherscan allows you to explore and search the zkSync Era network for transactions, addresses, tokens, prices and other -activities taking place on the Network. - -- [Etherscan Mainnet](https://era.zksync.network/) -- [Etherscan Testnet](https://sepolia-era.zksync.network/) - -### L2Scan - -L2Scan is the open source block explorer for zkSync by the Unifra team - -- [L2Scan Mainnet](https://zksync-era.l2scan.co/) -- [L2Scan Testnet](https://zksync-era-sepolia.l2scan.co/) - -### Blockscout - -Blockscout is a blockchain explorer for inspecting, analyzing, and interacting with zkSync. - -- [Blockscout Mainnet](https://zksync.blockscout.com/) -- [Blockscout Testnet](https://zksync-sepolia.blockscout.com/) - -### Hyperscan - -Routescan's zkSync Explorer allows you to explore and search for transactions, addresses, tokens, prices and other -activities taking place on zkSync. - -- [Hyperscan](https://hyperscan.xyz/) - -### zkScan Lite - -[zkScan](https://zkscan.io/) Block Explorer and Analytics Platform for zkSync Lite. - -### OKLink - -[OKLink](https://www.oklink.com/zksync) provides a familiar UI with data on transactions, blocks, account balances and -more. - -### Unifra - -[Unifra](https://zksync-era.unifra.xyz/) provides tools to help you debug smart contracts and transactions: - -- View, verify, and interact with smart contract source code. -- View detailed transaction information. - -### NFTScan - -Find the NFTScan [here](https://zksync.nftscan.com/). diff --git a/content/20.build/tooling/block-explorer/contract-verification.md b/content/20.build/tooling/block-explorer/contract-verification.md deleted file mode 100644 index cb4d1f60..00000000 --- a/content/20.build/tooling/block-explorer/contract-verification.md +++ /dev/null @@ -1,77 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Block Explorer Contract Verification | zkSync Docs ---- - -# Contract verification - -## User interface - -1. Click [**Smart Contract Verification**](https://sepolia.explorer.zksync.io/contracts/verify) in the block explorer - menu to go to the Smart Contract Verification page. - -![zkSync Era smart contract verification page](../../../assets/images/smart-contract-verification.png) - -2. Supply the contract details. - -![Contract details page](../../../assets/images/contract-details.png) - -- **Contract Address**: Enter the `0x` address generated at deployment time. -- **Compiler type**: Select Solidity or Vyper single or multi-part file from the dropdown menu. -- **Zksolc Version (in case Solidity is selected as Compiler type)**: Select the zkSync Era compiler version for - Solidity used in your code from the dropdown menu. -- **Solc Version (in case Solidity is selected as Compiler type)**: Specify the Solidity compiler version used in your - code from the dropdown menu. -- **Zkvyper Version (in case Vyper is selected as Compiler type)**: Select the zkSync Era compiler version for Vyper - used in your code from the dropdown menu. -- **Vyper Version (in case Vyper is selected as Compiler type)**: Specify the Vyper compiler version used in your code - from the dropdown menu. -- **Optimization**: Select **Yes** if you enabled optimization during contract compilation, otherwise **No**. -- **Contract Name**: Enter the exact name of your contract without the `.sol` postfix. -- **Contract Path (in case Solidity (Single file) is selected as Compiler type)**: Enter the path to the `.sol` contract - file in the required format. -- **Enter the Solidity Contract Code (in case Solidity (Single file) is selected as Compiler type)**: Copy/paste your - Solidity contract code into this text box. -- **Enter the Vyper Contract Code (in case Vyper (Single file) is selected as Compiler type)**: Copy/paste your Vyper - contract code into this text box. - - :::tip Contract code flattening If your Solidity code uses a library or inherits dependencies from another contract, - you may need to flatten it. Use a tool such as: - - - [Hardhat flatten](https://medium.com/coinmonks/flattening-smart-contracts-using-hardhat-dffe7dbc7b3f) - - [Truffle flattener](https://github.com/NomicFoundation/truffle-flattener) - - [POA Solidity flattener](https://github.com/poanetwork/solidity-flattener) ::: - -- **Constructor Arguments**: Enter the `0x` constructor argument returned at deployment time, or whatever was hardcoded - in the deployment script. - -3. Click **Verify Smart Contract** to run the verification process. - -During verification, the smart contract's bytecode and Solidity source code are compared. The algorithm compiles the -source code and checks if the generated bytecode matches the deployed bytecode. - -4. Success - -If the bytecode and source code match, the smart contract is verified. - -![Smart Contract Verified!](../../../assets/images/contract-verified.png 'Contract Verified') - -If any input information is incorrect, the verification process fails. - -## Hardhat plugin - -You can also verify your smart contract using the [Hardhat plugin](../hardhat/hardhat-zksync-verify.md). - -## Constructor arguments - -You can output the constructor argument data at deploy time by adding the following code to your deployment script. - -```js -const your_constructor_argument = 'Hi there!'; -const myContract = await deployer.deploy(artifact, [your_constructor_argument]); - -//obtain the Constructor Arguments -console.log('constructor args:' + myContract.interface.encodeDeploy([your_constructor_argument])); -``` diff --git a/content/20.build/tooling/block-explorer/getting-started.md b/content/20.build/tooling/block-explorer/getting-started.md deleted file mode 100644 index b39efa13..00000000 --- a/content/20.build/tooling/block-explorer/getting-started.md +++ /dev/null @@ -1,78 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Block Explorer | zkSync Docs ---- - -# Block Explorer - -The [zkSync Era Block Explorer user interface](https://explorer.zksync.io/) details comprehensive data about -transactions, blocks, batches, wallets, tokens, and smart contracts on the zkSync Era network. - -Toggle between testnet and mainnet data with the top-right dropdown menu. - -![zkSync Era Block Explorer](../../../assets/images/block-explorer-front-ui.png) - -## Block Explorer API - -We’ve developed the [zkSync Era Block Explorer API](https://block-explorer-api.mainnet.zksync.io/docs) for developers to -access [zkSync Era Block Explorer](https://explorer.zksync.io/) data directly via HTTP requests. - -The [API](https://block-explorer-api.mainnet.zksync.io/docs) provides various endpoints for many use cases you might -want in your app. It is compatible with [Etherscan API](https://docs.etherscan.io/), which makes it easy to transition -your existing apps to zkSync Era network. - -The following modules are supported: - -- [Contract](https://block-explorer-api.mainnet.zksync.io/docs#/Contract%20API) -- [Account](https://block-explorer-api.mainnet.zksync.io/docs#/Account%20API) -- [Transaction](https://block-explorer-api.mainnet.zksync.io/docs#/Transaction%20API) -- [Logs](https://block-explorer-api.mainnet.zksync.io/docs#/Logs%20API) -- [Block](https://block-explorer-api.mainnet.zksync.io/docs#/Block%20API) - -Check out the API documentation [API docs on Mainnet](https://block-explorer-api.mainnet.zksync.io/docs) | -[API docs on Testnet](https://block-explorer-api.testnets.zksync.dev/docs) - -:::note Note - -The [API](https://block-explorer-api.mainnet.zksync.io/docs) does not fully cover all the functionality yet. ::: - -We are working on additional endpoints to cover more use cases and to make developers’ experience better. Stay tuned for -further updates. - -Feel free to contribute and create issues and feature requests in -[zkSync Era Block Explorer GitHub repo](https://github.com/matter-labs/block-explorer). - -## Block explorer menu - -The [block explorer menu](./block-explorer-menu.md) has options for viewing data on blocks, batches, transactions, and -supported tokens. - -![zkSync Era block explorer menu](../../../assets/images/block-explorer-menu.png) - -## Smart contract verification - -The tools menu has options for [verifying your smart contract deployments](./contract-verification.md). - -![zkSync Era tools menu](../../../assets/images/tools-menu.png) - -:::warning Warning - -- Currently there are some issues with the UI contract verification tool. ::: - -## Search bar - -![zkSync Era search bar](../../../assets/images/search-bar.png) - -Use the search bar on all pages to access data by: - -- **Address**: The address of an EOA (externally owned account). -- **Batch index**: The index of a batch submitted to L1. -- **Contract address**: The callable address of a smart contract deployed on zkSync Era. -- **Transaction hash**: The unique 66 character identifier of an executed transaction. - -## Block Explorer API - -The [zkSync Era Block Explorer API](https://block-explorer-api.mainnet.zksync.io/docs) is available for developers to -access data directly via HTTP requests. Learn more [here](./block-explorer-api.md). diff --git a/content/20.build/tooling/bridges.md b/content/20.build/tooling/bridges.md deleted file mode 100644 index c5a9dd4a..00000000 --- a/content/20.build/tooling/bridges.md +++ /dev/null @@ -1,35 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Bridges | zkSync Docs ---- - -# Bridges - -Bridges are pivotal in enhancing interoperability between different networks or layers, facilitating seamless asset and -data transfer. In this section, we delve into various bridge solutions integrated within the zkSync ecosystem, providing -developers and users with diverse options for cross-chain or cross-layer interactions. - -:::info For an extended list of bridging options within the zkSync ecosystem, feel free to explore the -[bridges](https://zksync.dappradar.com/ecosystem?category-de=bridges) category on Dappradar. ::: - -### **zkSync Portal Bridge** - -The [Portal Bridge](https://bridge.zksync.io/) on zkSync provides a gateway for assets between Ethereum and the zkSync -network, ensuring secure and efficient transfers. - -### **Omnibtc Finance** - -[Omnibtc Finance](https://www.omnibtc.finance/) operates as a decentralized platform offering cross-chain swap, lending, -and borrowing services. Its primary objective is to integrate and harmonize on-chain liquidity across various networks. - -### **Orbiter Finance** - -[Orbiter Finance](https://www.orbiter.finance/?source=Ethereum&dest=zkSync%20Era&token=ETH) is a cross-chain rollup -protocol designed to enable safe, economical, and swift transfer of messages or assets across different networks. - -### **Owlto Finance** - -[Owlto Finance](https://owlto.finance/) is focused on creating a decentralized cross-rollup bridge, emphasizing layer 2 -solutions to promote scalability and interoperability. diff --git a/content/20.build/tooling/compiler-overview.md b/content/20.build/tooling/compiler-overview.md deleted file mode 100644 index 013ef2b3..00000000 --- a/content/20.build/tooling/compiler-overview.md +++ /dev/null @@ -1,93 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Compiler Overview | zkSync Docs ---- - -# Overview - -This section introduces the zkEVM LLVM-based compiler toolchain for smart contract languages with Ethereum Virtual -Machine (EVM) support. The toolchain works on top of existing compilers and requires their output, which typically -includes intermediate representations (IRs), abstract syntax trees (ASTs), and auxiliary contract metadata and -documentation. - -::: info At the time of writing, we support Solidity and Vyper. ::: - -The toolchain consists of the following: - -1. [High-level source code compilers](#high-level-source-code-compilers): `solc` and `vyper`. -2. [IR compilers, front ends to LLVM](#ir-compilers): `zksolc` and `zkvyper`. -3. [The LLVM framework](../../zk-stack/components/compiler/toolchain/llvm.md) with a zkEVM back end which emits zkEVM - text assembly. -4. [The assembler](#assembler) which produces the zkEVM bytecode from text assembly. -5. [Hardhat plugins](#hardhat-plugins) which set up the environment. - -![Compiler Toolchain Visualization](../../assets/images/compiler-toolchain.png 'Compiler Toolchain') - -## High-level Source Code Compilers - -High-level source code is processed by third-party compilers. These compilers do the following: - -1. Process and validate the high-level source code. -2. Translate the source code into IR and metadata. -3. Pass the IR and metadata to our IR compilers via the standard I/O streams. - -We are using two high-level source code compilers at the time of writing: - -- [solc](https://github.com/ethereum/solc-bin): the official Solidity compiler. For more info, see the latest - [Solidity documentation](https://docs.soliditylang.org/en/latest/). -- [vyper](https://github.com/vyperlang/vyper/releases): the official Vyper compiler. For more info, see the latest - [Vyper documentation](https://docs.vyperlang.org/en/latest/index.html). - -::: info Security and best practices Follow the -[security considerations and best practices](../../build/quick-start/best-practices.md) to build smart contracts on -zkSync Era. ::: - -## IR Compilers - -Our toolchain includes LLVM front ends, written in Rust, that process the output of high-level source code compilers: - -- [zksolc](https://github.com/matter-labs/zksolc-bin) which calls `solc` as a child process. For more info, see the - latest [zksolc documentation](../../zk-stack/components/compiler/toolchain/solidity.md). -- [zkvyper](https://github.com/matter-labs/zkvyper-bin): which calls `vyper` as a child process. For more info, see the - latest [zkvyper documentation](../../zk-stack/components/compiler/toolchain/vyper.md). - -These IR compilers perform the following steps: - -1. Receive the input, which is usually standard or combined JSON passed by the Hardhat plugin via standard input. -2. Save the relevant data, modify the input with zkEVM settings, and pass it to the underlying high-level source code - compiler which is called as a child process. -3. Receive the IR and metadata from the underlying compiler. -4. Translate the IR into LLVM IR, resolving dependencies with the help of metadata. -5. Optimize the LLVM IR with the powerful LLVM framework optimizer and emit zkEVM text assembly. -6. Print the output matching the format of the input method the IR compiler is called with. - -Our IR compilers leverage I/O mechanisms which already exist in the high-level source code compilers. They may modify -the input and output to some extent, add data for features unique to zkEVM, and remove unsupported feature artifacts. - -## Assembler - -The [assembler](https://github.com/matter-labs/era-zkevm-assembly), which is written in Rust, compiles zkEVM assembly to -zkEVM bytecode. This tool is not a part of our LLVM back end as it uses several cryptographic libraries which are easier -to maintain outside of the framework. - -## Hardhat Plugins - -We recommend using our IR compilers via [their corresponding Hardhat plugins](../tooling/hardhat/getting-started.md). -Add these plugins to the Hardhat's config file to compile new projects or migrate existing ones to zkSync Era. For a -lower-level approach, download our compiler binaries via the links above and use their CLI interfaces. - -### Installing and configuring plugins - -Add the plugins below to the Hardhat's config file to compile new projects or migrate existing ones to zkSync Era. For a -lower-level approach, download our compiler binaries [links above](#ir-compilers) and use their CLI interfaces. - -- [hardhat-zksync-solc documentation](../tooling/hardhat/hardhat-zksync-solc.md) -- [hardhat-zksync-vyper documentation](../tooling/hardhat/hardhat-zksync-vyper.md) - -::: warning - -- Using compilers running in Docker images is no longer supported. -- Instead, use the `compilerSource: "binary"` in the Hardhat config file to use the compiler binary. -- To compile with binaries, use `zksolc .sol --bin`. ::: diff --git a/content/20.build/tooling/cross-chain.md b/content/20.build/tooling/cross-chain.md deleted file mode 100644 index b179be66..00000000 --- a/content/20.build/tooling/cross-chain.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Cross Chain | zkSync Docs ---- - -# Cross Chain - -### LayerZero - -[LayerZero](https://layerzero.network) is an interoperability protocol that connects blockchains (50+ and counting), -allowing developers to build seamless omnichain applications, tokens, and experiences. The protocol relies on immutable -on-chain endpoints, a configurable Security Stack, and a permissionless set of Executors to transfer -censorship-resistant messages between chains. - -[Usage Guide](../tutorials/tooling-guides/layerzero.md) diff --git a/content/20.build/tooling/data-indexers.md b/content/20.build/tooling/data-indexers.md deleted file mode 100644 index 6e24d964..00000000 --- a/content/20.build/tooling/data-indexers.md +++ /dev/null @@ -1,48 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Data Indexers | zkSync Docs ---- - -# Data Indexers - -### Overview - -Welcome to the Analytics page, a comprehensive hub dedicated to interacting with data services, analytic tooling on -zkSync Era. Each guide includes hands-on examples, ensuring that both newcomers and experienced developers can -seamlessly harness the power of the analytical tooling within the zkSync Era. - -### The Graph Network - -[The Graph](https://thegraph.com/) is a decentralized protocol for indexing and querying blockchain data. The Graph -makes it possible to query data that is difficult to query directly. Use The Graph network today to index protocol data -on zkSync! - -### SubQuery Network - -[SubQuery](https://subquery.network/) is a fast, flexible, and reliable open-source data indexer that provides you with -custom APIs for your web3 project across all of our supported chains. - -### Covalent - -[Covalent](https://www.covalenthq.com/docs/networks/zksync-era/) provides the industry-leading Unified API bringing -visibility to billions of Web3 data points. Developers use Covalent to build exciting multi-chain applications like -crypto wallets, NFT galleries, and investor dashboard tools utilizing data. - -### Flair - -[Flair](https://docs.flair.dev/) offers reusable **indexing primitives** (such as fault-tolerant RPC ingestors, custom -processors, re-org aware database integrations) to make it easy to receive, transform, store and access your on-chain -data. - -### Usage guides - -- [the-graph](../tutorials/tooling-guides/the-graph.md) -- [subquery](../tutorials/tooling-guides/subquery.md) - -### **Contribute** - -The world of decentralized analytics is expansive, and there's always room for fresh perspectives. If you have carved -your path through the data forest and gleaned invaluable insights or have fresh tutorials to share, we wholeheartedly -welcome your contributions. Enlighten the community with your analytical prowess. diff --git a/content/20.build/tooling/foundry/getting-started.md b/content/20.build/tooling/foundry/getting-started.md deleted file mode 100644 index 0ba60ba9..00000000 --- a/content/20.build/tooling/foundry/getting-started.md +++ /dev/null @@ -1,347 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Foundry | Getting Started ---- - -## Getting Started - -### Prerequisites - -The primary prerequisite for using `foundry-zksync` is the [Rust Compiler](https://www.rust-lang.org/tools/install). - -### Installation - -`foundry-zksync` components can be installed individually or as a suite: - -- **zkForge**: Run `cargo install --path ./crates/zkforge --profile local --force --locked`. -- **zkCast**: Execute `cargo install --path ./crates/zkcast --profile local --force --locked`. -- **Entire Suite**: Use `cargo build --release` for a complete installation. - -## Configuration - -### Initial Setup - -After installation, initialize a new project with `zkforge init `, which sets up the basic structure of a -new Foundry project. - -### Project Configuration using `foundry.toml` - -Foundry is designed to be very configurable. You can configure Foundry using a file called `foundry.toml` in the root of -your project, or any other parent directory. - -Configuration can be arbitrarily namespaced by profiles. The default profile is named `default`. - -You can select another profile using the `FOUNDRY_PROFILE` environment variable. You can also override parts of your -configuration using `FOUNDRY_` or `DAPP_` prefixed environment variables, like `FOUNDRY_SRC`. - -`zkforge init` creates a basic, extendable `foundry.toml` file. - -To see your current configuration, run `zkforge config`. To see only basic options (as set with `zkforge init`), run -`zkforge config --basic`. This can be used to create a new `foundry.toml` file with -`zkforge config --basic > foundry.toml`. - -By default `zkforge config` shows the currently selected foundry profile and its values. It also accepts the same -arguments as `zkforge build`. An example `foundry.toml` for zkSync with zksolc configurations may look like: - -``` -[profile.default] -src = 'src' -out = 'out' -libs = ['lib'] - -[profile.zksync] -src = 'src' -libs = ['lib'] -fallback_oz = true -is_system = true -mode = "3" -``` - -## Basic Usage - -### Running Tests - -Use `zkforge test` to run tests written for your smart contracts. For an overview of how to write tests using -`Foundry-zksync` please refer to Foundry testing [here](../../test-and-debug/foundry.md). - -## Deploying Smart Contracts with `zkforge` - -### Compilation with `zkforge zk-build` - -`zkforge zkbuild` (also accessible via aliases like `zkforge zk-build`, `zkforge zk-compile`, `zkforge zkb`) is used for -compiling smart contracts into zkEVM bytecode. The compiled files are stored in a structured directory at -`/zkout/`. - -**Usage:** - -```sh -zkforge zkbuild [OPTIONS] -``` - -**Key Compiler Options:** - -- `--use-zksolc `: Specify the zksolc version or a local zksolc path. -- `--is-system `: Enables system contract compilation mode (`true`/`false`). -- `--force-evmla `: Switch to the EVM legacy assembly pipeline. -- `--fallback-oz `: Recompile with `-Oz` if bytecode is too large. -- `--detect-missing-libraries`: Detect and report missing libraries. -- `-O, --optimization `: Set LLVM optimization levels. -- `--zk-optimizer`: Optimize specifically for zkSync. - -**Example Usage:** Compile with default settings or specify `zksolc` version: - -```sh -zkforge zkbuild - -# specifying zksolc version -zkforge zkbuild --use-zksolc v1.3.19 -``` - -### Deployment with `zkforge zk-create` - -`zkforge zkcreate` (and its aliases `zkforge zk-create`, `zkforge zk-deploy`, `zkforge zkc`) deploys smart contracts to -zkSync. - -**Usage:** - -```sh -zkforge zkcreate [OPTIONS] --rpc-url --chain --private-key -``` - -**Options:** - -- `--constructor-args `: Specify constructor arguments. -- `--constructor-args-path `: File path for constructor arguments. -- ``: Contract identifier in `:` format. -- `--factory-deps `: Specify factory dependencies. - -**Example:** Deploy `Greeter.sol` to zkSync Sepolia testnet: - -
-Click to view the `Greeter.sol` contract - -```solidity -//SPDX-License-Identifier: Unlicense -pragma solidity ^0.8.0; - -contract Greeter { - string private greeting; - - constructor(string memory _greeting) { - greeting = _greeting; - } - - function greet() public view returns (string memory) { - return greeting; - } - - function setGreeting(string memory _greeting) public { - greeting = _greeting; - } -} -``` - -
- -```bash -zkforge zkcreate src/Greeter.sol:Greeter --constructor-args "Hello zkSync" --private-key --rpc-url https://sepolia.era.zksync.dev --chain 300 -``` - -### Deploying Factory Contracts - -To deploy contracts like `GreeterFactory.sol`, use the `is-system` flag. - -
-Click to view the `GreeterFactory.sol` contract - -```solidity -// SPDX-License-Identifier: Unlicense -pragma solidity ^0.8.0; - -import "./Greeter.sol"; - -contract Factory { - Greeter[] public GreeterArray; - - function CreateNewGreeter(string memory _greeting) public { - Greeter greeter = new Greeter(_greeting); - GreeterArray.push(greeter); - } - - function gfSetter(uint256 _greeterIndex, string memory _greeting) public { - Greeter(address(GreeterArray[_greeterIndex])).setGreeting(_greeting); - } - - function gfGetter(uint256 _greeterIndex) public view returns (string memory) { - return Greeter(address(GreeterArray[_greeterIndex])).greet(); - } -} -``` - -
- -**Compile `GreeterFactory.sol`:** - -```bash -zkforge zkbuild --is-system=true -``` - -**Deploy `GreeterFactory.sol`:** - -```sh -zkforge zkcreate src/GreeterFactory.sol:Factory --factory-deps src/Greeter.sol:Greeter --private-key --rpc-url https://sepolia.era.zksync.dev --chain 300 -``` - -**Deploy `Greeter.sol` via `GreeterFactory.sol`:** - -```sh -zkcast zk-send "CreateNewGreeter(string)" "zkSync Rules" --private-key --rpc-url https://sepolia.era.zksync.dev --chain 300 -``` - -**Interact with `Greeter.sol`** - -```sh -zkcast call "greet()(string)" --rpc-url https://sepolia.era.zksync.dev --chain 300 -``` - -**Output:** - -``` -0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000c7a6b53796e632052756c65730000000000000000000000000000000000000000 -``` - -**To decode the output to a readable string:** - -```sh -zkcast to-ascii 0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000c7a6b53796e632052756c65730000000000000000000000000000000000000000 -``` - -**Output:** - -``` -zkSync Rules -``` - -## Basic zkSync Chain Interactions with `zkcast` - -### Introduction - -This guide introduces you to fundamental interactions within the zkSync chain using `zkcast`, a component of the -`foundry-zksync` toolkit. Learn how to query chain IDs, retrieve client versions, check L2 ETH balances, obtain gas -prices, and more. - -### Chain ID Retrieval - -- **Local Node:** - - Retrieve the Chain ID for a local zkSync node with: - - ```sh - zkcast chain-id --rpc-url http://localhost:3050 - ``` - - Expected Output: `270`, indicating the Chain ID of your local zkSync node. - -- **zkSync Sepolia Testnet:** - - For the zkSync Sepolia Testnet, use: - - ```sh - zkcast chain-id --rpc-url https://sepolia.era.zksync.dev - ``` - - Expected Output: `300`, the Chain ID for the zkSync Sepolia Testnet. - -### Client Version Information - -Knowing the client version is vital for compatibility checks and debugging: - -```sh -zkcast client --rpc-url https://sepolia.era.zksync.dev -``` - -Expected Output: `zkSync/v2.0`, denoting the client version. - -### L2 Balance Check - -Verify the Layer 2 (L2) balance of an account: - -```sh -zkcast balance 0x8b1d48a69ACEbC6eb201e2F4d162A002203Bfe8E --rpc-url https://sepolia.era.zksync.dev -``` - -Expected Output: A numerical value, e.g., `774909739323110932`, representing the account's L2 balance. - -### Current Gas Price - -Fetch the current gas price on the network for transaction cost estimations: - -```sh -zkcast gas-price --rpc-url https://sepolia.era.zksync.dev -``` - -Expected Output: A value such as `100000000`, indicating the current gas price. - -### Latest Block Details - -Gain insights into the latest block on the zkSync chain: - -```sh -zkcast block latest --rpc-url https://sepolia.era.zksync.dev -``` - -Expected Output: Detailed information about the latest block, including base fee per gas, gas limit, block hash, and -more. - -### Sending Transactions - -Initiate transactions, such as contract function calls, using `zkcast`: - -```sh -zkcast zk-send --rpc-url --private-key --chain -``` - -Example: - -```sh -zkcast zk-send 0x97b985951fd3e0c1d996421cc783d46c12d00082 "setGreeting(string)" "Hello, zkSync!" --rpc-url http://localhost:3050 --private-key --chain 270 -``` - -This command calls the `setGreeting` function of a contract, updating the greeting to "Hello, zkSync!". Replace -`` with your actual private key. - -### Bridging Assets Between L1 and L2 - -#### L1 to L2 Deposits - -Deposit assets from Layer 1 (Ethereum) to Layer 2 (zkSync): - -```sh -zkcast zk-deposit --l1-rpc-url --l2-url --chain --private-key -``` - -Note: For ETH deposits, leave the `` parameter empty. - -Example (Depositing ETH): - -```sh -zkcast zk-deposit 0x36615Cf349d7F6344891B1e7CA7C72883F5dc049 1 ether --l1-rpc-url http://localhost:8545 --l2-url http://localhost:3050 --private-key --chain 270 -``` - -#### L2 to L1 Withdrawals - -Withdraw assets from Layer 2 back to Layer 1: - -```sh -zkcast zk-send --withdraw --amount --rpc-url --private-key --chain -``` - -Example (Withdrawing ETH): - -```sh -zkcast zk-send --withdraw 0x36615Cf349d7F6344891B1e7CA7C728 - -83F5dc049 --amount 1 ether --rpc-url http://localhost:3050 --private-key --chain 270 -``` diff --git a/content/20.build/tooling/foundry/overview.md b/content/20.build/tooling/foundry/overview.md deleted file mode 100644 index 855973cf..00000000 --- a/content/20.build/tooling/foundry/overview.md +++ /dev/null @@ -1,60 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Foundry | zkSync Docs ---- - -# Foundry with zkSync - -## Overview - -`foundry-zksync` is a specialized fork of [Foundry](https://github.com/foundry-rs/foundry), tailored for zkSync. It -extends Foundry's capabilities for Ethereum app development to support zkSync, allowing for the compilation, deployment, -testing, and interaction with smart contracts on zkSync. `foundry-zksync` introduces `zkforge` and `zkcast` extensions -of Foundry's existing `forge` and `cast` tools but tailored for zkSync usage. - -### Status and Contribution - -`foundry-zksync` is currently in its **alpha stage**, indicating ongoing development and potential for future -enhancements. It is open-sourced, and contributions from the developer community are welcome. For more details and -contributions, visit the [GitHub repository](https://github.com/matter-labs/foundry-zksync). - -### Features and Limitations - -### Features - -`Foundry-zksync` offers a set of features designed to work with zkSync, providing a comprehensive toolkit for smart -contract deployment and interaction: - -- **Smart Contract Deployment**: Easily deploy smart contracts to zkSync mainnet, testnet, or a local test node. -- **Asset Bridging**: Bridge assets between L1 and L2, facilitating seamless transactions across layers. -- **Contract Interaction**: Call and send transactions to deployed contracts on zkSync testnet or local test node. -- **Solidity Testing**: Write tests in Solidity for a familiar testing environment. -- **Fuzz Testing**: Benefit from fuzz testing, complete with shrinking of inputs and printing of counter-examples. -- **Remote RPC Forking**: Utilize remote RPC forking mode. -- **Flexible Debug Logging**: Choose your debugging style: - - DappTools-style: Utilize DsTest's emitted logs for debugging. - - Hardhat-style: Leverage the popular console.sol contract. -- **Configurable Compiler Options**: Tailor compiler settings to your needs, including LLVM optimization modes. - -### Limitations - -While `foundry-zksync` is **alpha stage**, there are some limitations to be aware of, but not limited to: - -- **Cheat Codes Support**: Not all cheat codes are fully supported. - [View the list of supported cheat codes](https://github.com/matter-labs/foundry-zksync/blob/main/SUPPORTED_CHEATCODES.md). -- **Compile Time**: Some users may experience slow compiling. -- **Specific Foundry Features**: Currently features such as `coverage`, `--gas-report` or `--verify` may not work as - intended. We are actively working on providing support for these feature types. -- **Compiling Libraries**: Compiling non-inlinable libraries requires deployment and adding to configuration. For more - information please refer to [official docs](https://era.zksync.io/docs/tools/hardhat/compiling-libraries.html). - - ``` - # In foundry.toml - libraries = [ - "src/MyLibrary.sol:MyLibrary:0xfD88CeE74f7D78697775aBDAE53f9Da1559728E4" - ] - ``` - -::: info We are actively working to resolve limitations listed. Please check back on future releases for updates. ::: diff --git a/content/20.build/tooling/hardhat/compiling-libraries.md b/content/20.build/tooling/hardhat/compiling-libraries.md deleted file mode 100644 index 3c0ff0b6..00000000 --- a/content/20.build/tooling/hardhat/compiling-libraries.md +++ /dev/null @@ -1,176 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Compiling non-inlinable Libraries | zkSync Docs ---- - -# Compiling non-inlinable libraries - -Solidity libraries can be divided into two categories: - -- _Inlinable_. The ones that contain only `private` or `internal` methods. Since they can never be called from outside, - the Solidity compiler inlines them, i.e. does not use external calls to access the library methods and uses the code - of these libraries as part of the code that uses them. -- _Non-inlinable_. The ones that have at least one `public` or `external` method. While they may be inlined by the - Solidity compiler, they are not inlined when compiled to Yul representation. Since Yul is an intermediate step when - compiling to zkEVM bytecode, this means that these libraries can not be inlined by the zkSync compiler. - -**Practically this means that libraries with public methods need to be deployed separately and their addresses passed as -an argument when compiling the main contract.** Usage of the methods of this library will be replaced with calls to its -address. - -## OpenZeppelin utility libraries - -Please note, that the total majority of the OpenZeppelin utility libraries _are_ inlinable. That means that _there is no -need to do any further actions to make them compile_. - -This section describes the compilation of non-inlinable libraries only. - -## Example - -Let's say that we have a small library that calculates the square of a number: - -```solidity -pragma solidity ^0.8.0; - -library MiniMath { - function square(uint256 x) public pure returns (uint256) { - return x*x; - } -} -``` - -And there is a smart contract that uses this library - -```solidity -pragma solidity ^0.8.0; - -import "./MiniMath.sol"; - -contract Main { - uint256 public lastNumber; - - function storeSquare(uint256 x) public { - uint256 square = MiniMath.square(x); - lastNumber = square; - } -} -``` - -::: info Support for missing libraries in hardhat-zksync-solc ^0.4.2 - -Version 0.4.2 introduced a mode that detects non-inlinable libraries that are missing and that are required for the -compilation of contracts. - -::: - -If you try to create a project with these two files following the guidelines from the -[getting started](./getting-started.md) guide, the `yarn hardhat compile` command will fail. - -#### Using hardhat-zksync-solc version >= 0.4.2 - -Following error: - -``` -zksolc compiler detected missing libraries! For more details, visit: https://era.zksync.io/docs/tools/hardhat/compiling-libraries.html. -To compile and deploy libraries, please run: `yarn hardhat deploy-zksync:libraries --private-key ` -For more details on how to use deploy-zksync:libraries task from hardhat-zksync-deploy plugin, visit: https://era.zksync.io/docs/tools/hardhat/hardhat-zksync-deploy.html. -``` - -To address the error, you can follow the instructions provided in the output, which is the recommended approach. For -more details, please refer to [this section](#automatic-deployment). Alternatively, if you prefer a manual resolution -for the libraries, you can find detailed instructions in [this section](#manual-deployment). - -Choose the method that best suits your preferences or requirements. - -#### Using hardhat-zksync-solc version < 0.4.2 - -Following error: - -``` -Error in plugin @matterlabs/hardhat-zksync-solc: LLVM("Library `contracts/MiniMath.sol:MiniMath` not found") - -``` - -The error indicates that the compilation process is expecting the address of the MiniMath library, but it is not being -provided. - -To resolve the error, it's necessary to manually resolve the libraries. For detailed instructions, please refer to -[this section](#automatic-deployment). - -## Non-inline libraries deployment - -### Automatic deployment - -::: note This approach is effective only with specific plugin versions: - -- `hardhat-zksync-solc` >= 0.4.2 -- `hardhat-zksync-deploy` >= 0.6.5 - -Make sure that you are using the specified versions or a later versions to ensure compatibility with the described -resolution method. ::: - -::: note Vyper does not support automatic deployment of missing libraries, and the process needs to be handled manually. -::: - -`hardhat-zksync-deploy` plugin has the capability to automatically deploy all missing libraries generated by compiler. -For additional information, you may refer to the -[documentation](./hardhat-zksync-deploy.md/#compilation-and-deployment-support-for-missing-libraries). This -documentation provides details on how the tool handles the compilation and deployment of libraries that are currently -missing. - -### Manual deployment - -To resolve the issue, you need to create _a separate project_, where only the library file will be located. After -deploying _only_ the library to zkSync Era, you should get the address of the deployed library and pass it to the -compiler settings. The process of deploying the library is the same as deploying a smart contract. You can learn how to -deploy smart contracts on zkSync Era in the [getting started](./getting-started.md#compile-and-deploy-a-contract) guide. - -Let's say that the address of the deployed library is `0xF9702469Dfb84A9aC171E284F71615bd3D3f1EdC`. To pass this address -to the compiler parameters, open the `hardhat.config.ts` file of the project where the `Main` contract is located and -add the `libraries` section in the `zksolc` plugin properties: - -```typescript -import '@matterlabs/hardhat-zksync-deploy'; -import '@matterlabs/hardhat-zksync-solc'; - -module.exports = { - zksolc: { - version: 'latest', // Uses latest available in https://github.com/matter-labs/zksolc-bin/ - settings: { - libraries: { - 'contracts/MiniMath.sol': { - MiniMath: '0xF9702469Dfb84A9aC171E284F71615bd3D3f1EdC', - }, - }, - }, - }, - defaultNetwork: 'zkTestnet', - networks: { - zkTestnet: { - url: 'https://sepolia.era.zksync.dev', // URL of the zkSync network RPC - ethNetwork: 'sepolia', // Can also be the RPC URL of the Ethereum network (e.g. `https://sepolia.infura.io/v3/`) - zksync: true, - }, - }, - solidity: { - version: '0.8.13', - }, -}; -``` - -The address of the library is passed in the following lines: - -```typescript -libraries: { - 'contracts/MiniMath.sol': { - 'MiniMath': '0xF9702469Dfb84A9aC171E284F71615bd3D3f1EdC' - } -}, -``` - -where `'contracts/MiniMath.sol'` is the location of the library's Solidity file and `MiniMath` is the name of the -library. - -Now, running `yarn hardhat compile` should successfully compile the `Main` contract. diff --git a/content/20.build/tooling/hardhat/getting-started.md b/content/20.build/tooling/hardhat/getting-started.md deleted file mode 100644 index f1d7bca2..00000000 --- a/content/20.build/tooling/hardhat/getting-started.md +++ /dev/null @@ -1,367 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Hardhat Getting Started | zkSync Docs ---- - -# Getting started - -::: warning Windows as platform If you are using Windows, we strongly recommend you use Windows Subsystem for Linux -(also known as WSL 2). You can use `Hardhat` and `Hardhat zkSync plugins` without it, but it will work better if you use -it. - -To install Node.js using WSL 2, please read this -[guide](https://learn.microsoft.com/en-us/windows/dev-environment/javascript/nodejs-on-wsl) ::: - -[Hardhat](https://hardhat.org) is an Ethereum development environment, designed for easy smart contract development in -Solidity. One of its most prominent features is extendability: you can easily add new plugins to your hardhat project. - -zkSync Era has the following official plugins for Hardhat: - -- [@matterlabs/hardhat-zksync-solc](./hardhat-zksync-solc.md) - used to compile contracts written in Solidity. -- [@matterlabs/hardhat-zksync-vyper](./hardhat-zksync-vyper.md) - used to compile contracts written in Vyper. -- [@matterlabs/hardhat-zksync-deploy](./hardhat-zksync-deploy.md) - used to deploy smart contracts. -- [@matterlabs/hardhat-zksync-chai-matchers](./hardhat-zksync-chai-matchers.md) - adds zkSync-specific capabilities to - the [Chai](https://www.chaijs.com/) assertion library for testing smart contracts. -- [@matterlabs/hardhat-zksync-verify](./hardhat-zksync-verify.md) - used to verify smart contracts. -- [@matterlabs/hardhat-zksync-verify-vyper](./hardhat-zksync-verify-vyper.md) - used to verify vyper smart contracts. -- [@matterlabs/hardhat-zksync-upgradable](./hardhat-zksync-upgradable.md) - used to deploy, update, and verify proxy - smart contracts. -- [@matterlabs/hardhat-zksync-ethers](./hardhat-zksync-ethers.md) - wrapper around zksync-ethers with some extra - Hardhat-specific functionality. -- [@matterlabs/hardhat-zksync-node](./hardhat-zksync-node.md) - used to run the zkSync era-test-node locally. - -::: tip Additional plugins Learn more about [other plugins from the community](./other-plugins.md) that you can use with -zkSync Era. ::: - -To learn more about Hardhat itself, check out [its official documentation](https://hardhat.org/getting-started/). - -This tutorial shows you how to Setup a zkSync Era Solidity project with Hardhat using the -[zkSync CLI](../zksync-cli/getting-started.md). - -If you are using Vyper, check out the [Vyper plugin documentation](./hardhat-zksync-vyper.md) or -[this example](https://github.com/matter-labs/hardhat-zksync/tree/main/examples/vyper-example) in GitHub! - -## Prerequisites - -- Make sure your machine satisfies the - [system requirements](https://github.com/matter-labs/era-compiler-solidity/tree/main#system-requirements). -- You have a Node installation and `yarn` or `npm` package manager. -- You are already familiar with deploying smart contracts on zkSync. If not, please refer to the first section of the -- A wallet with sufficient Sepolia or Göerli `ETH` on Ethereum and zkSync Era Testnet to pay for deploying smart - contracts. You can get Sepolia ETH from the [network faucets](../../tooling/network-faucets.md). - - Get testnet `ETH` for zkSync Era using [bridges](https://zksync.io/explore#bridges) to bridge funds to zkSync. -- You know how to get your - [private key from your MetaMask wallet](https://support.metamask.io/hc/en-us/articles/360015289632-How-to-export-an-account-s-private-key). - -::: tip Local zkSync Testing with zksync-cli Skip the hassle for test ETH by using `zksync-cli` for local testing. -Simply execute `npx zksync-cli dev start` to initialize a local zkSync development environment, which includes local -Ethereum and zkSync nodes. This method allows you to test contracts without requesting external testnet funds. Explore -more in the [zksync-cli documentation](../zksync-cli/getting-started.md). ::: - -::: warning Important - -- Contracts must be compiled using the - [official zkSync Era compilers](../../../zk-stack/components/compiler/toolchain/overview.md), with their respective - Hardhat plugins. -- Contracts compiled with other compilers will fail to deploy to zkSync Era. ::: - -## Project setup - -To create a new project run the CLI's `create` command, passing a project name: - -#### Solidity project - -```sh -npx zksync-cli create demo --template hardhat_solidity -``` - -#### Vyper project - -```sh -npx zksync-cli create demo --template hardhat_vyper -``` - -This command creates a `demo` folder and clones a Hardhat template project inside it. The downloaded project is already -configured and contains all the required plugins. - -::: tip Migrating a project If you want to migrate an existing project, please check the -[project migration guide](./migrating-to-zksync.md). ::: - -## Hardhat configuration - -The `hardhat.config.ts` file contains some zkSync-Era-specific configurations: - -The zkSync Era deployment and compiler plugin imports. - -###### Solidity project - -```typescript -import "@matterlabs/hardhat-zksync-deploy"; -import "@matterlabs/hardhat-zksync-solc"; -...... -``` - -The `zksolc` block contains the minimal configuration for the compiler. - -```typescript -zksolc: { - version: "latest", // Uses latest available in https://github.com/matter-labs/zksolc-bin/ - settings: {}, -}, -``` - -###### Vyper project - -```typescript -import "@nomiclabs/hardhat-vyper"; -import "@matterlabs/hardhat-zksync-deploy"; -import "@matterlabs/hardhat-zksync-vyper"; -...... -``` - -The `zkvyper` block contains the minimal configuration for the compiler. - -```typescript -zkvyper: { - version: "latest", // Uses latest available in https://github.com/matter-labs/zkvyper-bin/ - settings: {}, -}, -``` - -#### Network - -The network endpoints of the `zkSyncTestnet` network change dynamically for local tests. - -```typescript -// dynamically changes endpoints for local tests -const zkSyncTestnet = - process.env.NODE_ENV == 'test' - ? { - url: 'http://localhost:3050', - ethNetwork: 'http://localhost:8545', - zksync: true, - } - : { - url: 'https://sepolia.era.zksync.dev', - ethNetwork: 'sepolia', - zksync: true, - }; -``` - -::: info For local zkSync testing, modify `url` and `ethNetwork` in `hardhat.config.ts` to align with your local zkSync -and Ethereum node's L2 and L1 RPC URLs, respectively. ::: - -::: tip Unit tests This template project includes a basic unit test in the `/test` folder that runs with the local-setup -and can be executed with `yarn test`. Learn more about how to -[start the local setup and write unit tests here](../../test-and-debug/getting-started.md). ::: - -::: tip Advanced configuration To learn more about each specific property in the `hardhat.config.ts` file, check out the -[plugins documentation](../hardhat/getting-started.md) ::: - -## Set your Private Key - -Rename `.env.example` to `.env` and input your private key: - -```text -WALLET_PRIVATE_KEY=YourPrivateKeyHere... -``` - -Your private key will be used for paying the costs of deploying the smart contract. - -## Compile and deploy a contract - -Smart contracts belong in the `contracts` folder. - -#### 1. To compile the contract, run - -```sh -yarn hardhat compile -``` - -You'll see the following output: - -```text -Compiling 1 Solidity file -Successfully compiled 1 Solidity file -// Successfully compiled 1 Vyper file - Vyper project -✨ Done in 1.09s. -``` - -The `artifacts-zk` and `cache-zk` folders appear in the root directory (instead of the regular Hardhat's `artifacts` and -`cache`). These folders contain the compilation artifacts (including contract's ABIs) and compiler cache files. - -::: tip The `artifacts-zk` and `cache-zk` folders are included in the `.gitignore` file. - -::: - -The `deploy-greeter.ts` script is in the `deploy` folder. This script uses the `Deployer` class from the -`hardhat-zksync-deploy` package to deploy the `Greeter.sol`/`Greeter.vy` contract. - -```typescript -import { Wallet, utils } from 'zksync-ethers'; -import * as ethers from 'ethers'; -import { HardhatRuntimeEnvironment } from 'hardhat/types'; -import { Deployer } from '@matterlabs/hardhat-zksync-deploy'; - -// load env file -import dotenv from 'dotenv'; -dotenv.config(); - -// load wallet private key from env file -const PRIVATE_KEY = process.env.WALLET_PRIVATE_KEY || ''; - -if (!PRIVATE_KEY) throw '⛔️ Private key not detected! Add it to the .env file!'; - -// An example of a deploy script that will deploy and call a simple contract. -export default async function (hre: HardhatRuntimeEnvironment) { - console.log(`Running deploy script for the Greeter contract`); - - // Initialize the wallet. - const wallet = new Wallet(PRIVATE_KEY); - - // Create deployer object and load the artifact of the contract you want to deploy. - const deployer = new Deployer(hre, wallet); - const artifact = await deployer.loadArtifact('Greeter'); - - // Estimate contract deployment fee - const greeting = 'Hi there!'; - const deploymentFee = await deployer.estimateDeployFee(artifact, [greeting]); - - // ⚠️ OPTIONAL: You can skip this block if your account already has funds in L2 - // const depositHandle = await deployer.zkWallet.deposit({ - // to: deployer.zkWallet.address, - // token: utils.ETH_ADDRESS, - // amount: deploymentFee.mul(2), - // }); - // // Wait until the deposit is processed on zkSync - // await depositHandle.wait(); - - // Deploy this contract. The returned object will be of a `Contract` type, similar to ones in `ethers`. - // `greeting` is an argument for contract constructor. - const parsedFee = ethers.formatEther(deploymentFee); - console.log(`The deployment is estimated to cost ${parsedFee} ETH`); - - const greeterContract = await deployer.deploy(artifact, [greeting]); - - //obtain the Constructor Arguments - console.log('constructor args:' + greeterContract.interface.encodeDeploy([greeting])); - - // Show the contract info. - const contractAddress = await greeterContract.getAddress(); - console.log(`${artifact.contractName} was deployed to ${contractAddress}`); -} -``` - -#### 2. To execute the deployment script run - -```sh -yarn hardhat deploy-zksync --script deploy-greeter.ts -``` - -This script deploys the `Greeting` contract with the message "Hi there!" to zkSync Era Testnet. - -You should see something like this: - -```txt -Running deploy script for the Greeter contract -The deployment is estimated to cost 0.00579276320831943 ETH -constructor args:0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000094869207468657265210000000000000000000000000000000000000000000000 -Greeter was deployed to 0x46f1d2d8A16DBD8b47e9D61175a826ac667288Be4D1293a22E8 - -✨ Done in 12.69s. -``` - -**Congratulations! You have deployed a smart contract project to zkSync Era Testnet with Hardhat 🎉** - -::: warning Request-Rate Exceeded message - -- This message is caused by using the default RPC endpoints provided by ethers. -- To avoid this, use your own Sepolia RPC endpoint in the `hardhat.config.ts` file. -- Find multiple [node providers here](https://github.com/arddluma/awesome-list-rpc-nodes-providers). ::: - -## Interact with the contract - -The template project contains another script to interact with the contract. - -1. Enter the address of the deployed Greeter contract in the `CONTRACT_ADDRESS` variable of the `use-greeter.ts` script: - -```typescript -import { Provider } from 'zksync-ethers'; -import * as ethers from 'ethers'; -import { HardhatRuntimeEnvironment } from 'hardhat/types'; - -// load env file -import dotenv from 'dotenv'; -dotenv.config(); - -// load contract artifact. Make sure to compile first! - Solidity Project -import * as ContractArtifact from '../artifacts-zk/contracts/Greeter.sol/Greeter.json'; -// load contract artifact. Make sure to compile first! - Vyper Project -//import * as ContractArtifact from "../artifacts-zk/contracts/Greeter.vy/Greeter.json"; - -const PRIVATE_KEY = process.env.WALLET_PRIVATE_KEY || ''; - -if (!PRIVATE_KEY) throw '⛔️ Private key not detected! Add it to the .env file!'; - -// Address of the contract on zksync testnet -const CONTRACT_ADDRESS = ''; - -if (!CONTRACT_ADDRESS) throw '⛔️ Contract address not provided'; - -// An example of a deploy script that will deploy and call a simple contract. -export default async function (hre: HardhatRuntimeEnvironment) { - console.log(`Running script to interact with contract ${CONTRACT_ADDRESS}`); - - // Initialize the provider. - // @ts-ignore - const provider = new Provider(hre.userConfig.networks?.zkSyncTestnet?.url); - const signer = new ethers.Wallet(PRIVATE_KEY, provider); - - // Initialise contract instance - const contract = new ethers.Contract(CONTRACT_ADDRESS, ContractArtifact.abi, signer); - - // Read message from contract - console.log(`The message is ${await contract.greet()}`); - - // send transaction to update the message - const newMessage = 'Hello people!'; - const tx = await contract.setGreeting(newMessage); - - console.log(`Transaction to change the message is ${tx.hash}`); - await tx.wait(); - - // Read message after transaction - console.log(`The message now is ${await contract.greet()}`); -} -``` - -2. To execute the script, run: - -```sh -yarn hardhat deploy-zksync --script use-greeter.ts -``` - -The script will: - -- Retrieve the message from the contract by calling the `greet()` method. -- Update the greeting message in the contract with the `setGreeting()` method. -- Retrieve the message from the contract again. - -You should see something like this: - -```text -Running script to interact with contract Greeter -The message is Hello there! -Transaction to change the message is 0x12f16578A16DB0f47e9D61175a823ac214288Af -The message now is Hello people! - -✨ Done in 14.32s. -``` - -## Learn more - -- To learn more about the zkSync Hardhat plugins check out the [plugins documentation](../hardhat/getting-started.md). -- If you want to know more about how to interact with zkSync using Javascript, check out the - [zksync-ethers Javascript SDK documentation](../../sdks/js/zksync-ethers/getting-started.md) . diff --git a/content/20.build/tooling/hardhat/hardhat-zksync-chai-matchers.md b/content/20.build/tooling/hardhat/hardhat-zksync-chai-matchers.md deleted file mode 100644 index 106ab134..00000000 --- a/content/20.build/tooling/hardhat/hardhat-zksync-chai-matchers.md +++ /dev/null @@ -1,165 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: hardhat-zksync-chai-matchers | zkSync Docs ---- - -# `hardhat-zksync-chai-matchers` - -This plugin adds zkSync-specific capabilities to the [Chai](https://www.chaijs.com/) assertion library for testing smart -contracts. It extends all the functionalities supported by the -[hardhat-chai-matchers](https://hardhat.org/hardhat-chai-matchers/docs/overview) plugin, with the idea to preserve the -same behavior and interface. Currently, it is used in combination with -[local testing environment](../../test-and-debug/getting-started.md). - -[Changelog](https://github.com/matter-labs/hardhat-zksync/blob/main/packages/hardhat-zksync-chai-matchers/CHANGELOG.md) - -::: info - -- Since responses from transactions that revert are highly dependent on the RPC implementation, all - [Hardhat](https://hardhat.org/hardhat-chai-matchers/docs/overview) chai matchers that start with `revert` have been - affected (without any changes to the chai matchers interface). -- In addition, the `options` argument from `changeEtherBalance`/`changeEtherBalances` now includes the `overrides` field - in order to support `zksync-ethers` transfer methods with overrides. ::: - -::: warning Version Compatibility Warning Ensure you are using the correct version of the plugin with ethers: - -- For plugin version **<1.0.0**: - - - Compatible with ethers **v5**. - -- For plugin version **≥1.0.0**: - - Compatible with ethers **v6** (⭐ Recommended) - -Examples are adopted for plugin version **>=1.0.0** ::: - -## Installation - -Add the latest version of this plugin to your project with the following command: - -::: code-tabs - -@tab:active yarn - -```bash -yarn add -D @matterlabs/hardhat-zksync-chai-matchers @nomicfoundation/hardhat-chai-matchers chai @nomiclabs/hardhat-ethers ethers -``` - -@tab npm - -```bash -npm i -D @matterlabs/hardhat-zksync-chai-matchers -``` - -::: - -### Usage - -After installing it, add the plugin to your Hardhat config: - -```javascript -import '@matterlabs/hardhat-zksync-chai-matchers'; -``` - -Then you'll be able to use the matchers in your tests. - -#### changeEtherBalance - -Assert that the ether balance of an address changed by a specific amount: - -```javascript -await expect(() => - sender.transfer({ - to: receiver.address, - amount: 2000, - }) -).to.changeEtherBalance(sender.address, -2000); - -await expect(() => - sender.sendTransaction({ - to: receiver.address, - value: 1000, - }) -).to.changeEtherBalance(sender.address, '-1000'); -``` - -This matchers include additional options argument with functionalities for including fee and overriding transaction: - -```javascript -overrides = { - type: 2, - maxFeePerGas: 1 * gasPrice, - maxPriorityFeePerGas: 1 * gasPrice, -}; - -await expect(() => - sender.transfer({ - to: receiver.address, - amount: 500, - overrides, - }) -).to.changeEtherBalance(sender, -(txGasFees + 500), { - balanceChangeOptions: { - includeFee: true, - }, - overrides, -}); -``` - -#### changeTokenBalance - -Assert that an ERC20 token balance of an address changed by a specific amount: - -```javascript -await expect(sender.transfer({ to: receiver.address, amount: 5, token: token.address })).to.changeTokenBalance( - token, - sender, - -5 -); - -await expect(token.transfer(receiver.address, 5)).to.not.changeTokenBalance(token, sender, 0); -``` - -#### reverted - -Assert that a transaction reverted for any reason: - -```javascript -await expect(contract.setAmount(100)).to.be.reverted; -``` - -#### revertedWithCustomError - -Assert that a transaction reverted with a specific custom error: - -```javascript -await expect(contract.setAmount(100)).to.be.revertedWithCustomError(contract, 'InvalidAmount'); -``` - -
- -And you can also use regular chai matchers like: - -#### emit - -```javascript -await expect(contract.setAmount(100)).to.emit(contract, 'AmountUpdated'); -``` - -#### properAddress - -```javascript -expect('0x36615Cf349d7F6344891B1e7CA7C72883F5dc049').to.be.properAddress; -``` - -#### Comparisons of numbers - -```javascript -expect(await contract.getAmount()).to.equal(100); -``` - -Checkout the advantages of using chai matchers -[here](https://hardhat.org/hardhat-chai-matchers/docs/overview#why-would-i-want-to-use-it?). Since the list of all -supported chai matchers is same as with [hardhat-chai-matchers](https://hardhat.org/hardhat-chai-matchers/docs/overview) -plugin, check the [reference documentation](https://hardhat.org/hardhat-chai-matchers/docs/reference). diff --git a/content/20.build/tooling/hardhat/hardhat-zksync-deploy.md b/content/20.build/tooling/hardhat/hardhat-zksync-deploy.md deleted file mode 100644 index 09e99afc..00000000 --- a/content/20.build/tooling/hardhat/hardhat-zksync-deploy.md +++ /dev/null @@ -1,304 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: hardhat-zksync-deploy | zkSync Docs ---- - -# `hardhat-zksync-deploy` - -This plugin provides utilities for deploying smart contracts on zkSync Era with artifacts built by the -`@matterlabs/hardhat-zksync-solc` or `@matterlabs/hardhat-zksync-vyper` plugins. - -## Prerequisite - -To use the `hardhat-zksync-deploy` in your project, we recommend that: - -- You have a Node installation and `yarn` or `npm` package manager. -- You are already familiar with deploying smart contracts on zkSync Era. If not, please refer to the first section of - the [quickstart tutorial](../../quick-start/hello-world.md). -- A wallet with sufficient Sepolia `ETH` on Ethereum and zkSync Era Testnet to pay for deploying smart contracts on - testnet. You can get Sepolia ETH from the [network faucets](../../tooling/network-faucets.md). - - Get testnet `ETH` for zkSync Era using [bridges](https://zksync.io/explore#bridges) to bridge funds to zkSync. -- You know - [how to get your private key from your MetaMask wallet](https://support.metamask.io/hc/en-us/articles/360015289632-How-to-export-an-account-s-private-key). - -::: tip Local zkSync Testing with zksync-cli Skip the hassle for test ETH by using `zksync-cli` for local testing. -Simply execute `npx zksync-cli dev start` to initialize a local zkSync development environment, which includes local -Ethereum and zkSync nodes. This method allows you to test contracts without requesting external testnet funds. Explore -more in the [zksync-cli documentation](../zksync-cli/getting-started.md). ::: - -::: warning Version Compatibility Warning Ensure you are using the correct version of the plugin with ethers: - -- For plugin version **<1.0.0**: - - - Compatible with ethers **v5**. - -- For plugin version **≥1.0.0**: - - - Compatible with ethers **v6** (⭐ Recommended) - - ::: - -## Setup - -[@matterlabs/hardhat-zksync-deploy](https://www.npmjs.com/package/@matterlabs/hardhat-zksync-deploy) - -Add the latest version of this plugin to your project with the following command: - -::: code-tabs - -@tab:active yarn - -```bash -yarn add -D @matterlabs/hardhat-zksync-deploy ethers zksync-ethers -``` - -@tab npm - -```bash -npm i -D @matterlabs/hardhat-zksync-deploy -``` - -::: - -### Exports - -#### `Deployer` - -The main export of this plugin is the `Deployer` class. It is used to wrap a `zksync-ethers` Wallet instance and -provides a convenient interface to deploy smart contracts and account abstractions. It's main methods are: - -```typescript -class Deployer { - - /** - * @param hre Hardhat runtime environment. This object is provided to scripts by hardhat itself. - * @param zkWallet The wallet which will be used to deploy the contracts. - * @param deploymentType Optional deployment type that relates to the ContractDeployer system contract function to be called. Defaults to deploying regular smart contracts. - */ - constructor(hre: HardhatRuntimeEnvironment, zkWallet: zk.Wallet, deploymentType?: zk.types.DeploymentType) - - /** - * Created a `Deployer` object on ethers.Wallet object. - * - * @param hre Hardhat runtime environment. This object is provided to scripts by hardhat itself. - * @param ethWallet The wallet used to deploy smart contracts. - * @param deploymentType The optional deployment type that relates to the `ContractDeployer` system contract function to be called. Defaults to deploying regular smart contracts. - */ - static fromEthWallet(hre: HardhatRuntimeEnvironment, ethWallet: ethers.Wallet, deploymentType?: zk.types.DeploymentType) - - /** - * Loads an artifact and verifies that it was compiled by `zksolc`. - * - * @param contractNameOrFullyQualifiedName The name of the contract. - * It can be a bare contract name (e.g. "Token") if it's - * unique in your project, or a fully qualified contract name - * (e.g. "contract/token.sol:Token") otherwise. - * - * @throws Throws an error if a non-unique contract name is used, - * indicating which fully qualified names can be used instead. - * - * @throws Throws an error if an artifact was not compiled by `zksolc`. - */ - public async loadArtifact( - contractNameOrFullyQualifiedName: string - ): Promise - - /** - * Estimates the price of calling a deploy transaction in a certain fee token. - * - * @param artifact The previously loaded artifact object. - * @param constructorArguments The list of arguments to be passed to the contract constructor. - * - * @returns Calculated fee in ETH wei. - */ - public async estimateDeployFee( - artifact: ZkSyncArtifact, - constructorArguments: any[] - ): Promise - - /** - * Sends a deploy transaction to the zkSync network. - * For now it uses default values for the transaction parameters: - * - * @param artifact The previously loaded artifact object. - * @param constructorArguments The list of arguments to be passed to the contract constructor. - * @param overrides Optional object with additional deploy transaction parameters. - * @param additionalFactoryDeps Additional contract bytecodes to be added to the factory dependencies list. - * The fee amount is requested automatically from the zkSync Era server. - * - * @returns A contract object. - */ - public async deploy( - artifact: ZkSyncArtifact, - constructorArguments: any[], - overrides?: Overrides, - additionalFactoryDeps?: ethers.BytesLike[], - ): Promise - - /** - * Extracts factory dependencies from the artifact. - * - * @param artifact Artifact to extract dependencies from - * - * @returns Factory dependencies in the format expected by SDK. - */ - async extractFactoryDeps(artifact: ZkSyncArtifact): Promise -``` - -To see an example script of how to use a `Deployer` class to deploy a contract, check out the -[deployment section of the quickstart](./getting-started.md#compile-and-deploy-a-contract). - -### Configuration - -In the `hardhat.config.ts` file, specify zkSync Era and Ethereum networks in the `networks` object. - -```typescript -networks: { - sepolia: { - url: "https://sepolia.infura.io/v3/" // The Ethereum Web3 RPC URL (optional). - }, - zkTestnet: { - url: "https://sepolia.era.zksync.dev", // The testnet RPC URL of zkSync Era network. - ethNetwork: "sepolia", // The Ethereum Web3 RPC URL, or the identifier of the network (e.g. `mainnet` or `sepolia`) - zksync: true - } -}, -// defaultNetwork: "zkTestnet", // optional (if not set, use '--network zkTestnet') -``` - -- `zkTestnet` is an arbitrary zkSync Era network name. You can select this as the default network using the - `defaultNetwork` property. -- `url` is a field containing the URL of the zkSync Era node in case of the zkSync Era network (with `zksync` flag set - to `true`), or the URL of the Ethereum node. This field is required for all zkSync Era and Ethereum networks used by - this plugin. -- `ethNetwork` is a field with the URL of the Ethereum node. You can also provide network name (e.g. `sepolia`) as the - value of this field. In this case, the plugin will either use the URL of the appropriate Ethereum network - configuration (from the `networks` section), or the default `ethers` provider for the network if the configuration is - not provided. This field is required for all zkSync networks used by this plugin. -- `zksync` is a flag that indicates if the network is zkSync Era. This field needs to be set to `true` for all zkSync - Era networks; it is `false` by default. - -### Compilation and Deployment Support for Missing Libraries - -This plugin facilitates the compilation and deployment of missing libraries for users. By leveraging the -`@matterlabs/hardhat-zksync-solc` plugin, users can obtain a file that not only contains specifics about the missing -libraries for compilation but also showcases how they interlink with other dependent libraries. For more information -about missing libraries during the compilation process, please refer to [this link](./compiling-libraries.md). - -::: warning zksolc compiler version Starting from version 1.13.14, the zksolc compiler has been enhanced to identify -missing libraries. ::: - -Complex library dependency tree is also supported. It ensures libraries are compiled and deployed in a structured -manner, starting from the most foundational library to the topmost dependent one. - -Example: - -``` -Consider three libraries where: - -- Library A is dependent on Library B -- Library B is dependent on Library C - -A -└── B - └── C - -Deployment workflow: -1. Compile and deploy Library C. -2. Compile and deploy Library B, referencing the deployed address of Library C. -3. Compile and deploy Library A, referencing the deployed address of Library B. -``` - -The feature to automatically update the Hardhat user configuration with deployed addresses of libraries in the `zksolc` -object is supported as well. - -```typescript -zksolc: { - compilerSource: 'binary', - settings: { - libraries: { - "contracts/LibraryA.sol": { - "LibraryA": "0x13706Afd344d905BB9Cb50752065a67Fa8d09c70" - }, - "contracts/LibraryB.sol": { - "LibraryB": "0x4cf2E778D384746EaB115b914885e2bB18E893E2" - } - } - } - }, - // If the settings and libraries don't exist, they'll be created. -``` - -For a step-by-step guide on how to deploy missing libraries, see the `deploy-zksync:libraries` command below. - -### Commands - -`yarn hardhat deploy-zksync` -- runs through all the scripts in the `deploy` folder. - -::: tip The deployment scripts must be placed in the `deploy` folder. ::: - -- To run a specific script, add the `--script` argument, e.g. `hardhat deploy-zksync --script 001_deploy.ts`. This runs - script `./deploy/001_deploy.ts`. -- To run on a specific zkSync Era network, use the standard Hardhat `--network` argument, e.g. `--network zkTestnet`. - The network with the name `zkTestnet` needs to be configured in the `hardhat.config.ts` file, with all required fields - stated above, or specify `defaultNetwork` in `hardhat.config.ts` file. - -::: tip - -If network argument `--network` or `defaultNetwork` configuration are not specified, local setup with -`http://localhost:8545` (Ethereum RPC URL) and `http://localhost:3050` (zkSync Era RPC URL), will be used. In this case -zkSync Era network will not need to be configured in `hardhat.config.ts` file. For more details about a dockerized local -setup, check out [Local testing](../../test-and-debug/getting-started.md). ::: - -`yarn hardhat deploy-zksync:libraries --private-key ` -- runs compilation and deployment of missing -libraries (the list of all missing libraries is provided by the output of `@matterlabs/hardhat-zksync-solc` plugin). - -- `--private-key ` - A required argument. Libraries are deployed using the provided private key. -- `--no-auto-populate-config` - Flag which disables the auto-population of the hardhat config file. Enabled by default. -- `--external-config-object-path ` - Specifies the path to the file containing the zksolc configuration. If - not set, it defaults to the Hardhat configuration file path. Works only if auto-population is enabled. -- `--exported-config-object ` - Specifies the name of the user's Hardhat config object within the Hardhat - configuration file. Primarily for auto-population. Defaults to `config`. -- `--compile-all-contracts` - Compile all contracts with deployed libraries. Disabled by default. - -``` -yarn hardhat deploy-zksync:libraries --private-key 0x7726827caac94a7f9e1b160f7ea819f172f7b6f9d2a97f992c38edeab82d4110 -``` - -Example of using the `--exported-config-object ` argument: - -```javascript -const someObject = { - zksolc: { - compilerSource: 'binary', - settings: { - }, - solidity: { - compilers: compilers, - }, - .... - }, -} - -module.exports = someObject; -``` - -```bash -yarn hardhat deploy-zksync:libraries --private-key 0x7726827caac94a7f9e1b160f7ea819f172f7b6f9d2a97f992c38edeab82d4110 --exported-config-object someObject -``` - -::: tip In Typescript projects `--exported-config-object ` argument can be provided optionally. Plugin will -try to resolve config by `HardhatUserConfig` type. ::: - -::: warning Hardhat library auto-population - -Using `export default {}` for the Hardhat config is currently not supported for library auto-population. Instead, you -should use `export const config = {}`, and make sure to add `export default config;` at the bottom of the file. - -The default object name is `config`, but you can replace it with a different object name using the -`--exported-config-object ` command. This allows you to customize the exported object for your Hardhat -configuration. - -::: diff --git a/content/20.build/tooling/hardhat/hardhat-zksync-ethers.md b/content/20.build/tooling/hardhat/hardhat-zksync-ethers.md deleted file mode 100644 index 1ec28913..00000000 --- a/content/20.build/tooling/hardhat/hardhat-zksync-ethers.md +++ /dev/null @@ -1,191 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: hardhat-zksync-ethers | zkSync Docs ---- - -# `hardhat-zksync-ethers` - -:::warning SDK Deprecation Notice The `zksync2-js` SDK is now deprecated. \ -In line with this, the `hardhat-zksync-zksync2js` package will also be deprecated. \ -Moving forward, this package will be renamed to `hardhat-zksync-ethers` and will utilize the newly introduced -`zksync-ethers` SDK. \ -Please update your dependencies accordingly to ensure compatibility and continued support. ::: - -::: warning Version Compatibility Warning Ensure you are using the correct version of the plugin with ethers: - -- For plugin version **<1.0.0**: - - - Compatible with ethers **v5**. - -- For plugin version **≥1.0.0**: - - Compatible with ethers **v6** (⭐ Recommended) - -Examples are adopted for plugin version **>=1.0.0** ::: - -## Installation - -[@matterlabs/hardhat-zksync-ethers](https://www.npmjs.com/package/@matterlabs/hardhat-zksync-ethers) - -Add the latest version of this plugin to your project with the following command: - -::: code-tabs - -@tab:active yarn - -```bash -yarn add -D @matterlabs/hardhat-zksync-ethers zksync-ethers ethers -``` - -@tab npm - -```bash -npm i -D @matterlabs/hardhat-zksync-ethers -``` - -::: - -## Configuration - -Import the package in the `hardhat.config.ts` file: - -```ts -import '@matterlabs/hardhat-zksync-ethers'; -``` - -## Tasks - -This plugin creates no additional tasks. - -## Environment extensions - -This plugins adds an zksync-ethers object to the Hardhat Runtime Environment. This object has the same API as -[zksync-ethers](../../sdks/js/zksync-ethers/getting-started.md), with some extra Hardhat-specific functionality. - -## Helpers - -Helpers added to zksync-ethers object: - -```ts -interface FactoryDeps { - // A mapping from the contract hash to the contract bytecode. - [contractHash: string]: string; -} - -interface ZkSyncArtifact extends Artifact { - // List of factory dependencies of a contract. - factoryDeps: FactoryDeps; - // Mapping from the bytecode to the zkEVM assembly (used for tracing). - sourceMapping: string; -} - -interface FactoryOptions { - wallet?: zk.Wallet; -} - -function providerL2: () => zk.Provider; -function providerL1: () => ethers.Provider; -function getWallet: (privateKeyOrIndex?: string | number) => zk.Wallet; -function getContractFactory: (name: string, wallet?: zk.Wallet, deploymentType?: DeploymentType) => Promise; -function getContractFactory: (abi: any[], bytecode: ethers.BytesLike,wallet?: Wallet,deploymentType?: DeploymentType) => Promise; -function getContractFactoryFromArtifact: (artifact: ZkSyncArtifact, wallet?: zk.Wallet, deploymentType?: DeploymentType) => Promise; -function getContractAt: (nameOrAbi: string | any[], address: string | Address, wallet?: zk.Wallet) => Promise; -function getContractAtFromArtifact: (artifact: ZkSyncArtifact, address: string, wallet?: zk.Wallet) => Promise; -function getSigner: (address: string) => zk.Signer; -function getSigners: () => zk.Signer[]; -function getImpersonatedSigner: (address: string) => Promise; -function extractFactoryDeps: (artifact: ZkSyncArtifact) => Promise; -function loadArtifact: (name: string) => Promise; -function deployContract: (artifact: ZkSyncArtifact, constructorArguments: any[], wallet?: zk.Wallet, overrides?: ethers.Overrides, additionalFactoryDeps?: ethers.BytesLike[]) => Promise; -``` - -- `providerL2()` - retruns a `zk.Provider` for L2, automatically connected to the selected network. -- `providerL1()` - retruns a `ethers.Provider` for L1, automatically connected to the selected network. -- `getWallet(privateKeyOrIndex?: string | number)` - returns `zk.Wallet` for the given private key or index. If the - network is set to local and the private key is not provided, the method will return a wallet for rich accounts with - the default index of `0` or the specified index. If the `accounts` object is set in the hardhat config and the private - key is not specified, the method will return the wallet for the given account with the default index `0` or for the - specified index. -- `getWallets()` - returns all wallets of type `zk.Wallet`. If the network is set to local, the method will return - wallets for rich accounts. If the `accounts` object is set in the hardhat config for the used network, the method will - return the wallets for the provided accounts. -- `getContractFactory(name: string, wallet?: zk.Wallet, deploymentType?: DeploymentType)` - returns a - `zk.ContractFactory` for provided artifact name. -- `getContractFactory: (abi: any[], bytecode: ethers.BytesLike,wallet?: Wallet,deploymentType?: DeploymentType)` - - returns a zk.ContractFactory for provided artifact abi and bytecode. -- `getContractFactoryFromArtifact(artifact: ZkSyncArtifact, wallet?: zk.Wallet, deploymentType?: DeploymentType)` - - returns a `zk.ContractFactory` for provided artifact. -- `getContractAt(nameOrAbi: string | any[], address: string | Address, wallet?: zk.Wallet)` - returns `zk.Contract` for - provided artifact name or abi and address of deployed contract -- `getContractAtFromArtifact: (artifact: ZkSyncArtifact, address: string, wallet?: zk.Wallet)` - returns - `zk.ContractFactory` for provided artifact and address of deployed contract -- `getImpersonatedSigner(address: string)` - impersonates `zk.Signer` from address -- `loadArtifact(name: string)` - load `ZkSyncArtifact` from contract name -- `extractFactoryDeps(artifact: ZkSyncArtifact)` - extracts factory deps from artifact -- `deployContract(artifact: ZkSyncArtifact, constructorArguments: any[], wallet?: zk.Wallet, overrides?: ethers.Overrides, additionalFactoryDeps?: ethers.BytesLike[])` - - deploys contract, for more details check out the - [deployment section of the quickstart](./getting-started.md#compile-and-deploy-a-contract). - -::: tip - -- If `wallet?: zk.Wallet` is not provided and if the network is set to local, the default wallet will be the first - account in the list of rich accounts. If an `accounts` object is set in the hardhat config for the used network, the - default wallet will be taken from that object. -- If `deploymentType?: DeploymentType` is not provided default value will be `create` ::: - -## Usage - -Install it and access zksync-ethers through the Hardhat Runtime Environment anywhere you need it (tasks, scripts, tests, -etc). For example: - -Task usage: - -```ts -task('getFeeData', 'Returns a fee data.').setAction(async (hre) => { - const feeDataL2 = await hre.zksyncEthers.providerL2.getFeeData(); - const feeDataL1 = await this.env.zksyncEthers.providerL1.getFeeData(); - - return { feeDataL2, feeDataL1 }; -}); -``` - -Script usage: - -```ts -export default async function (hre: HardhatRuntimeEnvironment) { - console.info(chalk.yellow(`Running deploy`)); - - //automatically connected to the selected network - const gasPrice = await hre.zksyncEthers.providerL2.send('eth_gasPrice', []); - - //getContractFactory with default wallet, deploy contract and set new greeting message - const greeterFactory = await hre.zksyncEthers.getContractFactory('Greeter'); - const greeter = await greeterFactory.deploy('Hello, world!'); - - console.info(chalk.green(`Greeter deployed to: ${await greeter.getAddress()}`)); - - console.info(chalk.green(`Greeter greeting set to: ${await greeter.greet()}`)); - - const tx = await greeter.setGreeting('Hello, world again!'); - await tx.wait(); - console.info(chalk.green(`Greeter greeting set to: ${await greeter.greet()}`)); - - // deploy with provided wallet using loadArtifact and deployContract - const wallet = await hre.zksyncEthers.getWallet('0x7726827caac94a7f9e1b160f7ea819f172f7b6f9d2a97f992c38edeab82d4110'); - console.info(chalk.green(`Wallet address: ${await wallet.getAddress()}`)); - - // deposit ETH from L1 to L2 to cover costs of deployment - const depositHandle = await wallet.deposit({ - to: wallet.address, - token: utils.ETH_ADDRESS, - amount: ethers.parseEther('0.001'), - }); - await depositHandle.wait(); - - const artifact = await hre.zksyncEthers.loadArtifact('Greeter'); - const greets = await hre.zksyncEthers.deployContract(artifact, ['Hello, world!'], wallet); - console.info(chalk.green(`Greeter deployed to: ${await greets.getAddress()}`)); - console.info(chalk.green(`Greeter greeting set to: ${await greets.greet()}`)); -} -``` diff --git a/content/20.build/tooling/hardhat/hardhat-zksync-node.md b/content/20.build/tooling/hardhat/hardhat-zksync-node.md deleted file mode 100644 index 10f9b9eb..00000000 --- a/content/20.build/tooling/hardhat/hardhat-zksync-node.md +++ /dev/null @@ -1,176 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: hardhat-zksync-node | zkSync Docs ---- - -# `hardhat-zksync-node` - -This plugin is used to provide a convenient way to run zkSync Era -[In-memory node](../../test-and-debug/era-test-node.md) locally using hardhat. - -::: warning Platform Restrictions - -The zkSync Era In-memory node binaries are not supported on Windows at the moment. As an alternative, users can utilize -the Windows Subsystem for Linux (WSL). - -::: - -::: warning Version Compatibility Warning Ensure you are using the correct version of the plugin with ethers: - -- For plugin version **<1.0.0**: - - - Compatible with ethers **v5**. - -- For plugin version **≥1.0.0**: - - Compatible with ethers **v6** (⭐ Recommended) - -::: - -## Installation - -[@matterlabs/hardhat-zksync-node](https://www.npmjs.com/package/@matterlabs/hardhat-zksync-node) - -Add the latest version of this plugin to your project with the following command: - -::: code-tabs - -@tab:active yarn - -```bash -yarn add -D @matterlabs/hardhat-zksync-node zksync-ethers ethers -``` - -@tab npm - -```bash -npm i -D @matterlabs/hardhat-zksync-node -``` - -::: - -### Configuration - -Import the plugin in the `hardhat.config.ts` file: - -```javascript -import '@matterlabs/hardhat-zksync-node'; -``` - -### Commands - -```sh -yarn hardhat node-zksync -``` - -This command runs a local zkSync In-memory node by initiating a JSON-RPC server. It uses the provided or default -configurations to set up and run the zkSync node, allowing for blockchain operations in a local environment. The command -also handles tasks such as downloading the necessary JSON-RPC server binary if it's not already present. - -- `--port` - Port on which the server should listen. Defaults to 8011. -- `--log` - Log filter level. Accepted values are: error, warn, info, and debug. Defaults to info. -- `--log-file-path` - Path to the file where logs should be written. Defaults to `era_test_node.log`. -- `--cache` - Type of cache to use. Accepted values are: none, disk, and memory. Defaults to disk. -- `--cache-dir` - Directory location for the `disk` cache. Defaults to `.cache`. -- `--reset-cache` - Flag to reset the local `disk` cache. -- `--show-calls` - Determines which call debug information to show. Accepted values are: none, user, system, and all. - Defaults to none. -- `--show-storage-logs` - Determines which storage logs to show. Accepted values are: none, read, write, and all. - Defaults to none. -- `--show-vm-details` - Specifies the level of Virtual Machine (VM) details to show. Accepted values are: none and all. - Defaults to none. -- `--show-gas-details` - Specifies the level of gas details to show. Accepted values are: none and all. Defaults to - none. -- `--resolve-hashes` - Flag to try contacting openchain to resolve the ABI & topic names. When enabled, it makes the - debug log more readable but might decrease performance. -- `--dev-use-local-contracts` - Flag to load locally compiled system contracts. Useful when making changes to system - contracts or bootloader. -- `--fork` - Starts a local network that is a fork of another network. Accepted values are: testnet, mainnet, or a - specific URL. -- `--fork-block-number` - Specifies the block height at which to fork. -- `--replay-tx` - Transaction hash to replay. - -::: warning Parameter Restrictions - -The `--replay-tx` and `--fork-block-number` parameters cannot be specified simultaneously. The `--replay-tx` is used for -replaying a remote transaction locally for deep debugging, while `--fork-block-number` is used for forking the -blockchain at a specified block number. Combining these actions is not supported.
Additionally, if either -`--replay-tx` or `--fork-block-number` is specified, the `--fork` parameter must also be provided. - -::: - -::: tip Learn More - -If you wish to learn more about replaying transactions or forking, check out the -[In-memory node documentation](../../test-and-debug//era-test-node.md). - -::: - -::: tip Supported APIs - -To see a list of all supported APIs, visit -[this link ](https://github.com/matter-labs/era-test-node/blob/main/SUPPORTED_APIS.md). - -::: - -## Running Hardhat's test Task with hardhat-zksync-node - -The `hardhat-zksync-node` plugin enhances Hardhat's test task, allowing all tests to run against an In-memory node -operated in a separate process. By invoking the test task, ensure you are using the `hardhat` network and have set its -`zksync` flag to `true`. Doing so will initiate the plugin's In-memory node alongside the tests. After the tests -conclude, the node shuts down gracefully. The plugin begins port allocation from the default 8011. - -```ts -networks: { - hardhat: { - zksync: true, - } -}, -``` - -The network object in the Hardhat runtime environment is also updated to match the running node as follows: - -- The network name is set to `zkSyncEraTestNode`. -- The network config is set as an HTTP network config, adopting default values. -- The network provider uses a provider adapter that implements `EthereumProvider` and wraps the zksync's JS SDK Provider - implementation. - -::: warning Provider URL Mismatch - -When running tests, be aware that the In-memory node attempts to allocate free ports (starting from the default 8011). -This can lead to situations where the provider's URL does not match your expectations. It's strongly recommended to use -the network config URL from the hardhat runtime environment to instantiate the Provider instance from the JS SDK, like -this: - -```typescript -const provider = new Provider(hre.network.config.url); -``` - -::: - -::: info TypeScript Note - -If TypeScript marks the 'url' property indicating a potential issue (even though it works), simply add the following -import to your project: - -```typescript -import '@matterlabs/hardhat-zksync-node/dist/type-extensions'; -``` - -::: - -::: note Accessing the Network Provider in Hardhat - -Apart from the previously described method of instantiating the Provider, you can also directly access it from the -Hardhat runtime environment. Due to incompatibilities between Hardhat's `EthereumProvider` and the JS SDK Provider, -we've introduced a new adapter (`ZkSyncProviderAdapter`). This adapter bridges the gap and ensures that all the -necessary functionalities are seamlessly integrated. If you wish to access the JS SDK Provider directly, you can do so -in TypeScript with: - -```typescript -// hre stands for hardhat runtime environment -(hre.network.provider as ZkSyncProviderAdapter)._zkSyncProvider; -``` - -::: diff --git a/content/20.build/tooling/hardhat/hardhat-zksync-solc.md b/content/20.build/tooling/hardhat/hardhat-zksync-solc.md deleted file mode 100644 index 2117cb9d..00000000 --- a/content/20.build/tooling/hardhat/hardhat-zksync-solc.md +++ /dev/null @@ -1,252 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: hardhat-zksync-solc | zkSync Docs ---- - -# `hardhat-zksync-solc` - -This plugin is used to provide a convenient interface for compiling Solidity smart contracts before deploying them to -zkSync Era. - -Learn more about the latest updates in the -[changelog](https://github.com/matter-labs/hardhat-zksync/blob/main/packages/hardhat-zksync-solc/CHANGELOG.md) - -## Prerequisite - -To use the `hardhat-zksync-solc` in your project, we recommend that: - -- You have a Node installation and `yarn` or `npm` package manager. - -## Installation - -[@matterlabs/hardhat-zksync-solc](https://www.npmjs.com/package/@matterlabs/hardhat-zksync-solc) - -Add the latest version of this plugin to your project with the following command: - -::: code-tabs - -@tab:active yarn - -```bash -yarn add -D @matterlabs/hardhat-zksync-solc -``` - -@tab npm - -```bash -npm i -D @matterlabs/hardhat-zksync-solc -``` - -::: - -## Configuration - -Import the package in the `hardhat.config.ts` file: - -```ts -import '@matterlabs/hardhat-zksync-solc'; -``` - -::: info Default config in hardhat-zksync-solc ^0.4.0 - -Version 0.4.0 introduced a default configuration making all parameters optional. You can override the default -configuration in the `hardhat.config.ts` file. - -::: - -::: info Support for missing libraries in hardhat-zksync-solc ^0.4.2 - -Version 0.4.2 introduced a mode that detects non-inlinable libraries that are missing and that are required for the -compilation of contracts. This feature works with the `hardhat-zksync-deploy` plugin, specifically the -`deploy-zksync:libraries` task, to compile and deploy the missing libraries. There are no new commands, just follow the -instructions logged by the `yarn hardhat compile` output. - -Upon encountering missing non-inline libraries during the compilation process, the compiler logged steps to follow, -while compilation is not valid. This results with empty `artifacts-zk` and `cache-zk` folders. - -::: - -Any configuration parameters should be added inside a `zksolc` property in the `hardhat.config.ts` file: - -```typescript -zksolc: { - version: "latest", // optional. - settings: { - compilerPath: "zksolc", // optional. Ignored for compilerSource "docker". Can be used if compiler is located in a specific folder - libraries:{}, // optional. References to non-inlinable libraries - missingLibrariesPath: "./.zksolc-libraries-cache/missingLibraryDependencies.json", // optional. This path serves as a cache that stores all the libraries that are missing or have dependencies on other libraries. A `hardhat-zksync-deploy` plugin uses this cache later to compile and deploy the libraries, especially when the `deploy-zksync:libraries` task is executed - isSystem: false, // optional. Enables Yul instructions available only for zkSync system contracts and libraries - forceEvmla: false, // optional. Falls back to EVM legacy assembly if there is a bug with Yul - optimizer: { - enabled: true, // optional. True by default - mode: '3', // optional. 3 by default, z to optimize bytecode size - fallback_to_optimizing_for_size: false, // optional. Try to recompile with optimizer mode "z" if the bytecode is too large - }, - experimental: { - dockerImage: '', // deprecated - tag: '' // deprecated - }, - contractsToCompile: [] //optional. Compile only specific contracts - } -}, - -``` - -::: warning - -- Compilers are no longer released as Docker images and its usage is no longer recommended. - -::: - -- `version` is the `zksolc` compiler version. Compiler versions can be found in - [the following repository](https://github.com/matter-labs/zksolc-bin). -- `compilerSource` indicates the compiler source and can be either `binary` (default) or `docker` (deprecated). If there - isn't a compiler binary already installed, the plugin will automatically download it. -- `compilerPath` (optional) is a field with the path to the `zksolc` binary. By default, the binary in `$PATH` is used. -- `libraries` if your contract uses non-inlinable libraries as dependencies, they have to be defined here. Learn more - about [compiling libraries here](./compiling-libraries.md) -- `missingLibrariesPath` (optional) serves as a cache that stores all the libraries that are missing or have - dependencies on other libraries. A `hardhat-zksync-deploy` plugin uses this cache later to compile and deploy the - libraries, especially when the `deploy-zksync:libraries` task is executed. Defaults to - `./.zksolc-libraries-cache/missingLibraryDependencies.json`. -- `isSystem` - required if contracts use enables Yul instructions available only for zkSync system contracts and - libraries -- `forceEvmla` - falls back to EVM legacy assembly if there is an issue with the Yul IR compilation pipeline. -- `optimizer` - Compiler optimizations: - - `enabled`: `true` (default) or `false`. - - `mode`: `3` (default) recommended for most projects. Mode `z` reduces bytecode size for large projects that make - heavy use of `keccak` and far calls. - - `fallback_to_optimizing_for_size` (optional) indicates that the compiler will try to recompile with optimizer mode - "z" if the bytecode is too large. -- `metadata`: Metadata settings. If the option is omitted, the metadata hash appends by default: - - `bytecodeHash`: Can only be `none`. It removes metadata hash from the bytecode. -- `dockerImage` and `tag` are deprecated options used to identify the name of the compiler docker image. -- `contractsToCompile` (optional) field is utilized to compile only the specified contracts. The contract names do not - necessarily need to be written in full qualified form. The plugin will perform an include operation, attempting to - match the provided contract names. - -::: warning forceEvmla usage - -Setting the `forceEvmla` field to true can have the following negative impacts: - -- No support for recursion. -- No support for internal function pointers. -- Possible contract size and performance impact. - -For Solidity versions older than 0.8, only this compilation mode is available and it is used by default. - -::: - -::: warning fallback_to_optimizing_for_size usage - -`fallback_to_optimizing_for_size` option is supported for zksolc compiler version 1.3.21 or higher. - -::: - -### Compiler informations - -The zksolc compilers are stored in the cache folder with the path `{cache}/hardhat-nodejs/compilers-v2/zksolc`. In this -location, you can inspect the locally stored compiler versions. - -`{cache}` is a placeholder for a path that is resolved by Hardhat - -The `compilerVersion.json` file is used by the plugin to get the latest available version and the minimum required -compiler version. This file undergoes invalidation every 24 hours (currently), subsequently being updated with fresh -information. This approach is implemented to provide a caching mechanism, avoiding the risk of encountering GitHub -throttling issues during fetching new releases. - -### zkSync Era Solidity compiler - -Due to -[the identified limitations](https://docs.zksync.io/zk-stack/components/compiler/toolchain/solidity.html#limitations) of -the [upstream Solidity compiler](https://github.com/ethereum/solidity), our team has developed -[a new edition](https://github.com/matter-labs/era-solidity) of the compiler, which effectively addresses and resolves -these constraints. - -For usage of EraVM compiler, `eraVersion` should be added inside `solidity` property in the `hardhat.config.ts` file: - -```typescript -solidity: { - version: "0.8.17", - eraVersion: "1.0.0" //optional. Compile contracts with EraVM compiler -}, - -``` - -- `eraVersion` - (optional) field used to specify version of EraVM compiler - -::: warning eraVersion usage - -Using latest as the field value is not supported. Instead, the eraVersion field must be filled with a specific version. - -::: - -::: warning EraVM compiler usage - -To use the EraVM compiler, the zksolc compiler version must be equal to or greater than 1.3.22. - -::: - -### Network configuration - -Configure the `zksync` parameter in the networks to enable the zksolc compiler: - -```ts -defaultNetwork: "zkSyncTestnet", -networks: { - sepolia: { - url: "https://sepolia.infura.io/v3/", // The Ethereum Web3 RPC URL (optional). - zksync: false, // disables zksolc compiler - }, - zkSyncTestnet: { - url: "https://sepolia.era.zksync.dev", // The testnet RPC URL of zkSync Era network. - ethNetwork: "sepolia", // The Ethereum Web3 RPC URL, or the identifier of the network (e.g. `mainnet` or `sepolia`) - zksync: true, // enables zksolc compiler - } -}, -``` - -- `zksync` network option indicates whether zksolc is enabled on a certain network. `false` by default. Useful for - multichain projects in which you can enable `zksync` only for specific networks. - -## Commands - -::: code-tabs - -@tab:active yarn - -```bash -yarn hardhat compile -``` - -@tab npm - -```bash -npx hardhat compile -``` - -::: - -Compiles all the smart contracts in the `contracts` directory and creates the `artifacts-zk` folder with all the -compilation artifacts, including factory dependencies for the contracts, which could be used for contract deployment. - -To understand what the factory dependencies are, read more about them in the [Web3 API](../../api.md) documentation. - -## Troubleshooting - -#### Error in plugin @matterlabs/hardhat-zksync-solc: Invalid zksolc compiler version - -This error is returned when the version defined in the `hardhat.config.ts` file is lower than the minimal required -(versions are defined in file [compilerVersion.json](#compiler-informations)). Update the version to solve the issue. - -#### Why is there an `unexpected end of JSON input` compilation error? - -This is an error that is usually thrown when compiling a large smart contract codebase. - -If you encounter such an error, please do the following: - -- Update the `@matterlabs/hardhat-zksync-solc` library and try to re-compile the smart contracts afterwards. -- If after the recompilation you get the `Library not found` error, then you should follow the instructions from - [here](./compiling-libraries.md). diff --git a/content/20.build/tooling/hardhat/hardhat-zksync-toolbox.md b/content/20.build/tooling/hardhat/hardhat-zksync-toolbox.md deleted file mode 100644 index 689104bb..00000000 --- a/content/20.build/tooling/hardhat/hardhat-zksync-toolbox.md +++ /dev/null @@ -1,61 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: zkSync Hardhat Plugins | zkSync Docs ---- - -# `hardhat-zksync-toolbox` - -The hardhat-zksync-toolbox plugin provides a convenient method for bundling and accessing a range of zkSync-related -Hardhat plugins. This approach simplifies the process of utilizing these plugins and promotes ease of use. - -List of contained plugins: - -- [hardhat-zksync-solc](./hardhat-zksync-solc.md) -- [hardhat-zksync-deploy](./hardhat-zksync-deploy.md) -- [hardhat-zksync-chai-matchers](./hardhat-zksync-chai-matchers.md) -- [hardhat-zksync-verify](./hardhat-zksync-verify.md) - -::: tip Popular Hardhat plugins - -You can find a list of all official plugins [here](./getting-started.md). Also, zkSync supports some other -[popular plugins](./other-plugins.md) that can be used. - -::: - -### Installation - -Add the latest version of this plugin to your project with the following command: - -::: code-tabs - -@tab:active yarn - -```bash -yarn add -D @matterlabs/hardhat-zksync-toolbox @matterlabs/hardhat-zksync-solc @matterlabs/hardhat-zksync-chai-matchers @matterlabs/hardhat-zksync-deploy @matterlabs/hardhat-zksync-verify @nomicfoundation/hardhat-verify @nomiclabs/hardhat-ethers ethers chai zksync-ethers -``` - -@tab npm - -```bash -npm i -D @matterlabs/hardhat-zksync-toolbox -``` - -::: - -::: note For `npm`, version 7 or later is recommended. ::: - -### Usage - -After installing it, add the plugin to your Hardhat config: - -```javascript -import '@matterlabs/hardhat-zksync-toolbox'; -``` - -With the hardhat-zksync-toolbox plugin installed and imported, you will have access to all of the supported plugins and -will be able to use them as needed in your project. - -::: note To learn more about using any of the plugins that are supported by the hardhat-zksync-toolbox plugin, you can -refer to their documentation above. ::: diff --git a/content/20.build/tooling/hardhat/hardhat-zksync-upgradable.md b/content/20.build/tooling/hardhat/hardhat-zksync-upgradable.md deleted file mode 100644 index 799d7078..00000000 --- a/content/20.build/tooling/hardhat/hardhat-zksync-upgradable.md +++ /dev/null @@ -1,793 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: hardhat-zksync-upgradable | zkSync Docs ---- - -# `hardhat-zksync-upgradable` - -The `hardhat-zksync-upgradable` plugin is a Hardhat plugin that supports end-to-end pipelines for deploying and updating -upgradable smart contracts on the zkSync Era network. - -The plugin is based on [@openzeppelin/upgrades-core](https://www.npmjs.com/package/@openzeppelin/upgrades-core) plugin -for deploying and managing upgradeable smart contracts on the Ethereum network. The `hardhat-zksync-upgradable` plugin -provides an easy-to-use interface for interacting with the -[OpenZeppelin Upgrades Plugins](https://docs.openzeppelin.com/upgrades-plugins) within a Hardhat environment on zkSync. - -::: warning Version Compatibility Warning Ensure you are using the correct version of the plugin with ethers: - -- For plugin version **<1.0.0**: - - - Compatible with ethers **v5**. - -- For plugin version **≥1.0.0**: - - Compatible with ethers **v6** (⭐ Recommended) - -Examples are adopted for plugin version **>=1.0.0** ::: - -## Installation - -:::warning Version Incompatibility Current version of the upgradable plugin does not support the latest version of the -`@openzeppelin/upgrades-core` package. ::: - -[@matterlabs/hardhat-zksync-upgradable](https://www.npmjs.com/package/@matterlabs/hardhat-zksync-upgradable) - -Add the latest version of this plugin to your project with the following command: - -::: code-tabs - -@tab:active yarn - -```bash -yarn add -D @matterlabs/hardhat-zksync-upgradable @openzeppelin/upgrades-core @openzeppelin/contracts-upgradeable@4.9.5 @openzeppelin/contracts@4.9.5 -``` - -@tab npm - -```bash -npm i -D @matterlabs/hardhat-zksync-upgradable @openzeppelin/contracts-upgradeable@4.9.5 @openzeppelin/contracts@4.9.5 -``` - -::: - -## Configuration - -After installing it, add the plugin to your `hardhat.config.ts` file: - -```typescript -import '@matterlabs/hardhat-zksync-solc'; -import '@matterlabs/hardhat-zksync-deploy'; -// upgradable plugin -import '@matterlabs/hardhat-zksync-upgradable'; - -import { HardhatUserConfig } from 'hardhat/config'; - -const config: HardhatUserConfig = { - zksolc: { - version: 'latest', - settings: {}, - }, - defaultNetwork: 'zkSyncNetwork', - networks: { - ethNetwork: { - zksync: false, - url: 'http://localhost:8545', - }, - zkSyncNetwork: { - zksync: true, - ethNetwork: 'ethNetwork', - url: 'http://localhost:3050', - }, - }, - solidity: { - version: '0.8.19', - }, -}; - -export default config; -``` - -## Deploying proxies - -The plugin supports three types of proxies: Transparent upgradable proxies, UUPS proxies, and beacon proxies. - -Upgradability methods are all part of the `zkUpgrades` property in the `HardhatRuntimeEnvironment` and you only need to -interact with it in order to deploy or upgrade your contracts. - -For the following examples, we use the simple `Box` smart contract: - -```typescript -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.16; -import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; - - -contract Box is Initializable{ - uint256 private value; - uint256 private secondValue; - uint256 private thirdValue; - - function initialize(uint256 initValue) public initializer { - value = initValue; - } - - // Reads the last stored value - function retrieve() public view returns (uint256) { - return value; - } - - // Stores a new value in the contract - function store(uint256 newValue) public { - value = newValue; - emit ValueChanged(newValue); - } - // Emitted when the stored value changes - event ValueChanged(uint256 newValue); - -} -``` - -In the examples below, we assume that the Box contract is compiled and its artifact loaded using Deployer class from the -[hardhat-zksync-deploy plugin](./hardhat-zksync-deploy.md). More info on how to compile and load the contract can be -found in the [Hardhat getting started page](./getting-started.md). - -## Transparent upgradable proxies - -Transparent upgradable proxies provide a way to upgrade a smart contract without changing its address or requiring any -change in the contract's interaction code. With transparent proxies, a contract's address is owned by a proxy contract, -which forwards all calls to the actual contract implementation. When a new implementation is deployed, the proxy can be -upgraded to point to the new implementation, allowing for seamless upgrades without requiring changes to the contract's -interaction code. - -To deploy a simple upgradable contract on zkSync Era local setup, first create a test wallet and add it to the new -Deployer. - -```typescript -// mnemonic for local node rich wallet -const testMnemonic = 'stuff slice staff easily soup parent arm payment cotton trade scatter struggle'; -const zkWallet = Wallet.fromMnemonic(testMnemonic); - -const deployer = new Deployer(hre, zkWallet); -``` - -After that, load the `Box` artifact and call the `deployProxy` method from the `zkUpgrades` hre property. - -```typescript -const contractName = 'Box'; -const contract = await deployer.loadArtifact(contractName); -await hre.zkUpgrades.deployProxy(deployer.zkWallet, contract, [42], { initializer: 'initialize' }); -``` - -The `deployProxy` method deploys your implementation contract on zkSync Era, deploys the proxy admin contract, and -finally, deploys the transparent proxy. - -### Full deploy proxy script - -```typescript -import { Deployer } from '@matterlabs/hardhat-zksync-deploy'; -import { Wallet } from 'zksync-ethers'; - -import * as hre from 'hardhat'; - -async function main() { - const contractName = 'Box'; - console.log('Deploying ' + contractName + '...'); - - // mnemonic for local node rich wallet - const testMnemonic = 'stuff slice staff easily soup parent arm payment cotton trade scatter struggle'; - const zkWallet = Wallet.fromMnemonic(testMnemonic); - - const deployer = new Deployer(hre, zkWallet); - - const contract = await deployer.loadArtifact(contractName); - const box = await hre.zkUpgrades.deployProxy(deployer.zkWallet, contract, [42], { initializer: 'initialize' }); - - await box.waitForDeployment(); - console.log(contractName + ' deployed to:', await box.getAddress()); - - box.connect(zkWallet); - const value = await box.retrieve(); - console.log('Box value is: ', value); -} - -main().catch((error) => { - console.error(error); - process.exitCode = 1; -}); -``` - -Run the script with: - -::: code-tabs - -@tab:active yarn - -```bash -yarn hardhat run SCRIPT_FILE -``` - -@tab npm - -```bash -npx hardhat run SCRIPT_FILE -``` - -::: - -:::warning - -- deployProxy method (and other deploy/upgrade methods from the zkUpgrades) needs to know which wallet to use to deploy - smart contracts. -- For this reason, the wallet needs to have a configured provider that connects it to the specific zkSync network. -- This provider is configured in the hardhat config file, by stating the RPC url of the network to connect to. ::: - -### Openzeppelin Version - -The plugin does not work with the latest versions due to a blocker on the `@matterlab/zksync-contracts` package.The -solution is to change the development dependencies to the previous version in your `package.json`. - -``` - "@openzeppelin/contracts": "^4.9.5", - "@openzeppelin/contracts-upgradeable": "^4.9.5", -``` - -### Hardhat config - -```typescript -defaultNetwork: 'zkSyncNetwork', - networks: { - sepolia: { - zksync: false, - url: 'http://localhost:3050', - }, - zkSyncNetwork: { - zksync: true, - ethNetwork: 'sepolia', - url: 'http://localhost:8545', - }, - }, -``` - -Since the provider was instantiated on creating the `Deployer` class, based on your Hardhat configuration, we only have -to pass the `deployer.zkWallet` and be sure that the correct provider is already set. - -On the other hand, if you need to explicitly set the provider, do that with the code below: - -```typescript - import { Provider } from "zksync-ethers"; - - const provider = new Provider("https://sepolia.era.zksync.dev"); - - const testMnemonic = 'stuff slice staff easily soup parent arm payment cotton trade scatter struggle'; - const zkWallet = Wallet.fromMnemonic(testMnemonic); - zkWallet.connect(provider); - - const deployer = new Deployer(hre, zkWallet); - ... -``` - -## UUPS proxies - -:::warning - -- If you want to use the plugin's UUPS proxy functionality, use zksolc version >=1.3.9. ::: - -The UUPS proxy pattern is similar to the transparent proxy pattern, except that the upgrade is triggered via the logic -contract instead of from the proxy contract. - -For the UUPS deployment example, we use a slightly modified smart contract called `BoxUups`. - -```typescript - -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.16; -import '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; -import '@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol'; -import '@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol'; - -contract BoxUups is Initializable, { - uint256 private value; - uint256 private secondValue; - uint256 private thirdValue; - - function initialize(uint256 initValue) public initializer { - value = initValue; - __Ownable_init(); - __UUPSUpgradeable_init(); - } - - // Reads the last stored value - function retrieve() public view returns (uint256) { - return value; - } - - // Stores a new value in the contract - function store(uint256 newValue) public { - value = newValue; - emit ValueChanged(newValue); - } - - function _authorizeUpgrade(address) internal override onlyOwner {} - - // Emitted when the stored value changes - event ValueChanged(uint256 newValue); -} -``` - -The main difference between the `Box` and `BoxUups` contracts is that the latter implements both `UUPSUpgradeable` and -`OwnableUpgradeable` interfaces and has a special function `_authorizeUpgrade` which can only be called by the contract -owner. - -You can find more info about how UUPS works in -[OpenZeppelin's documentation.](https://docs.openzeppelin.com/contracts/4.x/api/proxy#transparent-vs-uups) - -To deploy the UUPS contract, use the same script as for the transparent upgradable proxy. - -```typescript -async function main() { - const contractName = 'BoxUups'; - console.info(chalk.yellow('Deploying ' + contractName + '...')); - - // mnemonic for local node rich wallet - const testMnemonic = 'stuff slice staff easily soup parent arm payment cotton trade scatter struggle'; - const zkWallet = Wallet.fromMnemonic(testMnemonic); - ... -``` - -When you run the script, the plugin detects that the proxy type is UUPS, it executes the deployment, and saves the -deployment info in your manifest file. - -## Beacon proxies - -Beacon proxies are a more advanced form of proxy that use an intermediate contract (called the Beacon contract) to -delegate calls to a specific implementation contract. - -Beacon proxies enable a more advanced upgrade pattern, where multiple implementation contracts can be deployed and -"hot-swapped" on the fly with no disruption to the contract's operation. - -This allows for more advanced upgrade patterns, such as adding or removing functionality while minimizing downtime. - -1. Start by creating a `Deployer` for the zkSync Era network and load the `Box` artifact: - -```typescript -// mnemonic for local node rich wallet -const testMnemonic = 'stuff slice staff easily soup parent arm payment cotton trade scatter struggle'; -const zkWallet = Wallet.fromMnemonic(testMnemonic); - -const deployer = new Deployer(hre, zkWallet); - -const contractName = 'Box'; -const boxContract = await deployer.loadArtifact(contractName); -``` - -2. Deploy the beacon contract using `deployBeacon` method from the `zkUpgrades` - -```typescript -await hre.zkUpgrades.deployBeacon(deployer.zkWallet, boxContract); -``` - -3. Use the `deployBeaconProxy` method which receives the zkSync Era wallet, beacon contract, and the implementation - (Box) contract with its arguments. - -```typescript -const box = await hre.zkUpgrades.deployBeaconProxy(deployer.zkWallet, beacon, boxContract, [42]); -``` - -After that, your beacon proxy contract is deployed on the network, and you can interact with it. - -### Full code for deploy beacon - -```typescript -import { Deployer } from '@matterlabs/hardhat-zksync-deploy'; -import { Wallet } from 'zksync-ethers'; - -import * as hre from 'hardhat'; - -async function main() { - const contractName = 'Box'; - console.log('Deploying ' + contractName + '...'); - // mnemonic for local node rich wallet - const testMnemonic = 'stuff slice staff easily soup parent arm payment cotton trade scatter struggle'; - const zkWallet = Wallet.fromMnemonic(testMnemonic); - - const deployer = new Deployer(hre, zkWallet); - - const boxContract = await deployer.loadArtifact(contractName); - const beacon = await hre.zkUpgrades.deployBeacon(deployer.zkWallet, boxContract); - await beacon.waitForDeployment(); - console.log('Beacon deployed to:', await beacon.getAddress()); - - const box = await hre.zkUpgrades.deployBeaconProxy(deployer.zkWallet, await beacon.getAddress(), boxContract, [42]); - await box.waitForDeployment(); - console.log(contractName + ' beacon proxy deployed to: ', await beacon.getAddress()); - - box.connect(zkWallet); - const value = await box.retrieve(); - console.log('Box value is: ', value); -} - -main().catch((error) => { - console.error(error); - process.exitCode = 1; -}); -``` - -Run the script with: - -::: code-tabs - -@tab:active yarn - -```bash -yarn hardhat run SCRIPT_FILE -``` - -@tab npm - -```bash -npx hardhat run SCRIPT_FILE -``` - -::: - -## Implementation addresses check - -Once you deploy the proxy contract, all interactions with your implementation contract go through it. - -If you invoke the `deployProxy` function multiple times for a single implementation contract, several proxies will be -created, but the implementation contract will remain the same for all of them. This means we can optimize the process to -check for the existing implementation addresses before deploying a new proxy, instead of deploying a new implementation -contract every time. - -The upgradable plugin saves this information in the manifest file. This file will be created in your project's -`.upgradable` folder. The manifest file is created per network, meaning you will have different data saved for upgrading -contracts on the local setup and zkSync Era networks. - -# Upgrading proxies - -## Validations - -In order for a smart contract implementation to be upgradable, it has to follow specific -[rules](https://docs.openzeppelin.com/upgrades-plugins/1.x/writing-upgradeable). - -:::warning - -- The current version of the `hardhat-zksync-upgradable` plugin does **NOT** support all the validation checks. -- This means that it is the users responsibility to check if the new implementation they want to upgrade follows the - predefined standards. -- At the time of writing, we are working on implementing those checks within the plugin itself, and the plan for - subsequent releases is to support them natively. ::: - -## Upgradable examples - -The following examples use the `BoxV2` contract as a new implementation for the `Box` proxy. - -```typescript -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.16; - -import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; - -contract BoxV2 is Initializable{ - uint256 private value; - - // Emitted when the stored value changes - event ValueChanged(uint256 newValue); - - function initialize(uint256 initValue) public initializer { - value = initValue; - } - - // Stores a new value in the contract - function store(uint256 newValue) public { - value = newValue; - emit ValueChanged(newValue); - } - - // Reads the last stored value and returns it with a prefix - function retrieve() public view returns (string memory) { - return string(abi.encodePacked("V2: ", uint2str(value))); - } - - // Converts a uint to a string - function uint2str(uint _i) internal pure returns (string memory) { - if (_i == 0) { - return "0"; - } - uint j = _i; - uint len; - while (j != 0) { - len++; - j /= 10; - } - bytes memory bstr = new bytes(len); - uint k = len; - while (_i != 0) { - k = k - 1; - uint8 temp = (48 + uint8(_i - (_i / 10) * 10)); - bytes1 b1 = bytes1(temp); - bstr[k] = b1; - _i /= 10; - } - return string(bstr); - } -} -``` - -## Upgrade transparent proxy - -To upgrade the implementation of the transparent upgradeable contract, use the `upgradeProxy` method from the -`zkUpgrades`. - -```typescript - const BoxV2 = await deployer.loadArtifact('BoxV2'); - await hre.zkUpgrades.upgradeProxy(deployer.zkWallet, , BoxV2); -``` - -`upgradeProxy` receives 3 arguments: - -- A zkSync Era wallet. -- The address of the previously deployed box proxy. -- The artifact containing the new `Box2` implementation. - -## Upgrade UUPS proxy - -Similar to the deployment script, there are no modifications needed to upgrade the implementation of the UUPS contract, -compared to upgrading the transparent upgradable contract. The only difference is that we use the `BoxUupsV2` as a new -implementation contract. - -```typescript - -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.16; -import '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; -import '@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol'; -import '@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol'; - -contract BoxUupsV2 is Initializable, UUPSUpgradeable, OwnableUpgradeable { - uint256 private value; - uint256 private secondValue; - uint256 private thirdValue; - - function initialize(uint256 initValue) public initializer { - value = initValue; - } - - // Reads the last stored value and returns it with a prefix - function retrieve() public view returns (string memory) { - return string(abi.encodePacked('V2: ', uint2str(value))); - } - - // Converts a uint to a string - function uint2str(uint _i) internal pure returns (string memory) { - if (_i == 0) { - return '0'; - } - uint j = _i; - uint len; - while (j != 0) { - len++; - j /= 10; - } - bytes memory bstr = new bytes(len); - uint k = len; - while (_i != 0) { - k = k - 1; - uint8 temp = (48 + uint8(_i - (_i / 10) * 10)); - bytes1 b1 = bytes1(temp); - bstr[k] = b1; - _i /= 10; - } - return string(bstr); - } - - // Stores a new value in the contract - function store(uint256 newValue) public { - value = newValue; - emit ValueChanged(newValue); - } - - function _authorizeUpgrade(address) internal override onlyOwner {} - - // Emitted when the stored value changes - event ValueChanged(uint256 newValue); -} -``` - -Upgrade proxy script snippet: - -```typescript - const BoxUupsV2 = await deployer.loadArtifact('BoxUupsV2'); - await hre.zkUpgrades.upgradeProxy(deployer.zkWallet, , BoxUupsV2); -``` - -## Upgrade beacon proxy - -Beacon proxy implementation can be upgraded using a similarly structured method from the `zkUpgrades` called -`upgradeBeacon`. For example: - -```typescript - const boxV2Implementation = await deployer.loadArtifact('BoxV2'); - await hre.zkUpgrades.upgradeBeacon(deployer.zkWallet, , boxV2Implementation); -``` - -The example below deploys and upgrades a smart contract using a beacon proxy: - -```typescript -import { Deployer } from '@matterlabs/hardhat-zksync-deploy'; -import { Wallet } from 'zksync-ethers'; -import * as zk from 'zksync-ethers'; -import { Contract } from 'ethers'; - -import * as hre from 'hardhat'; - -async function main() { - // mnemonic for local node rich wallet - const testMnemonic = 'stuff slice staff easily soup parent arm payment cotton trade scatter struggle'; - const zkWallet = Wallet.fromMnemonic(testMnemonic); - const deployer = new Deployer(hre, zkWallet); - - // deploy beacon proxy - const contractName = 'Box'; - const contract = await deployer.loadArtifact(contractName); - const beacon = await hre.zkUpgrades.deployBeacon(deployer.zkWallet, contract); - await beacon.waitForDeployment(); - - const beaconAddress = await beacon.getAddress(); - - const boxBeaconProxy = await hre.zkUpgrades.deployBeaconProxy(deployer.zkWallet, beaconAddress, contract, [42]); - await boxBeaconProxy.waitForDeployment(); - - // upgrade beacon - const boxV2Implementation = await deployer.loadArtifact('BoxV2'); - await hre.zkUpgrades.upgradeBeacon(deployer.zkWallet, beaconAddress, boxV2Implementation); - console.info('Successfully upgraded beacon Box to BoxV2 on address: ', beaconAddress); - - const attachTo = new zk.ContractFactory( - boxV2Implementation.abi, - boxV2Implementation.bytecode, - deployer.zkWallet, - deployer.deploymentType - ); - const upgradedBox = attachTo.attach(await boxBeaconProxy.getAddress()); - - upgradedBox.connect(zkWallet); - // wait some time before the next call - await new Promise((resolve) => setTimeout(resolve, 2000)); - const value = await upgradedBox.retrieve(); - console.log('New box value is', value); -} - -main().catch((error) => { - console.error(error); - process.exitCode = 1; -}); -``` - -Run the script with: - -::: code-tabs - -@tab:active yarn - -```bash -yarn hardhat run SCRIPT_FILE -``` - -@tab npm - -```bash -npx hardhat run SCRIPT_FILE -``` - -::: - -# Proxy verification - -::: warning - -- To use proxy verification functionality, you must use the `hardhat-zksync-verify` plugin version >=0.1.8 ::: - -The hardhat-zksync-upgradable plugin supports proxy verification, which means you can verify all the contracts deployed -during the proxy deployment with a single verify command. - -To use the verification functionality, you first need to **import the `hardhat-zksync-verify plugin` before the -`hardhat-zksync-upgradable` plugin in your `hardhat.config.ts` file:** - -```typescript -... -// Imports the verify plugin before the upgradable plugin -import '@matterlabs/hardhat-zksync-verify'; -import '@matterlabs/hardhat-zksync-upgradable'; -... -``` - -To verify all the deployed contracts, simply run the verify command with the _proxy address_ as an argument: - -```sh -yarn hardhat verify -``` - -This command will verify the implementation related to the proxy, the proxy contract itself, and all the smart contracts -included in the specific deployment process, such as a proxy admin smart contract or a beacon smart contract. - -# Proxy validations - -The `hardhat-zksync-upgradable` plugin has built-in checks to ensure that your smart contract's newest implementation -version follows the necessary requirements when upgrading your smart contract. - -You can learn more about what those restrictions are in -[OpenZeppelin's documentation](https://docs.openzeppelin.com/upgrades-plugins/1.x/writing-upgradeable). - -# Proxy gas fee estimation - -Should you wish to estimate the total gas used throughout the proxy deployment process, consider utilizing the -upgradable plugin's gas estimation functions. We offer three types of gas estimation functions for your convenience: - -- estimateGasProxy -- estimateGasBeacon -- estimateGasBeaconProxy - -In the examples provided below, we will use the a Box contract and the deployer in the same way we used them in the -previous examples: - -```typescript -// mnemonic for local node rich wallet -const testMnemonic = 'stuff slice staff easily soup parent arm payment cotton trade scatter struggle'; -const zkWallet = Wallet.fromMnemonic(testMnemonic); - -const deployer = new Deployer(hre, zkWallet); - -const contractName = 'Box'; -const contract = await deployer.loadArtifact(contractName); -``` - -To estimate the deployment fee for the Transparent upgradable proxies and UUPS proxies, use the `estimateGasProxy` -method from the `zkUpgrades.estimation`. This method calculates the fee for deploying the implementation contract, -transparent proxy/UUPS contract, and the ProxyAdmin smart contract. - -::: code-tabs - -@tab:active Transparent proxy - -```typescript -const totalGasEstimation = await hre.zkUpgrades.estimation.estimateGasProxy(deployer, contract, [], { - kind: 'transparent', -}); -``` - -@tab UUPS proxy - -```typescript -const totalGasEstimation = await hre.zkUpgrades.estimation.estimateGasProxy(deployer, contract, [], { kind: 'uups' }); -``` - -::: - -To estimate the deployment fee for the beacon contract and its corresponding implementation, use the `estimateGasBeacon` -method: - -```typescript -const totalGasEstimation = await hre.zkUpgrades.estimation.estimateGasBeacon(deployer, contract, []); -``` - -If you want to get the estimation for the beacon proxy contract, please use the `estimateGasBeaconProxy` method: - -```typescript -const totalGasEstimation = await hre.zkUpgrades.estimation.estimateGasBeacon(deployer, contract, []); -``` - -Each of these methods totals the fee for every contract in their respective pipeline, displays the cost on the console, -and returns the cumulative sum. If you prefer not to see the individual estimations, introduce the parameter `quiet` as -the final parameter in any method to receive only the returned sum. - -```typescript -const totalGasEstimation = await hre.zkUpgrades.estimation.estimateGasProxy( - this.deployer, - contract, - [], - { kind: 'uups' }, - true -); -``` diff --git a/content/20.build/tooling/hardhat/hardhat-zksync-verify-vyper.md b/content/20.build/tooling/hardhat/hardhat-zksync-verify-vyper.md deleted file mode 100644 index f7fac119..00000000 --- a/content/20.build/tooling/hardhat/hardhat-zksync-verify-vyper.md +++ /dev/null @@ -1,207 +0,0 @@ -# `hardhat-zksync-verify-vyper` - -This plugin is used to verify vyper contracts on the zkSync Era network. - -:::warning Verification context Current version of the verify vyper plugin has a limitation where in order to verify the -vyper contract, verification request must be sent with exactly the same vyper smart contracts list in your project's -"contracts" folder, as it was during the deployment of that specific vyper contract.
- -This means that if you had both `VyperGreeterOne.vy` and `VyperGreeterTwo.vy` smart contracts in your project when you -deployed them, in order to verify each one of them separately, you will also need to have both of them in the project -when sending verification request. In any other situation, you will receive a message that contract's "bytecode doesn't -match any of your local contracts".
- -In order to minimize this risk, we strongly recommend you to verify your vyper smart contracts right after -their deployment!
- -::: - -:::warning Alpha release - -Because of verification context limitation, hardhat-zksync-verify-vyper plugin is still labeled as `alpha` and we do NOT -recommend using it in the production environment. On the other hand, we are working on removing this limitation and we -want to encourage you to give us your feedback on the plugin's functionalities, usability or possible improvements. -Please start or engage in the discussion about it in our -[Community Hub](https://github.com/zkSync-Community-Hub/zkync-developers/discussions), or open a Github issue in the -[project's repository](https://github.com/matter-labs/hardhat-zksync/issues). - -::: - -::: warning Version Compatibility Warning Ensure you are using the correct version of the plugin with ethers: - -- For plugin version **<1.0.0**: - - - Compatible with ethers **v5**. - -- For plugin version **≥1.0.0**: - - - Compatible with ethers **v6** (⭐ Recommended) - - ::: - -## Setup - -The [@matterlabs/hardhat-zksync-verify-vyper](https://www.npmjs.com/package/@matterlabs/hardhat-zksync-verify-vyper) -plugin is used to verify contracts on zkSync network. To use it, install plugin and then import -`@matterlabs/hardhat-zksync-verify-vyper` in the `hardhat.config.ts` file. - -::: code-tabs - -@tab:active yarn - -```bash -yarn add -D @matterlabs/hardhat-zksync-verify-vyper -``` - -@tab npm - -```bash -npm i -D @matterlabs/hardhat-zksync-verify-vyper -``` - -::: - -### Configuration - -Import the plugin in the `hardhat.config.ts` file: - -```javascript -import '@matterlabs/hardhat-zksync-verify-vyper'; -``` - -Add the `verifyURL` property to the zkSync Era network in the `hardhat.config.ts` file as shown below: - -```typescript -networks: { - sepolia: { - url: "https://sepolia.infura.io/v3/" // The Ethereum Web3 RPC URL (optional). - }, - zkTestnet: { - url: "https://sepolia.era.zksync.dev", // The testnet RPC URL of zkSync Era network. - ethNetwork: "sepolia", // The Ethereum Web3 RPC URL, or the identifier of the network (e.g. `mainnet` or `sepolia`) - zksync: true, - // Verification endpoint for Sepolia - verifyURL: 'https://explorer.sepolia.era.zksync.dev/contract_verification' - } -}, -// defaultNetwork: "zkTestnet", // optional (if not set, use '--network zkTestnet') -``` - -Additional network properties: - -- `zkTestnet` is an arbitrary zkSync Era network name. You can select this as the default network using the - `defaultNetwork` property. -- `url` is a field with the URL of the zkSync Era node. This field is required for all zkSync networks used by this - plugin. -- `ethNetwork` is a field with the URL of the Ethereum node. You can also provide network name (e.g. `sepolia`) as the - value of this field. In this case, the plugin will either use the URL of the appropriate Ethereum network - configuration (from the `networks` section), or the default `ethers` provider for the network if the configuration is - not provided. This field is required for all zkSync networks used by this plugin. -- `zksync` is a flag that indicates a zkSync Era network configuration. This field is set to `true` for all zkSync Era - networks. Field value `true` is required for this plugin work. If field is missing or if values is set to `false` - plugin will throw a error. -- `verifyURL` is a field that points to the verification endpoint for the specific zkSync network. This parameter is - optional, and its default value is the testnet verification url. - - Testnet: `https://explorer.sepolia.era.zksync.dev/contract_verification` - - Mainnet: `https://zksync2-mainnet-explorer.zksync.io/contract_verification` - -### Commands - -```sh -yarn hardhat verify:vyper --network -``` - -This command verifies the contract on the given network with the given contract's address.
When executed in this -manner, the verification task attempts to compare the compiled bytecode of all the contracts in your local environment -with the deployed bytecode of the contract you are seeking to verify. If there is no match, it reports an error. - -```sh -yarn hardhat verify:vyper --network --contract -``` - -With the `--contract` parameter you can also specify which contract from your local setup you want to verify by -specifying its Fully qualified name. Fully qualified name structure looks like this: "contracts/Contract.vy:Contract" -
- -#### Constructor arguments - -If your contract was deployed with specific constructor arguments, you need to specify them when running the verify -task. For example: - -```sh -yarn hardhat verify:vyper --network testnet 0x7cf08341524AAF292255F3ecD435f8EE1a910AbF "Hi there!" -``` - -If your constructor takes a complex argument list, you can write a separate Javascript module to export it. For example, -create an `arguments.js` file with the following structure: - -```typescript -module.exports = [ - 'a string argument', - '0xabcdef', - '42', - { - property1: 'one', - property2: 2, - }, -]; -``` - -Include it in the verify function call by adding a new parameter: `--constructor-args arguments.js`: - -```sh -yarn hardhat verify:vyper --network testnet 0x7cf08341524AAF292288F3ecD435f8EE1a910AbF --constructor-args arguments.js -``` - -The hardhat-zksync-verify plugin also supports the verification with encoded constructor parameters. - -In order to use the encoded parameters, you need to specify a separate javascript module and export them as a -_non-array_ parameter. It is important for encoded arguments to start with `0x` in order to be recognized by the -plugin. For example: - -```typescript -module.exports = - '0x0x00087a676164696a61310000087a676164696a61310000000000000000000000008537b364a83f5c9a7ead381d3baf9cbb83769bf5'; -``` - -### Verification status check - -The verification process consists of two steps: - -- A verification request is sent to confirm if the given parameters for your contract are correct. -- Then, we check the verification status of that request. Both steps run when you run the `verify:vyper` task, but you - will be able to see your specific verification request ID. You can then use this ID to check the status of your - verification request without running the whole process from the beginning. - -The following command checks the status of the verification request for the specific verification ID: - -```sh -yarn hardhat verify-status:vyper --verification-id -``` - -### Verify smart contract programmatically - -If you need to run the verification task directly from your code, you can use the hardhat `verify:verify:vyper` task -with the previously mentioned parameters. - -```typescript -const verificationId = await hre.run("verify:verify:vyper", { - address: contractAddress, - contract: contractFullyQualifedName, - constructorArguments: [...] -}); -``` - -This task returns a verification id if the request was successfully sent.
You can use this id to check the status -of your verification request as described in the section above. - -If you are using encoded constructor args, `constructorArguments` parameter should be a non-array value starting with -`0x`. - -```typescript -const verificationId = await hre.run('verify:verify:vyper', { - address: contractAddress, - contract: contractFullyQualifedName, - constructorArguments: '0x12345...', -}); -``` diff --git a/content/20.build/tooling/hardhat/hardhat-zksync-verify.md b/content/20.build/tooling/hardhat/hardhat-zksync-verify.md deleted file mode 100644 index b073d2a9..00000000 --- a/content/20.build/tooling/hardhat/hardhat-zksync-verify.md +++ /dev/null @@ -1,218 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: hardhat-zksync-verify | zkSync Docs ---- - -# `hardhat-zksync-verify` - -This plugin is used to verify contracts on the zkSync Era network. - -[Changelog](https://github.com/matter-labs/hardhat-zksync/blob/main/packages/hardhat-zksync-verify/CHANGELOG.md) - -::: warning Unknown zksolc version - -If you encounter this error, it suggests that the backend verification system does not currently support the latest -version of the zksolc compiler. In such cases, it may require some time for the backend to be updated to accommodate the -latest compiler version. - -As a temporary solution, please use previous versions of the compiler until the backend verification system is updated -to support the latest version. - -::: - -::: warning Version Compatibility Warning Ensure you are using the correct version of the plugin with ethers: - -- For plugin version **<1.0.0**: - - - Compatible with ethers **v5**. - -- For plugin version **≥1.0.0**: - - - Compatible with ethers **v6** (⭐ Recommended) - - ::: - -## Setup - -The [@matterlabs/hardhat-zksync-verify](https://www.npmjs.com/package/@matterlabs/hardhat-zksync-verify) plugin is used -in conjunction with [@nomicfoundation/hardhat-verify](https://www.npmjs.com/package/@nomicfoundation/hardhat-verify) and -it supports backward compatibility. To use it, install both plugins and then import `@matterlabs/hardhat-zksync-verify` -in the `hardhat.config.ts` file. - -::: code-tabs - -@tab:active yarn - -```bash -yarn add -D @matterlabs/hardhat-zksync-verify @nomicfoundation/hardhat-verify -``` - -@tab npm - -```bash -npm i -D @matterlabs/hardhat-zksync-verify -``` - -::: - -### Configuration - -Import the plugin in the `hardhat.config.ts` file: - -```javascript -import '@matterlabs/hardhat-zksync-verify'; -``` - -Add the `verifyURL` property to the zkSync Era network in the `hardhat.config.ts` file as shown below: - -```typescript -networks: { - sepolia: { - url: "https://sepolia.infura.io/v3/" // The Ethereum Web3 RPC URL (optional). - }, - zkTestnet: { - url: "https://sepolia.era.zksync.dev", // The testnet RPC URL of zkSync Era network. - ethNetwork: "sepolia", // The Ethereum Web3 RPC URL, or the identifier of the network (e.g. `mainnet` or `sepolia`) - zksync: true, - // Verification endpoint for Sepolia - verifyURL: 'https://explorer.sepolia.era.zksync.dev/contract_verification' - } -}, -// defaultNetwork: "zkTestnet", // optional (if not set, use '--network zkTestnet') -``` - -Additional network properties: - -- `zkTestnet` is an arbitrary zkSync Era network name. You can select this as the default network using the - `defaultNetwork` property. -- `url` is a field with the URL of the zkSync Era node in case of the zkSync Era network (with `zksync` flag set to - `true`), or the URL of the Ethereum node. This field is required for all zkSync Era and Ethereum networks used by this - plugin. -- `ethNetwork` is a field with the URL of the Ethereum node. You can also provide network name (e.g. `sepolia`) as the - value of this field. In this case, the plugin will either use the URL of the appropriate Ethereum network - configuration (from the `networks` section), or the default `ethers` provider for the network if the configuration is - not provided. This field is required for all zkSync networks used by this plugin. -- `zksync` is a flag that indicates a zkSync Era network configuration. This field is set to `true` for all zkSync Era - networks. If you want to run a `hardhat-verify` verification, this field needs to be set to `false`. If set to `true`, - the verification process will try to run the verification process on the zkSync Era network. -- `verifyURL` is a field that points to the verification endpoint for the specific zkSync network. This parameter is - optional, and its default value is the testnet verification url. - - Testnet: `https://explorer.sepolia.era.zksync.dev/contract_verification` - - Mainnet: `https://zksync2-mainnet-explorer.zksync.io/contract_verification` - -If you want to verify a smart contract on the Ethereum in the same project, it is important to add `etherscan` field and -API key in the `hardhat.config.ts` file: - -```typescript - -networks: { - ... -}, -etherscan: { - apiKey: //, -}, - -``` - -### Commands - -```sh -yarn hardhat verify --network -``` - -This command verifies the contract on the given network with the given contract's address.
When executed in this -manner, the verification task attempts to compare the compiled bytecode of all the contracts in your local environment -with the deployed bytecode of the contract you are seeking to verify. If there is no match, it reports an error. - -```sh -yarn hardhat verify --network --contract -``` - -With the `--contract` parameter you can also specify which contract from your local setup you want to verify by -specifying its Fully qualified name. Fully qualified name structure looks like this: -"contracts/AContract.sol:TheContract"
- -#### Constructor arguments - -If your contract was deployed with the specific constructor arguments, you need to specify them when running the verify -task. For example: - -```sh -yarn hardhat verify --network testnet 0x7cf08341524AAF292255F3ecD435f8EE1a910AbF "Hi there!" -``` - -If your constructor takes a complex argument list, you can write a separate javascript module to export it. For example, -create an `arguments.js` file with the following structure: - -```typescript -module.exports = [ - 'a string argument', - '0xabcdef', - '42', - { - property1: 'one', - property2: 2, - }, -]; -``` - -Include it in the verify function call by adding a new parameter: `--constructor-args arguments.js`: - -```sh -yarn hardhat verify --network testnet 0x7cf08341524AAF292288F3ecD435f8EE1a910AbF --constructor-args arguments.js -``` - -The hardhat-zksync-verify plugin also supports the verification with encoded constructor parameters. - -In order to use the encoded parameters, you need to specify a separate javascript module and export them as a -_non-array_ parameter. It is important for encoded arguments to start with `0x` in order to be recognized by the -plugin. For example: - -```typescript -module.exports = - '0x0x00087a676164696a61310000087a676164696a61310000000000000000000000008537b364a83f5c9a7ead381d3baf9cbb83769bf5'; -``` - -### Verification status check - -The verification process consists of two steps: - -- A verification request is sent to confirm if the given parameters for your contract are correct. -- Then, we check the verification status of that request. Both steps run when you run the `verify` task, but you will be - able to see your specific verification request ID. You can then use this ID to check the status of your verification - request without running the whole process from the beginning. - -The following command checks the status of the verification request for the specific verification ID: - -```sh -yarn hardhat verify-status --verification-id -``` - -### Verify smart contract programmatically - -If you need to run the verification task directly from your code, you can use the hardhat `verify:verify` task with the -previously mentioned parameters with the difference in using `--address` parameter when specifying contract's address. - -```typescript -const verificationId = await hre.run("verify:verify", { - address: contractAddress, - contract: contractFullyQualifedName, - constructorArguments: [...] -}); -``` - -This task returns a verification id if the request was successfully sent.
You can use this id to check the status -of your verification request as described in the section above. - -If you are using encoded constructor args, `constructorArguments` parameter should be a non-array value starting with -`0x`. - -```typescript -const verificationId = await hre.run('verify:verify', { - address: contractAddress, - contract: contractFullyQualifedName, - constructorArguments: '0x12345...', -}); -``` diff --git a/content/20.build/tooling/hardhat/hardhat-zksync-vyper.md b/content/20.build/tooling/hardhat/hardhat-zksync-vyper.md deleted file mode 100644 index 79962837..00000000 --- a/content/20.build/tooling/hardhat/hardhat-zksync-vyper.md +++ /dev/null @@ -1,116 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: hardhat-zksync-vyper | zkSync Docs ---- - -# `hardhat-zksync-vyper` - -The [@matterlabs/hardhat-zksync-vyper](https://www.npmjs.com/package/@matterlabs/hardhat-zksync-vyper) plugin provides -an interface for compiling Vyper smart contracts before deploying them to zkSync Era. - -Learn more about the latest updates in the -[changelog](https://github.com/matter-labs/hardhat-zksync/blob/main/packages/hardhat-zksync-vyper/CHANGELOG.md). - -## Prerequisite - -To use the `hardhat-zksync-vyper` in your project, we recommend that: - -- You have a Node installation and `yarn` or `npm` package manager. - -## Installation - -[@matterlabs/hardhat-zksync-vyper](https://www.npmjs.com/package/@matterlabs/hardhat-zksync-vyper) - -Add the latest version of this plugin to your project with the following command: - -::: code-tabs - -@tab:active yarn - -```bash -yarn add -D @matterlabs/hardhat-zksync-vyper @nomiclabs/hardhat-vyper -``` - -@tab npm - -```bash -npm i -D @matterlabs/hardhat-zksync-vyper -``` - -::: - -## Configuration - -::: info zero-config - -`hardhat-zksync-vyper` v0.2.0 introduced a default configuration so all parameters are optional. - -::: - -Any configuration parameters should be added inside a `zkvyper` property in the `hardhat.config.ts` file: - -```typescript -zkvyper: { - version: "latest", // Uses latest available in https://github.com/matter-labs/zkvyper-bin/ - settings: { - // compilerPath: "zkvyper", // optional field with the path to the `zkvyper` binary. - libraries: {}, // optional. References to non-inlinable libraries - optimizer: { - mode: '3' // optional. 3 by default, z to optimize bytecode size - fallback_to_optimizing_for_size: false, // optional. Try to recompile with optimizer mode "z" if the bytecode is too large - }, - experimental: { - dockerImage: '', // deprecated - tag: '' // deprecated - }, - }, - } -``` - -::: warning - -- Compilers are no longer released as Docker images and its usage is no longer recommended. - -::: - -- `version`: The `zkvyper` compiler version. Default value is `latest`. Find the latest compiler versions in the - [zkvyper repo](https://github.com/matter-labs/zkvyper-bin). -- `compilerSource`: Indicates the compiler source and can be either `binary`. (A `docker` option is no longer - recommended). If there is no previous installation, the plugin automatically downloads one. -- `optimizer` - Compiler optimizations: - - `mode`: `3` (default) recommended for most projects. Mode `z` reduces bytecode size for large projects that make - heavy use of `keccak` and far calls. - - `fallback_to_optimizing_for_size` (optional) indicates that the compiler will try to recompile with optimizer mode - "z" if the bytecode is too large. -- `compilerPath`: Optional field with the path to the `zkvyper` binary. By default, the binary in `$PATH` is used. -- `libraries`: Define any non-inlinable libraries your contracts use as dependencies here. Learn more about - [compiling libraries](./compiling-libraries.md). - -::: warning fallback_to_optimizing_for_size usage - -`fallback_to_optimizing_for_size` option is supported for zkvyper compiler version 1.3.15 or higher. - -::: - -## Commands - -::: code-tabs - -@tab:active yarn - -```bash -yarn hardhat compile -``` - -@tab npm - -```bash -npx hardhat compile -``` - -::: - -Compiles all the smart contracts in the `contracts` directory and creates the `artifacts-zk` folder with all the -compilation artifacts, including factory dependencies for the contracts, which could be used for contract deployment. diff --git a/content/20.build/tooling/hardhat/migrating-to-zksync.md b/content/20.build/tooling/hardhat/migrating-to-zksync.md deleted file mode 100644 index ca99365e..00000000 --- a/content/20.build/tooling/hardhat/migrating-to-zksync.md +++ /dev/null @@ -1,278 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Migration Guide | zkSync Docs ---- - -# Migration guide - -::: warning Windows as platform If you are using Windows, we strongly recommend you use Windows Subsystem for Linux -(also known as WSL 2). You can use `Hardhat` and `Hardhat zkSync plugins` without it, but it will work better if you use -it. - -To install Node.js using WSL 2, please read this -[guide](https://learn.microsoft.com/en-us/windows/dev-environment/javascript/nodejs-on-wsl) ::: - -This guide shows you how to migrate an existing Hardhat project to zkSync Era. - -## Overview - -zkSync Era offers [multiple Hardhat plugins](../hardhat/getting-started.md) with different features. This guide details -the one you need to migrate your project to zkSync Era. - -::: warning Non-default paths are not supported yet - -- Contract files must be included in the `contracts` folder and deployment scripts must be included in the `deploy` - folder. -- Support for custom paths will be included in the future. ::: - -## Install dependencies - -Although zkSync Era is [compatible with Solidity and Vyper](../../developer-reference/contract-development.md), the -deployed bytecode and the deployment process is different from Ethereum or other EVM blockchains. So the first step is -to install the compiler and deployer Hardhat plugins: - -::: code-tabs - -@tab:active yarn - -```bash -yarn add -D @matterlabs/hardhat-zksync-deploy @matterlabs/hardhat-zksync-solc -``` - -@tab npm - -```bash -npm i -D @matterlabs/hardhat-zksync-deploy @matterlabs/hardhat-zksync-solc -``` - -::: - -If you're using Vyper, replace `@matterlabs/hardhat-zksync-solc` with `@matterlabs/hardhat-zksync-vyper` - -## Configuration changes - -In your `hardhat.config.ts` file import the installed dependencies: - -```typescript -import '@matterlabs/hardhat-zksync-deploy'; -import '@matterlabs/hardhat-zksync-solc'; -``` - -Networks on zkSync Era require two different URL endpoints: one for layer 1 (Ethereum or Sepolia), and one for layer 2 -(zkSync). This is how you add the zkSync Era testnet to your list of networks in the `hardhat.config.ts`: - -```typescript -const config: HardhatUserConfig = { - networks: { - hardhat: { - zksync: false, - }, - zkSyncTestnet: { - url: 'https://sepolia.era.zksync.dev', - ethNetwork: 'sepolia', // or a Sepolia RPC endpoint from Infura/Alchemy/Chainstack etc. - zksync: true, - }, - }, - defaultNetwork: 'zkSyncTestnet', - // configuration continues .... -}; -``` - -::: tip Remember to add `zksync: false` to any other networks. ::: - -Finally, add the compiler options inside a `zksolc` or `zkvyper` property. Here is the minimal configuration for a -Solidity project: - -```typescript -zksolc: { - version: "latest", - settings: {}, -}, -``` - -For more advanced settings, check out the [Solidity](./hardhat-zksync-solc.md) or [Vyper](./hardhat-zksync-vyper.md) -plugins. - -### How to configure multiple compilation targets - -To configure the `hardhat.config.ts` file to target both zkSync Era and other networks, do the following: - -1. In your `hardhat.config.ts`, configure the zkSync Era network with `zksync: true`. -2. Configure all other networks with `zksync: false`. -3. Run the compilation or deployment scripts with the network flag: `yarn hardhat compile --network zkSyncTestnet` for - zkSync Era network or `yarn hardhat compile --network sepolia` for other networks, e.g sepolia. - -```typescript -networks: { - sepolia: { - url: "https://sepolia.infura.io/v3/", // The Ethereum Web3 RPC URL. - zksync: false, // Set to false to target other networks. - }, - zkSyncTestnet: { - url: "https://sepolia.era.zksync.dev", // The testnet RPC URL of zkSync Era network. - ethNetwork: "sepolia", // The identifier of the network (e.g. `mainnet` or `sepolia`) - zksync: true, // Set to true to target zkSync Era. - } -}, - -``` - -### Full configuration - -Here is an example config file: - -```typescript -import { HardhatUserConfig } from 'hardhat/config'; - -import '@matterlabs/hardhat-zksync-deploy'; -import '@matterlabs/hardhat-zksync-solc'; - -const config: HardhatUserConfig = { - zksolc: { - version: 'latest', // Uses latest available in https://github.com/matter-labs/zksolc-bin/ - settings: {}, - }, - defaultNetwork: 'zkSyncTestnet', - networks: { - hardhat: { - zksync: false, - }, - sepolia: { - url: 'https://sepolia.com/api/abcdef12345', - zksync: false, - }, - mainnet: { - url: 'https://ethereum.mainnet.com/api/abcdef12345', - zksync: false, - }, - zkSyncTestnet: { - url: 'https://sepolia.era.zksync.dev', - ethNetwork: 'sepolia', // or a Sepolia RPC endpoint from Infura/Alchemy/Chainstack etc. - zksync: true, - }, - }, - solidity: { - version: '0.8.13', - }, - // OTHER SETTINGS... -}; - -export default config; -``` - -## Compile contracts - -To compile your contracts for zkSync Era, run: - -::: code-tabs - -@tab:active yarn - -```bash -yarn hardhat compile --network zkSyncTestnet -``` - -@tab npm - -```bash -npm hardhat compile --network zkSyncTestnet -``` - -::: - -Passing the `--network` flag we make sure Hardhat will use the zksolc compiler (or zkvyper). This command will compile -all contracts in the `/contracts` folder and create the folders `artifacts-zk` and `cache-zk`. - -If your contracts import any non-inlineable libraries, you need to configure them in the `hardhat.config.ts` file. Find -more info and examples about [compiling libraries here](./compiling-libraries.md). - -## Deploy contracts - -::: tip `hardhat-deploy` support `hardhat-deploy` version `^0.11.26` supports deployments on zkSync Era. ::: - -To deploy your contracts you need to use the `Deployer` class from the `hardhat-zksync-deploy` plugin. This class takes -care of all the specifics of [deploying contracts on zkSync](../../developer-reference/contract-deployment.md). - -Here is a basic deployment script for a `Greeter` contract: - -```typescript -import { utils, Wallet } from 'zksync-ethers'; -import * as ethers from 'ethers'; -import { HardhatRuntimeEnvironment } from 'hardhat/types'; -import { Deployer } from '@matterlabs/hardhat-zksync-deploy'; - -// An example of a deploy script that will deploy and call a simple contract. -export default async function (hre: HardhatRuntimeEnvironment) { - console.log(`Running deploy script`); - - // Initialize the wallet. - const wallet = new Wallet(''); - - // Create deployer object and load the artifact of the contract we want to deploy. - const deployer = new Deployer(hre, wallet); - // Load contract - const artifact = await deployer.loadArtifact('Greeter'); - - // Deploy this contract. The returned object will be of a `Contract` type, - // similar to the ones in `ethers`. - const greeting = 'Hi there!'; - // `greeting` is an argument for contract constructor. - const greeterContract = await deployer.deploy(artifact, [greeting]); - - // Show the contract info. - console.log(`${artifact.contractName} was deployed to ${await greeterContract.getAddress()}`); -} -``` - -::: tip Test ETH To obtain Sepolia ETH please refer to the [network faucets page](../network-faucets.md) for more info. -
To transfer Sepolia ETH to zkSync testnet use [bridges](https://zksync.io/explore#bridges). ::: - -Include your deployment script in the `deploy` folder and execute it running: - -::: code-tabs - -@tab:active yarn - -```bash -yarn hardhat deploy-zksync --script SCRIPT_FILENAME.ts --network zkSyncTestnet -``` - -@tab npm - -```bash -npm hardhat deploy-zksync --script SCRIPT_FILENAME.ts --network zkSyncTestnet -``` - -::: - -If you don't include the `--script` option, all script files inside the `deploy` folder will be executed in alphabetical -order. - -Check out a detailed [approach](./hardhat-zksync-deploy.md) on how to use `hardhat-zksync-deploy` plugin. - -## Frontend integration - -You can interact with your contracts using the `zksync-ethers` Javascript library. This SDK has been built on top of -ethers and uses the same classes (`Provider`, `Contract`, `Wallet`) so in a lot of cases, you just need to import these -classes from `zksync-ethers` instead of `ethers`: - -```typescript -//import { utils, Provider, Contract, Wallet } from "ethers"; -import { utils, Provider, Contract, Wallet } from 'zksync-ethers'; -``` - -You also need to use the `contract ABI` from the `artifacts-zk` folder to instantiate contracts. - -Apart from the same classes and methods provided by ethers, zksync-ethers includes additional methods for -zksync-specific features. You can read more in the [`zksync-ethers` documentation](../../sdks/js/getting-started.md). - -## Verify contracts - -To verify your contracts you have two options: - -- Explorer: verify your contracts manually in the [zkSync explorer](../block-explorer/contract-verification.md) -- Plugin: verify your contracts programmatically using the [Hardhat verify plugin](./hardhat-zksync-verify.md) - -If you have any problems migrating your project, [send us a message on Discord](https://join.zksync.dev/). diff --git a/content/20.build/tooling/hardhat/other-plugins.md b/content/20.build/tooling/hardhat/other-plugins.md deleted file mode 100644 index 509a4681..00000000 --- a/content/20.build/tooling/hardhat/other-plugins.md +++ /dev/null @@ -1,79 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Hardhat Community Plugins | zkSync Docs ---- - -# Community plugins - -The following plugins were created by the community and tested on zkSync Era. Feel free to suggest new plugins by -[creating a issue(feat request) at this page](https://github.com/matter-labs/hardhat-zksync/issues/new?assignees=&labels=feat&projects=&template=feature_report.md&title=). - -## Supported plugins - -::: tip Example project - -Here is -[a template project configured with all plugins mentioned below](https://github.com/matter-labs/era-hardhat-with-plugins). -You can use it as a starting template for your projects. - -::: - -### hardhat-deploy - -Multiple tasks for advanced deployments. - -This plugin was [updated to support zkSync Era](https://github.com/wighawag/hardhat-deploy/pull/437) on version -`0.11.26`. - -[More information](https://www.npmjs.com/package/hardhat-deploy) - -### typechain/hardhat - -Automatically generate TypeScript bindings for smart contracts. - -[More information](https://www.npmjs.com/package/@typechain/hardhat) - -### openzeppelin/hardhat-upgrades - -Plugin used to deploy and update upgradable smart contracts (proxies). Use the -[hardhat-zksync-upgradable plugin](./hardhat-zksync-upgradable.md) which provides an easy-to-use interface for -interacting with the OpenZeppelin Upgrades Plugins within a Hardhat environment on zkSync. - -### hardhat-contract-sizer - -Generates a report of the bytecode size of the contracts in your project. - -[More information](https://www.npmjs.com/package/hardhat-contract-sizer) - -### hardhat-abi-exporter - -Different options to export smart contract ABIs. - -[More information](https://www.npmjs.com/package/hardhat-abi-exporter) - -### hardhat-gas-reporter - -Although this plugin works out of the box, zkSync Era has a -[different fee model](../../developer-reference/fee-model.md) than Ethereum. Users should consider this when analysing -the report generated by this plugin. - -In addition, make sure to read about [local testing](../../test-and-debug/getting-started.md). - -[More information](https://www.npmjs.com/package/hardhat-gas-reporter) - -## Unsupported plugins - -### nomicfoundation/hardhat-network-helpers - -This plugin adds new methods that interact with the Hardhat network used for testing. - -However, we do not recommend using the Hardhat network for testing contracts that will be deployed on zkSync Era. We -recommend instead using the [in-memory node](../../test-and-debug/era-test-node.md) or the -[docker setup to test your contracts](../../test-and-debug/dockerized-l1-l2-nodes.md) as they will give you the same -results as our testnet/mainnet. - -::: warning The additional methods provided by this plugin are not compatible with the zkSync Era in-memory node or -docker setup yet. Currently, we are working on adapting our in-memory node to ensure compatibility with -hardhat-network-helpers. ::: diff --git a/content/20.build/tooling/ide.md b/content/20.build/tooling/ide.md deleted file mode 100644 index 7c449692..00000000 --- a/content/20.build/tooling/ide.md +++ /dev/null @@ -1,30 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: IDE | zkSync Docs ---- - -# IDE - -### Overview - -Welcome to the **IDE page**, a comprehensive hub dedicated to interacting with ready-to-use interactive developer -environments using zkSync Era. Each guide has been curated to offer hands-on examples, ensuring that both newcomers and -experienced developers can seamlessly get started with developing on zkSync Era. - -### Atlas IDE - -[**Atlas**](https://www.atlaszk.com/) provides a robust and user-friendly environment to write, test, and deploy your -smart contracts in a matter of minutes. Discover the potential and get started with Atlas today and deploy your first -contract on zkSync Era by following this [video tutorial](https://www.youtube.com/watch?v=TL-QnxoPyUY)! - -### Remix IDE - -The [Remix](https://remix.ethereum.org/) plugin for zkSync Era is live, providing a smooth, user-friendly interface for -developers of all skill levels to engage with the zkSync ecosystem. The plugin simplifies the writing and deployment of -zkSync’s smart contracts, making it accessible to newcomers and experienced users. - -Follow the -[The zkSync Era Remix Plugin: A How-To Guide](https://medium.com/nethermind-eth/the-zksync-era-remix-plugin-a-how-to-guide-fc54e8d24bd3), -written by [Nethermind](https://twitter.com/NethermindEth), the team who developed the plugin. diff --git a/content/20.build/tooling/monitoring.md b/content/20.build/tooling/monitoring.md deleted file mode 100644 index 8fafd819..00000000 --- a/content/20.build/tooling/monitoring.md +++ /dev/null @@ -1,29 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Monitoring | zkSync Docs ---- - -# Monitoring - -Monitoring is a crucial aspect of the development and maintenance phases for any blockchain network. It provides -insights into the performance, health, and other operational aspects of the network and applications. In this section, -we explore key tools that offer monitoring solutions, aiding developers in keeping a close watch on their projects -within the zkSync ecosystem. These tools provide a platform for analytics, real-time monitoring, and data aggregation -which are essential for making informed decisions. - -#### Dune Analytics - -[Dune Analytics](https://dune.xyz/docs) is a web-based platform tailored for querying public blockchain data and -aggregating it into visually appealing dashboards. With blockchain networks being open and transparent yet unique, Dune -Analytics provides the necessary tools for cross-chain data analysis covering various tokens, wallets, and protocols. It -also fosters a community-centric environment by allowing users to share their analytical work effortlessly. - -#### Zetta Blocks - -[Zetta Blocks](https://www.zettablock.com/) stands as an enterprise-grade, full-stack Web3 infrastructure focusing on -indexing and analytics while bridging on-chain and off-chain data. It empowers developers to construct real-time, -reliable GraphQL APIs via SQL swiftly, eliminating the concerns of data processing on both frontends and backends. Zetta -Blocks is an epitome of how seamless monitoring and analytics can be integrated into the blockchain development -workflow. diff --git a/content/20.build/tooling/network-faucets.md b/content/20.build/tooling/network-faucets.md deleted file mode 100644 index 768fd345..00000000 --- a/content/20.build/tooling/network-faucets.md +++ /dev/null @@ -1,30 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Network Faucets | zkSync Docs ---- - -# Network Faucets - -To access the testnet funds (Sepolia) you can use one of the following third party faucets: - -## LearnWeb3 - -You can use [LearnWeb3's zkSync Sepolia Faucet](https://learnweb3.io/faucets/zksync_sepolia/) to claim zkSync Sepolia -Testnet **0.01 ETH per day**. - -## zkSync testnet faucet by Chainstack - -[Chainstack Faucet](https://faucet.chainstack.com/zksync-testnet-faucet) is an easy to use Multi-Chain Faucet. You can -use Chainstack Faucet to claim zkSync Sepolia Testnet **0.05 ETH every 24 hours**. Chainstack API key is required. - -## Sepolia faucets - -Use any of the following faucets to claim SepoliaETH, which you can bridge to zkSync testnet using the -[TxSync bridge](https://portal.txsync.io/bridge/?network=era-sepolia). - -- [LearnWeb3 Sepolia Faucet](https://learnweb3.io/faucets/sepolia) -- [QuickNode Sepolia faucet](https://faucet.quicknode.com/ethereum/sepolia) -- [Alchemy Sepolia faucet](https://sepoliafaucet.com/) -- [Proof of Work Sepolia faucet](https://sepolia-faucet.pk910.de/) diff --git a/content/20.build/tooling/nft-marketplaces.md b/content/20.build/tooling/nft-marketplaces.md deleted file mode 100644 index 14921def..00000000 --- a/content/20.build/tooling/nft-marketplaces.md +++ /dev/null @@ -1,43 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: NFT Marketplaces | zkSync Docs ---- - -# NFT Marketplaces - -The following NFT marketplaces are specialized in facilitating the trade, creation, and management of NFTs. These -platforms offer distinct features and benefits. - -### Element - -[Element](https://element.market/) is a community-driven aggregated marketplace where you can buy and sell NFTs across -different platforms, save money, and earn rewards.\ -**Specialty**: Aggregated Marketplace, Rewards - -### Kreatorland - -[Kreatorland](https://kreatorland.com/) is a native NFT marketplace built specifically for the zkSync Era.\ -**Specialty**: zkSync Era Native - -### OKX NFT - -[OKX NFT](https://www.okx.com/web3/marketplace/nft) serves as a one-stop decentralized NFT market, allowing you to -create and trade NFTs across multiple blockchains and platforms.\ -**Specialty**: Multi-Blockchain, One-Stop Market - -### Tevaera - -[Tevaera](https://market.tevaera.com/) is the first paymasters and ONFT powered marketplace on the zkSync Era. It offers -the lowest transaction fees while being fully secured by the Ethereum consensus.\ -**Specialty**: zkSync Era, Low Fees, Paymasters and ONFT - -### Zonic - -[Zonic](https://zonic.app/) supports the Ethereum Layer-2 ecosystem by providing a platform where individuals can -construct their own NFT projects and exchange them through an intuitive user interface.\ -**Specialty**: Ethereum Layer-2, User-Centric Design - -Choose a marketplace that aligns with your requirements, whether it's low fees, multi-blockchain support, or specific -zkSync Era functionalities. Always perform your own due diligence before using any third-party platforms. diff --git a/content/20.build/tooling/node-providers.md b/content/20.build/tooling/node-providers.md deleted file mode 100644 index 163e381d..00000000 --- a/content/20.build/tooling/node-providers.md +++ /dev/null @@ -1,55 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: RPC Providers | zkSync Docs ---- - -# RPC Providers - -### Ankr - -[Ankr](https://www.ankr.com/rpc/base/) provides private and public RPC endpoints for Base, powered by a globally -distributed and decentralized network of nodes. They offer free and [paid plans](https://www.ankr.com/rpc/pricing/) with -increased request limits. - -### BlockPI - -[BlockPI](https://blockpi.io/) is a high-quality, robust, and efficient RPC service network that provides access to Base -nodes with [free and paid plans](https://docs.blockpi.io/documentations/pricing). - -### Chainstack - -[Chainstack](https://chainstack.com/) is a leading blockchain infrastructure providing company. Build, run and scale -blockchain applications using Chainstack nodes. - -### Chainbase - -[Chainbase](https://chainbase.com/) API is supercharged for reliability, data correctness, and scalability. Chainbase -will handle all the forks, upgrades, and network interruptions - -### DRPC - -[DRPC](https://drpc.org/public-endpoints/zksync) offers access to distributed network of independent third-party -partners and public nodes for Base. They provide a free tier that allows for an unlimited amount of requests over public -nodes, or a paid tier which provides access to all providers, as well as other additional features. - -### Quicknode - -[QuickNode](https://www.quicknode.com/chains/base) offers access to hosted Base nodes as part of their free Discover -Plan. You can configure add-ons, like "Trace Mode" and "Archive Mode" for an additional cost by upgrading to one of -their paid plans. - -### Unifra - -[Unifra](https://base.unifra.io/) is a Web3 developer platform that provides tools, APIs, and node infrastructure, and -provides access to Base nodes that are nodes are reliabile, scalable, and easy to use. - -### Public RPCs - -| Mainnet | Testnet | -| ---------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- | -| [https://mainnet.era.zksync.io](https://mainnet.era.zksync.io) | [https://sepolia.era.zksync.dev](https://sepolia.era.zksync.dev) | -| [https://zksync.drpc.org](https://zksync.drpc.org) | [https://zksync-era-sepolia.blockpi.network/v1/rpc/public](https://zksync-era-sepolia.blockpi.network/v1/rpc/public) | -| [https://zksync.meowrpc.com](https://zksync.meowrpc.com) | | -| [https://zksync-era.blockpi.network/v1/rpc/public](https://zksync-era.blockpi.network/v1/rpc/public) | | diff --git a/content/20.build/tooling/oracles.md b/content/20.build/tooling/oracles.md deleted file mode 100644 index 0da88584..00000000 --- a/content/20.build/tooling/oracles.md +++ /dev/null @@ -1,43 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Oracles | zkSync Docs ---- - -# Oracles - -### **Overview** - -Welcome to the Oracles page, a comprehensive hub dedicated to interacting with oracle services on zkSync Era. As the -demand for decentralized applications continues, the need for reliable and efficient oracle services becomes paramount. -Within these sections, you'll unearth specialized usage guides and tangible examples designed to facilitate seamless -interactions with a variety of different oracle services. - -### DIA - -[DIA](https://docs.diadata.org/products/token-price-feeds) token price feeds provide smart contract real-time price -information of 3,000+ cryptocurrencies, transparently sourced from 80+ trusted, high-volume DEXs and CEXs. Check out the -usage guide below to get started today! - -### Redstone - -[Redstone](https://docs.redstone.finance/docs/introduction) delivers frequently updated, reliable, and diverse data -feeds for your dApp and smart contracts. Check out all the price feeds available to zkSync Era and get started with the -provided usage guide. - -### Pyth - -[Pythnet](https://docs.pyth.network/documentation/pythnet-price-feeds) price feeds use a "pull" price update model, -where users are responsible for posting price updates on-chain when needed. Checkout the usage guide to get started -today! - -### Usage guides - -- [redstone](../tutorials/tooling-guides/redstone.md) - -### Contribute - -We believe in collective growth. If you've traversed the oracles' maze and have insights or guides to share, we urge you -to contribute. Your knowledge could be the beacon for many. Let's co-create and expand the repository of oracle wisdom -on zkSync Era. diff --git a/content/20.build/tooling/wallets.md b/content/20.build/tooling/wallets.md deleted file mode 100644 index 401026e9..00000000 --- a/content/20.build/tooling/wallets.md +++ /dev/null @@ -1,72 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Wallets | zkSync Docs ---- - -# Wallets - -The following wallets are known for their robustness, ease of use, and compatibility with zkSync Era. These wallets -offer various features including, but not limited to, DeFi, NFT management, and multiple chain support. - -### BlockWallet - -[BlockWallet](https://blockwallet.io/networks/zksync-wallet) is designed for zkSync users seeking a decentralized wallet -in a user-friendly package.\ -**Availability**: Chrome extension - -### Echoo - -[Echoo](https://www.echooo.xyz/) combines MPC and AI technologies to offer a next-generation AA smart contract wallet -with low-cost Layer 2 capabilities.\ -**Availability**: App store, Google Play - -### Enkrypt - -[Enkrypt](https://www.enkrypt.com/networks/zksync-wallet/) provides native support for zkSync and enables seamless -building and deployment on zkSync.\ -**Availability**: Browser extension (all browsers) - -### Holdstation - -[Holdstation](https://holdstation.com/) emphasizes self-custodial and private transactions, driven by Account -Abstraction and Layer-2 solutions.\ -**Availability**: App store, Google Play - -### MetaMask - -[MetaMask](https://metamask.io/) is a popular crypto wallet offering a wide range of features and is trusted by over 30 -million users worldwide.\ -**Availability**: Browser extension - -### OKX Wallet - -[OKX Wallet](https://www.okx.com/web3) offers a diverse range of Web3 functionalities at your fingertips.\ -**Availability**: Mobile, Desktop, Chrome Extension - -### Pier Wallet - -[Pier Wallet](https://www.pierwallet.com/) enables Web3 integration through its leading smart contract wallet as a -service.\ -**Availability**: Web app - -### Rabby Wallet - -[Rabby Wallet](https://rabby.io/) is an open-source browser plugin that facilitates a secure multi-chain experience in -the DeFi ecosystem.\ -**Availability**: Chrome extension, Desktop (macOS, Windows) - -### YaspFi - -[YaspFi](https://yasp.fi/) is focused on sustainable DeFi yield and offers an all-in-one solution.\ -**Availability**: Web App, Chrome browser extension - -### Zerion - -[Zerion](https://zerion.io/) enables you to manage your DeFi and NFT portfolios, trade across 10+ networks, and connect -to decentralized applications.\ -**Availability**: Web, Android, iOS, macOS - -Choose a wallet based on your specific requirements for transaction types, chain support, and additional -functionalities. Always remember to conduct your own due diligence before using any third-party service. diff --git a/content/20.build/tooling/zksync-cli/commands/bridge.md b/content/20.build/tooling/zksync-cli/commands/bridge.md deleted file mode 100644 index 03969295..00000000 --- a/content/20.build/tooling/zksync-cli/commands/bridge.md +++ /dev/null @@ -1,110 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Bridge Operations with zksync-cli | zkSync Docs ---- - -# Bridge operations with zksync-cli - -Leverage the [zksync-cli](../../zksync-cli/getting-started.md) to facilitate bridge operations between Ethereum (L1) and -zkSync (L2), including token deposits, withdrawals, and finalizing withdrawals. - -### Prerequisites - -Before you start, make sure you have installed: - -- [Node.js v18+](https://nodejs.org/en) - -### Table of contents - -- [Bridge Deposit](#bridge-deposit) - - [Deposit Options](#deposit-options) - - [Depositing ERC-20 Tokens](#depositing-erc-20-tokens) -- [Bridge Withdraw](#bridge-withdraw) - - [Withdraw Options](#withdraw-options) - - [Withdrawing ERC-20 Tokens](#withdrawing-erc-20-tokens) -- [Withdraw Finalize](#withdraw-finalize) - - [Finalize Withdraw Options](#finalize-withdraw-options) -- [Troubleshooting](#troubleshooting) - -## Bridge Deposit - -Transfer ETH from L1 to L2 using the deposit command. - -```bash -npx zksync-cli bridge deposit -``` - -### Deposit Options - -If options are not specified, you will be prompted to enter them. - -- `--to, --recipient <0x address>`: Recipient address on L2. -- `--amount <0.1>`: Amount to deposit. -- `--token <0x address>`: ERC-20 token address. -- `--pk, --private-key `: Private key of the sender. -- `--chain `: Chain to use. -- `--l1-rpc `: Override L1 RPC URL. -- `--rpc `: Override L2 RPC URL. - -### Depositing ERC-20 Tokens - -To deposit ERC-20 tokens, include the `--token` option with the token's contract address: - -```bash -npx zksync-cli bridge deposit --token 0x3e622317f8C93f7328350cF0B56d9eD4C620C5d6 -``` - -## Bridge Withdraw - -Transfer tokens from L2 back to L1. - -```bash -npx zksync-cli bridge withdraw -``` - -### Withdraw Options - -You will be prompted to enter options if they are not specified. - -- `--to, --recipient <0x address>`: Recipient address on L1. -- `--amount <0.1>`: Amount to withdraw. -- `--token <0x address>`: ERC-20 token address (omit this option to withdraw ETH). -- `--pk, --private-key `: Private key of the sender. -- `--chain `: Chain to use. -- `--l1-rpc `: Override L1 RPC URL. -- `--rpc `: Override L2 RPC URL. - -### Withdrawing ERC-20 Tokens - -For withdrawing ERC-20 tokens, specify the token address using the `--token` option: - -```bash -npx zksync-cli bridge withdraw --token 0x3e622317f8C93f7328350cF0B56d9eD4C620C5d6 -``` - -## Withdraw Finalize - -Finalize the withdrawal of funds with the following command. This step is necessary to complete the withdrawal process -initiated on L2. - -```bash -npx zksync-cli bridge withdraw-finalize -``` - -### Finalize Withdraw Options - -Options will be prompted if not specified. - -- `--hash `: L2 withdrawal transaction hash to finalize. -- `--pk, --private-key `: Private key of the sender. -- `--chain `: Chain to use. -- `--l1-rpc `: Override L1 RPC URL. -- `--rpc `: Override L2 RPC URL. - -## Troubleshooting - -If you encounter any issues, please consult our [troubleshooting guide](../../zksync-cli/troubleshooting.md) or report -them in our -[GitHub discussions](https://github.com/zkSync-Community-Hub/zksync-developers/discussions/new?category=general). diff --git a/content/20.build/tooling/zksync-cli/commands/contract-interaction.md b/content/20.build/tooling/zksync-cli/commands/contract-interaction.md deleted file mode 100644 index 271d5ff8..00000000 --- a/content/20.build/tooling/zksync-cli/commands/contract-interaction.md +++ /dev/null @@ -1,338 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Contract interaction with zksync-cli | zkSync Docs ---- - -# Contract interaction with zksync-cli - -The zksync-cli tool, now enhanced with `contract read`, `contract write` and `contract encode` commands, offers -efficient ways for developers to interact with smart contracts on zkSync. These commands automate tasks such as method -verification, ABI handling, output decoding, and proxy contract processing. - -### Table of contents - -- [Contract Read - Running read-only methods](#contract-read) -- [Contract Write - Executing write operations](#contract-write) -- [Examples](#examples) - - [Basic read example](#basic-read-example) - - [Basic write example](#basic-write-example) - - [Basic encode example](#basic-encode-example) - - [Using local ABI file](#using-local-abi-file) - - [Running read on behalf of another address](#running-read-on-behalf-of-another-address) - - [Write operation with value transfer](#write-operation-with-value-transfer) -- [Troubleshooting](#troubleshooting) - -
- ---- - -
- -## Contract Read - -The `npx zksync-cli contract read` command executes read-only methods on contracts, like checking ERC-20 balances or -contract states. [See basic example](#basic-read-example) - -### Read Options - -You do not need to specify options bellow, you will be prompted to enter them if they are not specified. - -- `--chain `: Select the chain to use (e.g., `zksync-mainnet`, `zksync-sepolia`). -- `--rpc `: Provide RPC URL instead of selecting a chain -- `--contract
`: Specify contract's address -- `--method `: Defines the contract method to interact with -- `--arguments `: Pass arguments to the contract method -- `--data <0x-transaction-data>`: Instead of specifying the method and arguments, you can pass the raw transaction data -- `--outputTypes `: Specifies output types for decoding -- `--from
`: Call method on behalf of specified address -- `--abi `: Path to local ABI file or contract artifact -- `--decode-skip`: Skips prompting for output types and decoding the response -- `--show-info`: Displays transaction request information (e.g. encoded transaction data) - -
- ---- - -
- -## Contract Write - -The `npx zksync-cli contract write` command performs write operations on smart contracts. It enables sending -transactions that alter the state of a contract, such as transferring tokens or changing ownership. -[See basic example](#basic-write-example) - -### Write Options - -You do not need to specify options bellow, you will be prompted to enter them if they are not specified. - -- `--chain `: Select the chain to use -- `--rpc `: Provide RPC URL instead of selecting a chain -- `--contract
`: Specify contract's address -- `--method `: Defines the contract method to interact with -- `--arguments `: Pass arguments to the contract method -- `--value `: Ether amount to send with the transaction (e.g. 0.01) -- `--private-key `: Private key of the wallet to use to sign the transaction -- `--data <0x-transaction-data>`: Instead of specifying the method and arguments, you can pass the raw transaction data -- `--abi `: Path to local ABI file or contract artifact -- `--show-info`: Displays transaction request information (e.g. encoded transaction data) - -
- ---- - -
- -## Examples - -#### Basic read example - -```bash -npx zksync-cli contract read -``` - -You will be prompted to select a chain, contract address, and method. - -```bash -? Chain to use: zkSync Sepolia Testnet -? Contract address: 0x45E6dC995113fd3d1A3b1964493105B9AA9a9A42 -``` - -Next you need to select a **method (function) to call**. - -- In case your contract is verified it will automatically identify the ABI: - - ```bash - ? Contract method to call - ────────── Provided contract ────────── - ❯ balanceOf(address account) view returns (uint256) - decimals() pure returns (uint8) - name() pure returns (string) - symbol() pure returns (string) - totalSupply() view returns (uint256) - ─────────────────────────────────────── - Type method manually - ``` - -- Otherwise you'll have to enter method signature manually, for example `balanceOf(address)`. - - ```bash - ? Enter method to call: balanceOf(address) - ``` - -- Alternatively, you can specify the ABI file manually using the `--abi` option. [See example](#using-local-abi-file) - -After that, you will be prompted to enter **arguments** for the method, one by one. - -```bash -? Provide method arguments: -? [1/1] account (address): 0xa1cf087DB965Ab02Fb3CFaCe1f5c63935815f044 -``` - -When submitted a contract call will be made and you'll see the response in it's original encoded form. - -```bash -✔ Method response (raw): 0x000000000000000000000000000000000000000000010508e606548a9e5d2000 -``` - -Finally, you will be asked the **method output** type to decode the response. You can skip this step by submitting empty -response or completely skip it by passing `--decode-skip` option. - -```bash -? Output types: uint256 -✔ Decoded method response: 1232701801010000000000000 -``` - -**Tip**: after running command with prompts you will see a full command with all the options that you can copy and use -later to quickly run the same command again. For example: - -```bash -npx zksync-cli contract read \ - --chain "zksync-sepolia" \ - --contract "0x45E6dC995113fd3d1A3b1964493105B9AA9a9A42" \ - --method "balanceOf(address)" \ - --args "0xa1cf087DB965Ab02Fb3CFaCe1f5c63935815f044" \ - --output "uint256" -``` - -
- ---- - -
- -#### Basic write example - -```bash -npx zksync-cli contract write -``` - -You will be prompted to select a chain, contract address, and method. - -```bash -? Chain to use: zkSync Sepolia Testnet -? Contract address: 0x45E6dC995113fd3d1A3b1964493105B9AA9a9A42 -``` - -Next you need to select a **method (function) to call**. - -- In case your contract is verified it will automatically identify the ABI: - - ```bash - ? Contract method to call - ────────── Provided contract ────────── - ❯ approve(address spender, uint256 amount) returns (bool) - transfer(address to, uint256 amount) returns (bool) - ─────────────────────────────────────── - Type method manually - ``` - -- Otherwise you'll have to enter method signature manually, for example `transfer(address,uint256)`. - - ```bash - ? Enter method to call: transfer(address,uint256) - ``` - -- Alternatively, you can specify the ABI file manually using the `--abi` option. [See example](#using-local-abi-file) - -After that, you will be prompted to enter **arguments** for the method, one by one. - -```bash -? Provide method arguments: -? [1/2] to (address): 0xa1cf087DB965Ab02Fb3CFaCe1f5c63935815f044 -? [2/2] amount (uint256): 1 -``` - -Now you need to provide private key of the wallet to use to sign the transaction. - -```bash -? Private key of the wallet to sign transaction: ***** -``` - -When submitted a contract call will be made and you'll see the transaction hash - -```bash -✔ Transaction submitted. Transaction hash: 0xa83ad7e8932e18cdc57d3892040505a50d560a56fa507cabcd4180e9e5898bec -``` - -**Tip**: after running command with prompts you will see a full command with all the options that you can copy and use -later to quickly run the same command again. For example: - -```bash -npx zksync-cli contract write \ - --chain "zksync-sepolia" \ - --contract "0x45E6dC995113fd3d1A3b1964493105B9AA9a9A42" \ - --method "transfer(address to, uint256 amount)" \ - --args "0x45E6dC995113fd3d1A3b1964493105B9AA9a9A42" "1" -``` - -
- ---- - -
- -#### Basic encode example - -```bash -npx zksync-cli contract encode -``` - -This command allows you to encode contract method signature and arguments into raw calldata (e.g. `0x1234...`). - -You will need to select a **method (function) to encode**. - -- Enter method signature manually, for example `transfer(address,uint256)`. - - ```bash - ? Enter method to call: transfer(address,uint256) - ``` - -- Alternatively, you can specify the ABI file using the `--abi` option. [See example](#using-local-abi-file) - -```bash -? Contract method to call - ────────── Provided contract ────────── -❯ approve(address spender, uint256 amount) returns (bool) - transfer(address to, uint256 amount) returns (bool) - ─────────────────────────────────────── - Type method manually -``` - -After that, you will be prompted to enter **arguments** for the method, one by one. - -```bash -? Provide method arguments: -? [1/2] to (address): 0xa1cf087DB965Ab02Fb3CFaCe1f5c63935815f044 -? [2/2] amount (uint256): 1 -``` - -When finished you will see the encoded data. - -```bash -✔ Encoded data: 0xa41368620000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000c48656c6c6f20776f726c64210000000000000000000000000000000000000000 -``` - -
- ---- - -
- -### Using local ABI file - -You can specify a local ABI file using the `--abi` option. It should be a JSON file with either ABI data (array) or -contract artifact which you get after compiling your contracts. - -```bash -npx zksync-cli contract read \ - --abi "./Greeter.json" -``` - -Now you will be able to select a method: - -```bash - ────────── Provided contract ────────── -❯ greet() view returns (string) - ─────────────────────────────────────── - Type method manually -``` - -Response will be decoded automatically as well according to the ABI file. - -
- ---- - -
- -### Running read on behalf of another address - -You can specify the `--from` option to run the method on behalf of another address. This is useful when you need to call -a method that expects a specific address as `msg.sender`. - -```bash -npx zksync-cli contract read \ - --from "0xa1cf087DB965Ab02Fb3CFaCe1f5c63935815f044" -``` - -
- ---- - -
- -### Write operation with value transfer - -Here, the command sends a transaction that includes Ether transfer along with the method call. - -```bash -npx zksync-cli contract write \ - --value "0.1" -``` - -## Troubleshooting - -If you encounter issues, consult our [troubleshooting guide](../../zksync-cli/troubleshooting.md) or report them in our -[GitHub discussions](https://github.com/zkSync-Community-Hub/zksync-developers/discussions/new?category=general). diff --git a/content/20.build/tooling/zksync-cli/commands/create.md b/content/20.build/tooling/zksync-cli/commands/create.md deleted file mode 100644 index dabdc90f..00000000 --- a/content/20.build/tooling/zksync-cli/commands/create.md +++ /dev/null @@ -1,64 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Project Creation with zksync-cli | zkSync Docs ---- - -# Project creation with zksync-cli - -Leverage the power of [zksync-cli](../../zksync-cli/getting-started.md) to kickstart your project with -`npx zksync-cli create`. This command streamlines project setup by offering templates for frontend development, smart -contracts, and scripting for zkSync, enabling rapid deployment and development. - -### Prerequisites - -Ensure you have the following installed before you start: - -- [Node.js v18+](https://nodejs.org/en) -- [Git](https://git-scm.com/downloads) - -### Table of contents - -- [Available Templates](#available-templates) - - [Frontend](#frontend) - - [Contracts](#contracts) - - [Scripting](#scripting) -- [Using Templates](#using-templates) -- [Troubleshooting](#troubleshooting) - -## Available Templates - -`npx zksync-cli create` simplifies the initial project setup by providing templates in three main categories: - -### Frontend - -Fast-track your UI development with our frontend templates, supporting popular frameworks like Vue, React, Next.js, -Nuxt, and Vite. Options include viem, ethers, web3modal, rainbowkit, equipping you with the necessary tools for dApp -development. [More Info](https://github.com/matter-labs/zksync-frontend-templates#readme). - -### Contracts - -For smart contract development, choose from templates designed for quick deployment and testing, compatible with -Solidity or Vyper. Utilize tools like Hardhat to streamline your workflow. -[Contract templates](https://github.com/matter-labs/zksync-contract-templates#readme). - -### Scripting - -Enhance your project with Node.js scripting templates for automated interactions and advanced zkSync operations. -Includes examples of wallet or contract interactions using viem, ethers, or web3.js. -[Scripting Templates](https://github.com/matter-labs/zksync-scripting-templates#readme). - -## Using Templates - -To create a project using a template, run the following command and follow the prompts to select your desired template -category and specific framework or tool: - -```bash -npx zksync-cli create -``` - -## Troubleshooting - -If you encounter issues, consult our [troubleshooting guide](../../zksync-cli/troubleshooting.md) or report them in our -[GitHub discussions](https://github.com/zkSync-Community-Hub/zksync-developers/discussions/new?category=general). diff --git a/content/20.build/tooling/zksync-cli/commands/custom-chains.md b/content/20.build/tooling/zksync-cli/commands/custom-chains.md deleted file mode 100644 index e224600c..00000000 --- a/content/20.build/tooling/zksync-cli/commands/custom-chains.md +++ /dev/null @@ -1,46 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Custom Chains Configuration with zksync-cli | zkSync Docs ---- - -# Using custom chains with zksync-cli - -The [zksync-cli](../../zksync-cli/getting-started.md) tool provides a flexible way to add or edit custom chains, -enabling you to specify your own chain configuration. This feature is essential for developers looking to interact with -ZK Stack Hyperchains. - -## Configuring Custom Chains - -To add or edit a custom chain, use the following command: - -```bash -npx zksync-cli config chains -``` - -Upon execution, you will be guided through a series of prompts to enter specific details for the custom chain, -including: - -- **Chain Name**: A unique identifier for the custom chain. -- **RPC URL**: The RPC endpoint URL for interacting with the chain. -- **Chain ID**: The unique identifier for the chain, crucial for transaction signing and validation. -- **Other Information**: Depending on the chain's requirements, you may need to provide additional information such as - block explorer URLs. - -## Using Custom Chains - -Once a custom chain is configured, you can use it across various `zksync-cli` commands. All of your custom chains will -be listed in the chain selection prompt, allowing you to select and use them as needed. You can also specify a custom -chain directly using the `--chain` option, for example: - -```bash -npx zksync-cli wallet balance --chain -``` - -## Troubleshooting - -If you encounter issues while configuring or using custom chains, ensure your RPC URLs and Chain IDs are correct and -that the network is accessible. For further assistance, consult our -[troubleshooting guide](../../zksync-cli/troubleshooting.md) or report your issue in our -[GitHub discussions](https://github.com/zkSync-Community-Hub/zksync-developers/discussions/new?category=general). diff --git a/content/20.build/tooling/zksync-cli/commands/local-node.md b/content/20.build/tooling/zksync-cli/commands/local-node.md deleted file mode 100644 index ff2f7687..00000000 --- a/content/20.build/tooling/zksync-cli/commands/local-node.md +++ /dev/null @@ -1,76 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Local Node with zksync-cli | zkSync Docs ---- - -# Start a zkSync Node locally with zksync-cli - -Utilize the [zksync-cli](../../zksync-cli/getting-started.md) to effortlessly initiate a local development environment. -A simple command, `npx zksync-cli dev start`, gears up local zkSync and Ethereum nodes, along with Block Explorer, -Wallet, and Bridge for a seamless development experience. - -### Prerequisites - -Before beginning, ensure you have installed: - -- [Node.js v18+](https://nodejs.org/en) -- [Git](https://git-scm.com/downloads) -- [Docker](https://www.docker.com/get-started/) - -### Table of contents - -- [Starting and Stopping Nodes](#starting-and-stopping-nodes) -- [Configuring Your Environment](#configuring-your-environment) -- [Managing Modules](#managing-modules) -- [Viewing Logs](#viewing-logs) -- [Cleaning Modules](#cleaning-modules) -- [Updating Modules](#updating-modules) -- [Troubleshooting](#troubleshooting) - -## Starting and Stopping Nodes - -- **Start**: `npx zksync-cli dev start` initiates your local environment. On the first run, it prompts to select a node - and additional modules. -- **Stop**: `npx zksync-cli dev stop` terminates the local environment. Use `npx zksync-cli dev stop [module name]` to - stop specific modules, e.g., `npx zksync-cli dev stop zkcli-block-explorer`. -- **Restart**: `npx zksync-cli dev restart` or `npx zksync-cli dev restart [module name]` restarts your environment or - specific modules. - -## Configuring Your Environment - -- `npx zksync-cli dev config` allows the selection of nodes and additional modules like block explorer and bridge. Run - modules such as Block Explorer against an already running node by adding a new chain. - -## Managing Modules - -- `npx zksync-cli dev modules` lists all installed modules, providing a clear overview of your environment's components. - -## Viewing Logs - -- `npx zksync-cli dev logs` displays logs for all active modules, essential for monitoring and debugging. - -## Cleaning Modules - -- `npx zksync-cli dev clean` removes all module data from your computer. For specific modules, use - `npx zksync-cli dev clean [module name]`. - -## Updating Modules - -- `npx zksync-cli dev update [module name]` updates individual modules, ensuring you're running the latest versions. - Usually you will see a notification when a new version is available. - -## Troubleshooting - -If modules malfunction, e.g., failing to start: - -1. Use `npx zksync-cli dev stop` to cease all operations. -2. Reinstall the problematic module with `npx zksync-cli dev clean [module name]`, viewable via - `npx zksync-cli dev modules`. -3. Restart with `npx zksync-cli dev start`. Check Docker container logs for detailed errors, accessible through Docker - Desktop. -4. Persisting issues? Please report them in our - [GitHub discussions](https://github.com/zkSync-Community-Hub/zksync-developers/discussions/new?category=general&title=[zksync-cli]%20). - -For additional assistance, refer to our [troubleshooting guide](../../zksync-cli/troubleshooting.md). diff --git a/content/20.build/tooling/zksync-cli/commands/transaction-info.md b/content/20.build/tooling/zksync-cli/commands/transaction-info.md deleted file mode 100644 index f89ec726..00000000 --- a/content/20.build/tooling/zksync-cli/commands/transaction-info.md +++ /dev/null @@ -1,122 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Contract interaction with zksync-cli | zkSync Docs ---- - -# Transaction information with zksync-cli - -The `npx zksync-cli transaction info` command is designed to fetch and display detailed information about a specific -transaction. It can be used to check the status, amounts transferred, fees, method signatures, and arguments of -transactions on the chain of choice. - -### Table of contents - -- [Options](#options) -- [Examples](#example-usage) - - [Basic usage](#basic-usage) - - [Parsing transaction data](#parsing-transaction-data) - - [Viewing detailed information](#viewing-detailed-information) - - [Displaying raw JSON response](#displaying-raw-json-response) -- [Troubleshooting](#troubleshooting) - -<br /> - ---- - -<br /> - -### Options - -You do not need to specify options bellow, you will be prompted to enter them if they are not specified. - -- `--tx <transaction hash>`: Specify the transaction hash to query. -- `--chain <chain-name>`: Select the chain to use (e.g., `zksync-mainnet`, `zksync-sepolia`). -- `--rpc <url>`: Provide RPC URL instead of selecting a chain -- `--full`: Show all available transaction data for comprehensive insights. -- `--raw`: Display the raw JSON response from the node. -- `--abi <path>`: Path to a local ABI file to decode the transaction's input data. - -If no options are provided directly, the CLI will prompt the user to enter the necessary information, such as the chain -and transaction hash. - -<br /> - ---- - -<br /> - -## Example usage - -### Basic usage - -```bash -npx zksync-cli transaction info -``` - -You will be prompted to select a chain and transaction hash. - -```bash -? Chain to use: zkSync Sepolia Testnet -? Transaction hash: 0x2547ce8219eb7ed5d73e68673b0e4ded83afc732a6c651d43d9dc49bb2f13d40 -``` - -The command will then display detailed information about the transaction, including its status, from/to addresses, value -transferred, method signature with arguments, and more: - -``` -──────────────────── Main info ──────────────────── -Transaction hash: 0x2547ce8219eb7ed5d73e68673b0e4ded83afc732a6c651d43d9dc49bb2f13d40 -Status: completed -From: 0x56DDd604011c5F8629bd7C2472E3504Bd32c269b -To: 0xBB5c309A3a9347c0135B93CbD53D394Aa84345E5 -Value: 0 ETH -Fee: 0.0001503581 ETH | Initial: 0.0004 ETH Refunded: 0.0038496419 ETH -Method: transmit(bytes,bytes32[],bytes32[],bytes32) 0xc9807539 - -───────────────── Method arguments ───────────────── -[1] bytes: 0x0000000000000000000000fd69e45d6f51e482ac4f8f2e14f2155200008b5f010001020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000007df298c81a0000000000000000000000000000000000000000000000000000007df298c81a0000000000000000000000000000000000000000000000000000007df298c81a -[2] bytes32[]: 0xd737d65b6b610c3f330bcfddbfc08e46d2a628c88bf22ec0d8f25627a3330798,0x9d33be2ba33b731555c13a4e7bf02d3d576fa3115f7523cbf07732321c85cdba -[3] bytes32[]: 0x73d639deda36b781ae049c8eceafba4196ee8ecc1efb74c538a28ea762ff6658,0x37ac79ff2ca902140613b0e51357d8fb218a67b4736bdee0c268c5fd9812e146 -[4] bytes32: 0x0101000000000000000000000000000000000000000000000000000000000000 - -───────────────────── Details ───────────────────── -Date: 2/8/2024, 2:19:54 PM (15 minutes ago) -Block: #364999 -Nonce: 50131 -``` - -### Parsing transaction data - -By default `zksync-cli` tries to fetch contract verification data from the server. In case this is not possible it -queries the [open signature](https://www.4byte.directory/) database to get signature of the transaction method. If the -method signature is not found, the transaction's data is displayed as a hex string. - -Alternatively, you can provide the path to a local ABI file to decode the transaction's input data: - -```bash -npx zksync-cli transaction info \ - --abi "./Greeter.json" -``` - -### Viewing detailed information - -For an even more detailed overview you can use the `--full` option: - -```bash -npx zksync-cli transaction info --full -``` - -### Displaying raw JSON response - -If you prefer to see the raw JSON response from the zkSync node, use the `--raw` option: - -```bash -npx zksync-cli transaction info --raw -``` - -## Troubleshooting - -If you encounter issues, consult our [troubleshooting guide](../../zksync-cli/troubleshooting.md) or report them in our -[GitHub discussions](https://github.com/zkSync-Community-Hub/zksync-developers/discussions/new?category=general). diff --git a/content/20.build/tooling/zksync-cli/commands/wallet.md b/content/20.build/tooling/zksync-cli/commands/wallet.md deleted file mode 100644 index 783d1a49..00000000 --- a/content/20.build/tooling/zksync-cli/commands/wallet.md +++ /dev/null @@ -1,90 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Wallet Operations with zksync-cli | zkSync Docs ---- - -# Wallet operations with zksync-cli - -Utilize the [zksync-cli](../../zksync-cli/getting-started.md) for an easy way to manage your assets on zkSync, like -token transfers and balance check. - -### Prerequisites - -Ensure the following are installed before you proceed: - -- [Node.js v18+](https://nodejs.org/en) - -### Table of contents - -- [Wallet Transfer](#wallet-transfer) - - [Basic Transfer](#basic-transfer) - - [Transfer Options](#transfer-options) - - [Transfer ERC-20 Token](#transfer-erc-20-token) -- [Wallet Balance](#wallet-balance) - - [Checking Balance](#checking-balance) - - [Balance Options](#balance-options) - - [Checking ERC-20 Token Balance](#checking-erc-20-token-balance) -- [Troubleshooting](#troubleshooting) - -## Wallet Transfer - -### Basic Transfer - -To transfer ETH between accounts on zkSync, use the following command: - -```bash -npx zksync-cli wallet transfer -``` - -### Transfer Options - -You do not need to specify options bellow, you will be prompted to enter them if they are not specified. - -- `--to`, `--recipient <0x address>`: Define the recipient address on L2. -- `--amount <0.1>`: Specify the amount to transfer. -- `--token <token address>`: Specify an ERC-20 token for the transfer instead of ETH. -- `--pk`, `--private-key <wallet private key>`: Use the private key of the sender for the transaction. -- `--chain <chain>`: Select the chain to use. -- `--rpc <URL>`: Override the default L2 RPC URL. - -### Transfer ERC-20 Token - -For transferring ERC-20 tokens, include the `--token` option with the token's contract address, for example: - -```bash -npx zksync-cli wallet transfer --token 0x3e622317f8C93f7328350cF0B56d9eD4C620C5d6 -``` - -## Wallet Balance - -### Checking Balance - -View zkSync wallet's ETH balance using the following command: - -```bash -npx zksync-cli wallet balance -``` - -### Balance Options - -You do not need to specify options bellow, you will be prompted to enter them if they are not specified. - -- `--address <0x address>`: Address of the wallet to check. -- `--token <token address>`: Specify an ERC-20 token for the transfer instead of ETH. -- `--chain <chain>`: Select the chain to use. -- `--rpc <URL>`: Override the default L2 RPC URL. - -### Checking ERC-20 Token Balance - -To check the balance of a specific ERC-20 token, use the `--token` option, for example: - -```bash -npx zksync-cli wallet balance --token 0x3e622317f8C93f7328350cF0B56d9eD4C620C5d6 -``` - -## Troubleshooting - -If you encounter issues, consult our [troubleshooting guide](../../zksync-cli/troubleshooting.md) or report them in our -[GitHub discussions](https://github.com/zkSync-Community-Hub/zksync-developers/discussions/new?category=general). diff --git a/content/20.build/tooling/zksync-cli/getting-started.md b/content/20.build/tooling/zksync-cli/getting-started.md deleted file mode 100644 index fe53a5aa..00000000 --- a/content/20.build/tooling/zksync-cli/getting-started.md +++ /dev/null @@ -1,47 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Getting Started with zkSync CLI | zkSync Docs ---- - -# Getting Started with zkSync CLI - -Welcome to the zkSync CLI documentation! The zkSync Command Line Interface (CLI) is a powerful tool designed to simplify -the development and interaction with zkSync. It provides developers with an easy-to-use set of commands to manage local -development environment, interact with contracts, manage tokens, and much more. - -## 📥 Usage - -You can run commands without installation: `npx zksync-cli`. For example: `npx zksync-cli dev start`. - -## Available Commands - -- [Start Local Node](./commands/local-node.md): Start a local development environment with zkSync and Ethereum nodes. -- [Project Creation](./commands/create.md): Scaffold new projects using templates for frontend, contracts, and - scripting. -- [Contract Interactions](./commands/contract-interaction.md): Read and write data to zkSync contracts without building - UI. -- [Transaction Information](./commands/transaction-info.md): Fetch and display detailed information about a specific - transaction. -- [Wallet Operations](./commands/wallet.md): Manage zkSync wallet assets, including transfers and balance checks. -- [Bridge Operations](./commands/bridge.md): Perform deposits and withdrawals between Ethereum and zkSync. -- [Custom Chains](./commands/custom-chains.md): Add or edit custom chains for flexible testing and development. - -## Troubleshooting - -Encountering issues? Our [Troubleshooting](./troubleshooting.md) guide covers common problems and their solutions, -helping you resolve any hiccups quickly. - -## Further Assistance - -Need more help? Join our [GitHub Discussions](https://github.com/zkSync-Community-Hub/zksync-developers/discussions/) to -ask questions, share your experiences, and connect with the zkSync community. - -Thank you for choosing zkSync CLI for your development journey. We're excited to support your projects and innovations -on the zkSync platform. - -## Source Code - -The zkSync CLI is open-source and available on [GitHub](https://github.com/matter-labs/zksync-cli) under MIT License. -Feel free to contribute, report issues, or suggest new features to help us improve the tool for everyone. diff --git a/content/20.build/tooling/zksync-cli/troubleshooting.md b/content/20.build/tooling/zksync-cli/troubleshooting.md deleted file mode 100644 index 7e466268..00000000 --- a/content/20.build/tooling/zksync-cli/troubleshooting.md +++ /dev/null @@ -1,73 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Troubleshooting zkSync CLI | zkSync Docs ---- - -# Troubleshooting zkSync CLI - -Encountering issues with zkSync CLI? Here are some common problems and step-by-step recommendations for resolving them: - -<details> -<summary><strong>`unknown command` Error</strong></summary> - -If you encounter an `unknown command` error, follow these steps: - -a. **Check the zkSync CLI Version** - -- Run `npx zksync-cli --version` to check your current version. -- Compare it with the latest version available on [npm](https://www.npmjs.com/package/zksync-cli). -- If your version is lower than the one on npm, follow the steps below. If your version is up-to-date, it's possible - that the command was moved or renamed. Use `npx zksync-cli help` for a list of current commands or refer to the - documentation. - -b. **Verify Local Installation** - -- Use `npm list zksync-cli` to check if `zksync-cli` is installed in the current directory or any parent directories - from where you are running your terminal. -- If it is indeed installed, make sure to uninstall it by running `npm uninstall zksync-cli` in its installation - location. Remove all instances of `zksync-cli` until none are found by `npm list zksync-cli`. - -c. **Verify Global Installation** - -- Use `npm list -g zksync-cli` to check if `zksync-cli` is installed globally. -- If it is installed globally, uninstall it using `npm uninstall -g zksync-cli`. - -d. **Clean npm Cache** - -- Run `npm cache clean --force`. - -e. **Use the Latest Version** - -- As a quick fix, or if the above steps don't resolve the issue, use `npx zksync-cli@latest [command]`, for example, - `npx zksync-cli@latest dev start`. - -</details> - -<br /> - -<details> -<summary><strong>My Version is Outdated</strong></summary> - -If `npx zksync-cli` is not running the latest version: - -- Refer to the guide above to check and update your zkSync CLI version. - -</details> - -<br /> - -<details> -<summary><strong>`command not found: npx` Error</strong></summary> - -If you receive a `command not found: npx` error, it means Node.js is not installed or not correctly set up on your -system: - -- Install Node.js from [https://nodejs.org/](https://nodejs.org/). This will also install `npm` and `npx`. -- After installation, restart your terminal and try running `npx zksync-cli` again. - -</details> - -For all other issues, we encourage you to seek help or report them in our -[GitHub Discussions](https://github.com/zkSync-Community-Hub/zksync-developers/discussions/new?category=general&title=[zksync-cli]%20<Title>). diff --git a/content/20.build/tutorials/dapp-development/frontend-quickstart-paymaster.md b/content/20.build/tutorials/dapp-development/frontend-quickstart-paymaster.md deleted file mode 100644 index c9bc7625..00000000 --- a/content/20.build/tutorials/dapp-development/frontend-quickstart-paymaster.md +++ /dev/null @@ -1,560 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Frontend quickstart | zkSync Docs ---- - -# Frontend Quickstart: build your first dApp - -::: info - -Although this tutorial can be used as a reference to understand how to create frontends to interact with zkSync -contracts, this is a continuation of the [Quickstart tutorial](../../quick-start/hello-world.md). Make sure to complete -it before continue. - -::: - -In this tutorial we're going to: - -- Create a basic frontend to interact with the contract deployed in - [the quickstart tutorial](../../quick-start/hello-world.md). -- Learn about `zksync-ethers` and use it to connect to zkSync and interact with our contract. -- Learn about paymasters. -- Integrate a paymaster in our frontend to allow users to pay transaction fees in any ERC20 token. - -## Prerequisites - -- Download and install [Node.js](https://nodejs.org/en/download). -- Use the `yarn` or `npm` package manager. We recommend using `yarn`. To install `yarn`, follow the - [Yarn installation guide](https://yarnpkg.com/getting-started/install). -- Get some ERC20 tokens. The easiest way is to - [mint TEST tokens](https://sepolia.explorer.zksync.io/address/0x7E2026D8f35872923F5459BbEDDB809F6aCEfEB3#contract) - directly in our explorer. You can also get Sepolia USDC or DAI from - [the Aave faucet](https://staging.aave.com/faucet/) and then bridge them to zkSync using - [the zkSync bridge](https://portal.zksync.io/bridge/?network=sepolia). - -## Setup the project - -We're going use the [Vue.js web framework](https://vuejs.org/) to build this app although the process is similar with -other frameworks like [React](https://react.dev/). In addition, we're going to use the `zksync-ethers` SDK, which -extends `ethers` with zksync-specific features. In order to focus on `zksync-ethers`, we provide a prebuilt template -project with most of the frontend code. We'll just need to implement the methods to interact with the smart contracts. -Let's start! - -1. Clone the template project and `cd` into the folder. - -```sh -git clone https://github.com/matter-labs/tutorials -cd tutorials/hello-world/frontend -``` - -2. Spin up the project. - -```bash -yarn -yarn dev -``` - -Navigate to `http://localhost:8080/` in a browser to see the application running. - -## Project Structure - -We'll only work in the `<script>` section of the `./src/App.vue` file. Some methods are already provided while other -have to be implemented. We'll go through these ones one by one: - -```javascript -// METHODS TO BE IMPLEMENTED - const initializeProviderAndSigner= async ()=>{ - // TODO: initialize provider and signer based on `window.ethereum` - } - - const getGreeting = async ()=> { - // TODO: return the current greeting - return ""; - } - - const getFee = async() => { - // TODO: return formatted fee - return ""; - } - - const getBalance = async()=> { - // TODO: Return formatted balance - return ""; - } - const getOverrides = async() => { - if (selectedToken.value.l2Address != ETH_ADDRESS) { - // TODO: Return data for the paymaster - } - - return {}; - } -... -``` - -At the top of the `<script>` tag, there are also placeholder variables for the address of your deployed `Greeter` -contract, `GREETER_CONTRACT_ADDRESS`, and the path to its ABI, `GREETER_CONTRACT_ABI`. - -```ts -<script setup lang="ts" > -import { ref, onMounted } from 'vue' -// TODO: import ethers and zksync-ethers - -const GREETER_CONTRACT_ADDRESS = ""; // TODO: insert the Greeter contract address here -import * as GREETER_CONTRACT_ABI from './abi.json' // TODO: Complete and import the ABI -``` - -## Install zksync-ethers - -1. From the `hello-world/frontend` root directory, install the `zksync-ethers` library by running the following command - in your terminal: - -::: code-tabs - -@tab:active yarn - -```bash -yarn add ethers zksync-ethers -``` - -@tab npm - -```bash -npm install zksync-ethers -``` - -::: - -2. Add the library imports under at the top of the `./src/App.vue` file. - -```ts -<script setup lang="ts" > -import { ref, onMounted } from 'vue' - -import {} from "zksync-ethers"; -import {} from "ethers"; -``` - -## Add the Contract Info - -:::tip - -- To interact with a smart contract deployed to zkSync, we need its ABI. -- ABI stands for Application Binary Interface and it's a JSON which describes the contract's variables and methods. - -::: - -1. Locate the `./src/abi.json` file. It already contains information but it's better to use the one you created instead; - just in case you added new methods. - -2. Copy/paste the contract's ABI from the `./artifacts-zk/contracts/Greeter.sol/Greeter.json` file in the Hardhat - project from the [Quickstart tutorial](../../quick-start/hello-world.md), into `abi.json` replacing the existing one. - The file should look something like this: - -```json -[ - { - "inputs": [ - { - "internalType": "string", - "name": "_greeting", - "type": "string" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "inputs": [], - "name": "greet", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "string", - "name": "_greeting", - "type": "string" - } - ], - "name": "setGreeting", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - } -] -``` - -3. The `GREETER_CONTRACT_ABI` variable already imports the `abi.json` file so there's nothing else you need to do: - -```ts -import * as GREETER_CONTRACT_ABI from './abi.json'; // TODO: Complete and import the ABI -``` - -## Initialise Provider and Signer - -The `initializeProviderAndSigner` function in `./src/App.vue` is called right after the connection to Metamask is -successful. In this function we should: - -- Initialize a `BrowserProvider` and a `Signer` to interact with zkSync. -- Initialize the `Contract` object to interact with the `Greeter` contract we deployed previously. - -1. Import the necessary classes from `zksync-ethers` in the import statement we added previously: - -```javascript -import { Contract, BrowserProvider, Provider } from 'zksync-ethers'; -``` - -2. Initialise the provider, signer, and contract instances like this: - -```javascript -const initializeProviderAndSigner = async () => { - provider = new Provider('https://sepolia.era.zksync.dev'); - // Note that we still need to get the Metamask signer - signer = await new BrowserProvider(window.ethereum).getSigner(); - contract = new Contract(GREETER_CONTRACT_ADDRESS, GREETER_CONTRACT_ABI, signer); -}; -``` - -::: info zksync-ethers classes - -Note that classes like `Contract` and `Provider` have the same constructor parameters in `zksync-ethers`. - -`zksync-ethers` extends the existing classes from `ethers` with zksync-specific methods so, unless you're using any of -those features, you won't need to do any changes in your code. - -::: - -## Retrieve the Greeting - -Fill in the function to retrieve the greeting from the smart contract: - -```javascript -const getGreeting = async () => { - // Smart contract calls work the same way as in `ethers` - return await contract.greet(); -}; -``` - -Now if you go back to your browser, after connecting the Metamask wallet to zkSync Era Testnet, you should see the -following page: - -!['Retrieve message from contract'](../../../assets/images/quickstart-hello-nofee.jpg) - -The "select token" dropdown menu allows you to choose which token to pay fees with. We'll enable this feature later. - -## Check Balance and Estimate Fee - -The easiest way to retrieve the user's balance is to use the `Signer.getBalance` function. - -1. Add the following dependencies to the same place you added imports before: - -```javascript -// `ethers` is only used in this tutorial for its utility functions -import { ethers } from 'ethers'; -``` - -2. Implement the `getBalance()` function as shown below: - -```javascript -const getBalance = async () => { - // Getting the balance for the signer in the selected token - const balanceInUnits = await signer.getBalance(selectedToken.value.l2Address); - // To display the number of tokens in the human-readable format, we need to format them, - // e.g. if balanceInUnits returns 500000000000000000 wei of ETH, we want to display 0.5 ETH the user - return ethers.formatUnits(balanceInUnits, selectedToken.value.decimals); -}; -``` - -3. Implement the `getFee()` method that will estimate how much will it cost to update the message in the `Greeter.sol` - contract calling the `setGreeting` method: - -```javascript -const getFee = async () => { - // Getting the amount of gas (gas) needed for one transaction - const feeInGas = await contract.setGreeting.estimateGas(newGreeting.value); - // Getting the gas price per one erg. For now, it is the same for all tokens. - const gasPriceInUnits = await provider.getGasPrice(); - - // To display the number of tokens in the human-readable format, we need to format them, - // e.g. if feeInGas*gasPriceInUnits returns 500000000000000000 wei of ETH, we want to display 0.5 ETH the user - return ethers.formatUnits(feeInGas * gasPriceInUnits, selectedToken.value.decimals); -}; -``` - -Now, when you select the token to pay the fee, both the account balance and the expected fee for the transaction will be -displayed. - -Enter the message you want to save and click **Refresh** to recalculate the fee. Note that the fee depends on the length -of the message that we want to store in the contract. - -![Estimate transaction fee](../../../assets/images/quickstart-hello.jpg) - -It is possible to also click on the **Change greeting** button, but nothing will happen yet as we haven't implemented -the function. Let's implement that next. - -## Update the Greeting - -Update the `changeGreeting` function in `./src/App.vue` with the following code: - -```javascript -const changeGreeting = async () => { - txStatus.value = 1; - try { - const overrides = await getOverrides(); - const txHandle = await contract.setGreeting(newGreeting.value, overrides); - - txStatus.value = 2; - - // Wait until the transaction is committed - await txHandle.wait(); - txStatus.value = 3; - - // Update greeting - greeting.value = await getGreeting(); - - retrievingFee.value = true; - retrievingBalance.value = true; - // Update balance and fee - currentBalance.value = await getBalance(); - currentFee.value = await getFee(); - } catch (e) { - console.error(e); - alert(e); - } - - txStatus.value = 0; - retrievingFee.value = false; - retrievingBalance.value = false; - newGreeting.value = ''; -}; -``` - -Now you can update the greeting message in the contract via a transaction sent with Metamask. Once the transaction is -processed, you will see the Greeter message change on the app. - -Congrats! You now have a fully functional Greeter-dApp! However, it does not yet leverage any zkSync-specific features. -Let's fix that by integrating a paymaster! - -::: warning Do you see a **wallet_requestPermissions** error? - -Refresh your browser, or open the Metamask extension on your browser and click _Next_ or _Cancel_ to resolve it. - -Read more about `wallet_requestPermissions`, in the -[MetaMask documentation](https://docs.metamask.io/guide/rpc-api.html#wallet-requestpermissions). ::: - -## Pay Fees with ERC20 Tokens - -zkSync Era has native account abstraction, a feature that allows application developers to integrate paymasters. You can -find more information about paymasters in -[this section of our docs](../../../build/developer-reference/account-abstraction.md#paymasters) but the TL;DR is the -following: - -- Paymasters are smart contracts that alter the fee mechanism of the protocol. -- The paymaster contract pays the transaction fees with ETH using its own balance. -- Instead of forcing users to just pay transaction fees with ETH, the paymaster contract logic dictates what can be - done. -- From a user's point of view, paymasters can allow users to pay gas fess with ERC20 tokens or even allow gasless - transactions. -- To integrate a paymaster in your app, transactions must include specific parameters as transaction overrides in a - custom property called `paymasterParams` - -We will use the [testnet paymaster](../../../build/developer-reference/account-abstraction.md#testnet-paymaster) that is -provided on all zkSync Era testnets. - -:::tip About the testnet paymaster **The testnet paymaster allows users to pay fees in any ERC20 token with a fixed -exchange rate of 1:1 - Token:ETH**, i.e. one unit of the token for one wei of ETH. - -This means that transaction fees in tokens with fewer decimals than ETH will be bigger; for example, USDC which has only -6 decimals. This is a known behaviour of the testnet paymaster, which was built for demonstration purposes only. - -As the name suggests, the testnet paymaster is only available on testnet. When integrating your protocol on mainnet, you -should follow the documentation of the paymaster you use, or create your own. - -::: - -The `getOverrides` function returns an empty object when users decide to pay with Ether but, when users select the ERC20 -option, it should return the paymaster address and all the information required to interact with it. Let's see how it's -done. - -1. To retrieve the address of the testnet paymaster we'll use the `getTestnetPaymasterAddress` method from the zkSync - provider. This is one of the zksync-specific methods provided by `zksync-ethers`: - -```javascript -const getOverrides = async () => { - if (selectedToken.value.l2Address != ETH_ADDRESS) { - // retrieve the testnet paymaster address - const testnetPaymaster = await provider.getTestnetPaymasterAddress(); - - // .. - } - - return {}; -}; -``` - -2. Import `utils` from `zksync-ethers` SDK as we'll need to use some of its methods next: - -```javascript -import { Contract, Web3Provider, Provider, utils } from 'zksync-ethers'; -``` - -3. We need to calculate how many tokens are required to process the transaction. Since the testnet paymaster exchanges - any ERC20 token to ETH at a 1:1 rate, the amount is the same as the ETH amount in wei: - -```javascript -async getOverrides() { - if (this.selectedToken.l1Address != ETH_L1_ADDRESS) { - const testnetPaymaster = await this.provider.getTestnetPaymasterAddress(); - - const gasPrice = await provider.getGasPrice(); - - // define paymaster parameters for gas estimation - const paramsForFeeEstimation = utils.getPaymasterParams( - testnetPaymaster, - { - type: "ApprovalBased", - minimalAllowance: BigInt("1"), - token: selectedToken.value.l2Address, - innerInput: new Uint8Array(), - } - ); - - // estimate gasLimit via paymaster - const gasLimit = await contract.setGreeting.estimateGas( - newGreeting.value, - { - customData: { - gasPerPubdata: utils.DEFAULT_GAS_PER_PUBDATA_LIMIT, - paymasterParams: paramsForFeeEstimation, - }, - } - ); - // fee calculated in ETH will be the same in - // ERC20 token using the testnet paymaster - const fee = gasPrice.mul(gasLimit); - - // .. - } - - return {}; -} -``` - -4. Now, what is left is to encode the paymasterInput following the - [protocol requirements](../../../build/developer-reference/account-abstraction.md#testnet-paymaster) and return the - needed overrides. - -This will be the complete function: - -```javascript -const getOverrides = async () => { - if (selectedToken.value.l2Address != ETH_ADDRESS) { - const testnetPaymaster = await provider.getTestnetPaymasterAddress(); - - const gasPrice = await provider.getGasPrice(); - - // define paymaster parameters for gas estimation - const paramsForFeeEstimation = utils.getPaymasterParams(testnetPaymaster, { - type: 'ApprovalBased', - minimalAllowance: BigInt('1'), - token: selectedToken.value.l2Address, - innerInput: new Uint8Array(), - }); - - // estimate gasLimit via paymaster - const gasLimit = await contract.setGreeting.estimateGas(newGreeting.value, { - customData: { - gasPerPubdata: utils.DEFAULT_GAS_PER_PUBDATA_LIMIT, - paymasterParams: paramsForFeeEstimation, - }, - }); - - // fee calculated in ETH will be the same in - // ERC20 token using the testnet paymaster - const fee = gasPrice * gasLimit; - - const paymasterParams = utils.getPaymasterParams(testnetPaymaster, { - type: 'ApprovalBased', - token: selectedToken.value.l2Address, - // provide estimated fee as allowance - minimalAllowance: fee, - // empty bytes as testnet paymaster does not use innerInput - innerInput: new Uint8Array(), - }); - - return { - maxFeePerGas: gasPrice, - maxPriorityFeePerGas: BigInt(1), - gasLimit, - customData: { - gasPerPubdata: utils.DEFAULT_GAS_PER_PUBDATA_LIMIT, - paymasterParams, - }, - }; - } - - return {}; -}; -``` - -The `ApprovalBased` type in the `paymasterParams` indicates that this paymaster allows ERC20 tokens. Behind the scenes, -zkSync will take care of approve the ERC20 spending. - -5. To enable the use a list of ERC20 tokens, change the following line: - -```javascript -import allowedTokens from './eth.json'; // change to "./erc20.json" to use ERC20 tokens -``` - -to the following, which uses a list of predefined ERC20 tokens including DAI, USDC and -[the TEST token](https://sepolia.explorer.zksync.io/address/0x7E2026D8f35872923F5459BbEDDB809F6aCEfEB3#contract): - -```javascript -import allowedTokens from './erc20.json'; // change to "./erc20.json" to use ERC20 tokens -``` - -## Complete Application - -Now you should be able to update the greeting message with ETH or any of the available tokens. - -1. Select one of the ERC20 tokens to see the estimated fee: - -![img](../../../assets/images/quickstart-dai-fees.jpg) - -2. Click on the `Change greeting` button to update the message. Since the `paymasterParams` were supplied, the - transaction will be an `EIP712` ([more on EIP712 here](https://eips.ethereum.org/EIPS/eip-712)) so it'll look - slightly different in your wallet: - -![img](../../../assets/images/start-4.png) - -3. Click "Sign" to send the transaction. - -After the transaction is processed, the page updates the balances and the new greeting can be viewed. - -**You've paid for this transaction with an ERC20 token using the testnet paymaster** 🎉 - -## Takeaways - -- `zksync-ethers` is a Javascript library that extends `ethers` with zksync-specific methods. -- Paymasters allow users to pay transaction fees in ERC20 tokens or gasless. -- Paymasters can be easily integrated in frontend applications by including additional transaction parameters. - -## Next steps - -- For an overview of security and best practices for developing on zkSync Era, refer to the - [Security and best practices page](../../quick-start/best-practices.md). -- To learn more about `zksync-ethers` SDK, check out its - [documentation](../../../build/sdks/js/zksync-ethers/getting-started.md). -- To learn more about the zkSync hardhat plugins, check out their - [documentation](../../../build/tooling/hardhat/getting-started.md). -- If you have a project, check out our [migration guide](../../tooling/hardhat/migrating-to-zksync.md). diff --git a/content/20.build/tutorials/dapp-development/gated-nft-paymaster-tutorial.md b/content/20.build/tutorials/dapp-development/gated-nft-paymaster-tutorial.md deleted file mode 100644 index 9f1139c5..00000000 --- a/content/20.build/tutorials/dapp-development/gated-nft-paymaster-tutorial.md +++ /dev/null @@ -1,792 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Gated NFT Paymaster Tutorial | zkSync Docs ---- - -# Gated NFT Paymaster - -Discover how to construct a tailored paymaster that enables users to sidestep gas fees when they own a particular NFT. -By the end of this tutorial, you'll: - -- Write a `mint` function for the `ERC721.sol` contract. -- Design and implement the validation logic for the `ERC721GatedPaymaster.sol` contract. -- Deploy `Greeter.sol`, `ERC721.sol`, and `ERC721GatedPaymaster.sol` contracts. -- Connect our frontend application with users' MetaMask wallets. -- Initialize our contracts to facilitate interaction on the client side. -- Fetch data to display in a React component. -- Harness the capabilities of our paymaster based on NFT possession. - -### Introduction - -Welcome to this hands-on tutorial on creating and interacting with an `ERC721GatedPaymaster` and interacting with a -front-end application. If you've ever been curious about the mechanisms that allow for gasless transactions on zkSync -Era and our native account abstraction capabilities you're in the right place! - -You'll gain a thorough understanding of how to create, compile, and deploy smart contracts on zkSync Era, delve into the -intricacies of paymasters and validation logic, and seamlessly integrate them within a frontend application. On -completion, you'll have a fully functional `ERC721GatedPaymaster` contract and an interactive frontend to go with it. - -## Prerequisites - -- Make sure your machine satisfies the - [system requirements](https://github.com/matter-labs/era-compiler-solidity/tree/main#system-requirements). -- A [Node.js](https://nodejs.org/en/download) installation running Node.js version 16. -- Some familiarity with deploying smart contracts on zkSync. If not, please refer to the first section of the - [quickstart tutorial](../../quick-start/hello-world.md). -- Some background knowledge on the concepts covered by the tutorial would be helpful too. Have a look at the following - docs: - - [Account abstraction protocol](../../developer-reference/account-abstraction.md). - - [Introduction to system contracts](../../developer-reference/system-contracts.md). - - [Smart contract deployment](../../developer-reference/contract-deployment.md) on zkSyn Era. - - [Gas estimation for transactions](../../developer-reference/fee-model.md#gas-estimation-for-transactions) guide. -- You should also know - [how to get your private key from your MetaMask wallet](https://support.metamask.io/hc/en-us/articles/360015289632-How-to-export-an-account-s-private-key). - -### Complete Project - -Download the complete project [here](https://github.com/matter-labs/tutorials/tree/main/gated-nft). - -## Build time - -### Step 1 — Setup the Project - -:::info - -- This tutorial uses `React` and `Next.js` for the frontend framework (though the principles apply to other frameworks - too). -- We've provided a template for a hassle-free start. The primary focus is on mastering the `zksync-ethers` SDK and - paymaster validations. ::: - -1. Clone the template and `cd` into the folder. - -```bash -git clone https://github.com/matter-labs/tutorials -cd tutorials/gated-nft -``` - -2. Install dependencies: - -```bash -yarn install -``` - -Your project structure should now resemble: - -```text -├── LICENSE -├── README.md -├── frontend -├── package.json -├── yarn.lock -└── zksync -``` - -The project makes use of Yarn workspaces so we can seamlessly manage our dependencies between our frontend and smart -contracts. While `/frontend` houses React components, styles, and logic, `/zksync` contains everything related to smart -contract development and deployment. This tutorial will start in the `/zksync` directory as we need to write, compile -and deploy our contracts before we can interact with them! - -## Step 2 — Contract Development - -### Implementing `ERC721.sol` Mint Function - -:::tip 📍 Quick Tip: Always be in the `/zksync` directory for this phase. ::: - -Let’s first break down the project structure within `/zksync`: - -```text -├── LICENSE -├── README.md -├── contracts -├── deploy -├── hardhat.config.ts -├── package.json -├── test -└── yarn.lock -``` - -The template provides a ready-to-use `hardhat.config.ts` file that targets zkSync Era Testnet. If you are unfamiliar -with zkSync Era Hardhat configurations please refer to the documentation -[here](../../tooling/hardhat/getting-started.md#hardhat-configuration). - -1. To configure your private key, copy the `.env.example` file, rename the copy to `.env`, and add your wallet private - key. - -```text -WALLET_PRIVATE_KEY=YourPrivateKeyHere... -``` - -Your private key will be used for paying the costs of deploying the smart contract. - -::: warning A heads up! Make sure your account has zkSync Era Sepolia Testnet or Sepolia ETH to successfully deploy the -contracts. ::: - -2. Navigate to `/contracts` directory and open up the `ERC721.sol` contract. We will implement the missing logic for the - `mint` function. - -The contract code defines an ERC721 collection and allows the owner to mint a collectible to a provided recipient. - -The skeleton contract looks like this: - -```solidity -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol"; -import "@openzeppelin/contracts/access/Ownable.sol"; -import "@openzeppelin/contracts/utils/Strings.sol"; - -contract InfinityStones is ERC721URIStorage, Ownable { - uint256 public tokenId; - string public baseURI; - mapping (string => bool) public stoneExists; - mapping (address => uint256[]) private _ownedTokens; - - string[] public stones = [ - "Space Stone", - "Mind Stone", - "Reality Stone", - "Power Stone", - "Time Stone", - "Soul Stone" - ]; - - constructor() ERC721("InfinityStones", "ISTN") {} - - function mint(address recipient, string memory stoneName) public onlyOwner { - // TODO: TO BE IMPLEMENTED - // REQUIREMENTS: - // 1. Only the owner of the contract can mint - // 2. The stone name must be one of the 6 stones - // 3. The stone name must not have been minted before - // 4. The stoneName cannot be empty - // 5. The recipient must be a valid non-zero address - // 6. We must add the token to the list of tokens owned by the recipient - } - - function setBaseURI(string memory _baseURI) public onlyOwner { - baseURI = _baseURI; - } - - function tokenURI(uint256 _tokenId) public view override returns (string memory) { - require(_exists(_tokenId), "ERC721URIStorage: URI query for nonexistent token"); - return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, "/", Strings.toString(_tokenId))) : ""; - } - - function tokensOfOwner(address owner) public view returns (uint256[] memory) { - return _ownedTokens[owner]; - } -} -``` - -The function contains outlined requirements to assist in our implementation. We need to first make some checks to ensure -that the `stoneName` is not empty, that the recipient address is not a zero address, and ensure that the `stoneName` has -not been minted before. Let's start with that. - -```solidity -function mint(address recipient, string memory stoneName) public onlyOwner { - require(bytes(stoneName).length > 0, "stoneName must not be empty"); - require(recipient != address(0), "recipient must not be the zero address"); - require(!stoneExists[stoneName], "This stone already exists"); - - // TODO: MORE TO BE IMPLEMENTED -} -``` - -Great! A few criteria are met, but we aren't done yet. We still need to ensure the `stoneName` is 1 of 6 stones, and -update our owners mapping. Lets do that now. - -```solidity -function mint(address recipient, string memory stoneName) public onlyOwner { - require(bytes(stoneName).length > 0, "stoneName must not be empty"); - require(recipient != address(0), "recipient must not be the zero address"); - require(!stoneExists[stoneName], "This stone already exists"); - - for(uint i=0; i<stones.length; i++) { - if(keccak256(bytes(stoneName)) == keccak256(bytes(stones[i]))) { - stoneExists[stoneName] = true; - _safeMint(recipient, tokenId); - _ownedTokens[recipient].push(tokenId); - _setTokenURI(tokenId, stoneName); - tokenId++; - break; - } - } -} -``` - -We have now fully implemented our `mint` function on the `ERC721.sol` contract. We can now proceed to implement the -validation logic on the `ERC721GatedPaymaster.sol` contract. Let's open that file up and move to the next steps. - -### Implementing `validateAndPayForPaymasterTransaction` Function - -The skeleton contract looks like this: - -```solidity -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -import "@openzeppelin/contracts/token/ERC721/IERC721.sol"; -import "@openzeppelin/contracts/access/Ownable.sol"; - -import "@matterlabs/zksync-contracts/l2/system-contracts/Constants.sol"; - -import {IPaymaster, ExecutionResult, PAYMASTER_VALIDATION_SUCCESS_MAGIC} from "@matterlabs/zksync-contracts/l2/system-contracts/interfaces/IPaymaster.sol"; -import {IPaymasterFlow} from "@matterlabs/zksync-contracts/l2/system-contracts/interfaces/IPaymasterFlow.sol"; -import {TransactionHelper, Transaction} from "@matterlabs/zksync-contracts/l2/system-contracts/libraries/TransactionHelper.sol"; - -/// @author Matter Labs -/// @notice This smart contract pays the gas fees on behalf of users that are the owner of a specific NFT asset -contract ERC721GatedPaymaster is IPaymaster, Ownable { - IERC721 private immutable nft_asset; - - modifier onlyBootloader() { - require( - msg.sender == BOOTLOADER_FORMAL_ADDRESS, - "Only bootloader can call this method" - ); - // Continue execution if called from the bootloader. - _; - } - - // The constructor takes the address of the ERC721 contract as an argument. - // The ERC721 contract is the asset that the user must hold in order to use the paymaster. - constructor(address _erc721) { - nft_asset = IERC721(_erc721); // Initialize the ERC721 contract - } - - // The gas fees will be paid for by the paymaster if the user is the owner of the required NFT asset. - function validateAndPayForPaymasterTransaction( - bytes32, - bytes32, - Transaction calldata _transaction - ) - external - payable - onlyBootloader - returns (bytes4 magic, bytes memory context) - { - // TODO: TO BE IMPLEMENTED - // REQUIREMENTS: - // 1. Only the bootloader can validate and pay for the paymaster transaction. - // 2. The standard paymaster input must be at least 4 bytes long. - // 3. We must use a valid paymaster input selector (e.g. General or Approval-based). - // 4. The user address from the transaction must own the required NFT asset to use the paymaster. - // 5. We need to calculate the minimum required ETH value to pay for the transaction. - // 6. We need to to use the Bootloader to execute the transaction. - } - - function postTransaction( - bytes calldata _context, - Transaction calldata _transaction, - bytes32, - bytes32, - ExecutionResult _txResult, - uint256 _maxRefundedGas - ) external payable override onlyBootloader { - } - - function withdraw(address payable _to) external onlyOwner { - // send paymaster funds to the owner - uint256 balance = address(this).balance; - (bool success, ) = _to.call{value: balance}(""); - require(success, "Failed to withdraw funds from paymaster."); - } - - receive() external payable {} -} -``` - -:::info - -- Only the [bootloader](../../../zk-stack/components/zkEVM/bootloader.md) is allowed to call the - `validateAndPayForPaymasterTransaction` and `postTransaction` functions. -- To implement that, the `onlyBootloader` modifier is used on these functions. ::: - -#### Parsing the Paymaster Input - -The paymaster pays the transaction fees only if the user possesses one of NFT's from our previous contract. - -The input that the paymaster receives is encoded in the `paymasterInput` within the -`validateAndPayForPaymasterTransaction` function. - -As described in [the paymaster documentation](../../developer-reference/account-abstraction.md#paymasters), there are -standardized ways to encode user interactions with `paymasterInput`. To cover the gas costs of a user, we need to ensure -the user has the appropriate NFT in their account. - -1. Firstly, we check that the `paymasterInput` is encoded and uses the `General` flow, and that the account address has - a balance of at least 1 of the required NFTs. - -```solidity - magic = PAYMASTER_VALIDATION_SUCCESS_MAGIC; -require( - _transaction.paymasterInput.length >= 4, - "The standard paymaster input must be at least 4 bytes long" -); - -bytes4 paymasterInputSelector = bytes4( - _transaction.paymasterInput[0:4] -); - -if (paymasterInputSelector == IPaymasterFlow.general.selector) { - address userAddress = address(uint160(_transaction.from)); - - require( - nft_asset.balanceOf(userAddress) > 0, - "User does not hold the required NFT asset and therefore must pay for their own gas!" - ); - - // - // ... - // -} else { - revert("Unsupported paymaster flow"); -} -``` - -2. Next, we check the price of transaction fees, and transfer the correspondent gas fee from the paymaster to the - bootloader to cover the transaction fees. - -```solidity -// Note, that while the minimal amount of ETH needed is tx.gasPrice * tx.gasLimit, -// neither paymaster nor account are allowed to access this context variable. -uint256 requiredETH = _transaction.gasLimit * - _transaction.maxFeePerGas; - -(bool success, ) = payable(BOOTLOADER_FORMAL_ADDRESS).call{ - value: requiredETH -}(""); -``` - -The full `validateAndPayForPaymasterTransaction` function should resemble the following: - -```solidity -function validateAndPayForPaymasterTransaction( - bytes32, - bytes32, - Transaction calldata _transaction -) - external - payable - onlyBootloader - returns (bytes4 magic, bytes memory context) -{ - magic = PAYMASTER_VALIDATION_SUCCESS_MAGIC; - require( - _transaction.paymasterInput.length >= 4, - "The standard paymaster input must be at least 4 bytes long" - ); - - bytes4 paymasterInputSelector = bytes4( - _transaction.paymasterInput[0:4] - ); - - if (paymasterInputSelector == IPaymasterFlow.general.selector) { - address userAddress = address(uint160(_transaction.from)); - - require( - nft_asset.balanceOf(userAddress) > 0, - "User does not hold the required NFT asset and therefore must pay for their own gas!" - ); - - uint256 requiredETH = _transaction.gasLimit * - _transaction.maxFeePerGas; - - (bool success, ) = payable(BOOTLOADER_FORMAL_ADDRESS).call{ - value: requiredETH - }(""); - } else { - revert("Invalid paymaster flow"); - } -} -``` - -Amazing! We have successfully written the smart contracts let's proceed to deploy them using the deployment scripts -provided. - -#### Contract Deployment - -The deployment scripts provided will deploy the `ERC721.sol`, `ERC721GatedPaymaster.sol`, and `Greeter.sol` contracts. -You will need to provide the deployment script with an address to receive the NFT which we will be required to make use -of the paymaster. But before we deploy the contracts we first need to compile the contracts. - -1. Navigate to the root directory of the repository and run: - -```bash -yarn compile:contracts -``` - -The output of the command should resemble the following: - -```bash -Successfully compiled 43 Solidity files -``` - -2. Deploy the contracts to zkSync Era Testnet. This will also programmatically verify the contracts on zkSync Era - Testnet. - -```bash -yarn deploy:contracts -``` - -You will be prompted to input the recipient public address to receive a NFT. - -```bash -Running deploy script for the ERC721 contract... -You first need to add a RECIPIENT_ADDRESS to mint the NFT to... -Please provide the recipient address to receive an NFT: <INSERT_PUBLIC_ADDRESS_HERE> -``` - -After inserting the recipient address the script will continue: - -```bash -Running deploy script for the ERC721 contract... -You first need to add a RECIPIENT_ADDRESS to mint the NFT to... -Please provide the recipient address to receive an NFT: 0xf0e0d7709a335C2DD712F4F0F907017886B26707 -NFT Contract address: 0xb38b08fC34313A5Be7975FFE2C63F78f843325c1 -The Power Stone has been given to 0xf0e0d7709a335C2DD712F4F0F907017886B26707 -Balance of the recipient: 1 -New baseURI is https://ipfs.io/ipfs/QmPtDtJEJDzxthbKmdgvYcLa9oNUUUkh7vvz5imJFPQdKx -Your verification ID is: 34297 -Contract successfully verified on zkSync block explorer! -contracts/ERC721.sol:InfinityStones verified! VerificationId: 34297 -Done! -Running deploy script for the ERC721GatedPaymaster contract... -The deployment is estimated to cost 0.0001577065 ETH -Paymaster address: 0x83F1C9e8f03C5A756e3eed38823A14d1D6dA6f98 -Funding paymaster with ETH -Paymaster ETH balance is now 5000000000000000 -Your verification ID is: 34298 -Contract successfully verified on zkSync block explorer! -contracts/ERC721GatedPaymaster.sol:ERC721GatedPaymaster verified! VerificationId: 34298 -Done! -Running deploy script for the Greeter contract -The deployment is estimated to cost 0.000140617 ETH -Constructor args:0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000094869207468657265210000000000000000000000000000000000000000000000 -Greeter was deployed to 0x19720a45b7aB632Cc380A33E0964bc90013CCB2e -Your verification ID is: 34299 -Contract successfully verified on zkSync block explorer! -Done! -``` - -We have successfully compiled and deployed our smart contracts to zkSync Era Testnet! Let's move over to the `/frontend` -directory to interact with these smart contracts. - -## Step 3 — Frontend Development - -:::tip 📍 Quick Tip: Always be in the `/frontend` directory for this phase. ::: - -Let’s first break down the project structure within `/frontend`: - -```text -. -├── README.md -├── app -│   ├── assets -│   ├── components -│   ├── constants -│   ├── context -│   ├── favicon.ico -│   ├── globals.css -│   ├── hooks -│   ├── layout.tsx -│   ├── page.tsx -│   └── types -├── next-env.d.ts -├── next.config.js -├── package.json -├── postcss.config.js -├── public -├── tailwind.config.js -└── tsconfig.json -``` - -1. Let's spin up our frontend to see what we need to implement: - -```bash -yarn dev -``` - -This will start a local server running on `http://localhost:3000/`. You should see something that looks similar to: - -![starter frontend](../../../assets/images/gated-tutorial.png) - -### Connecting our `WalletButton` Component - -The first component we are going to interact with is the `WalletButton` component. - -1. Navigate to `app/components/WalletButton.tsx` - -```bash -cd app/components/WalletButton.tsx -``` - -2. Let implement the requirements for the `connectWallet` function - -The `connectWallet` function requirements indicates that we need to ensure we are connected to the correct network, -connect to the users MetaMask account, store some variables using React's Context API, and then call `initContracts` -function to instantiate our contracts. Let's proceed to do that: - -```typescript -const connectWallet = async () => { - if (!networkOk) await switchNetwork(); - try { - if ((window as any).ethereum) { - const provider = new Web3Provider((window as any).ethereum); - web3Context.setProvider(provider); - - const data = await provider.send('eth_requestAccounts', []); - - const signerInstance = provider.getSigner(); - web3Context.setSigner(signerInstance); - - setWallet({ address: data[0], acc_short: shortenAddress(data[0]) }); - - await initContracts(provider, signerInstance); - } - } catch (error) { - console.error('Error connecting DApp to your wallet'); - console.error(error); - } -}; -``` - -3. Great! Let's continue within our `WalletButton` component and implement the `initContracts` function. - -The `initContracts` function should instantiate our Greeter and NFT token contracts, check if the connected wallet -contains our specific NFT, and if so fetch the NFT metadata from IPFS and store some variables using React's Context -API. Copy and paste the below code snippet. - -```typescript -const initContracts = async (provider: Web3Provider, signer: Signer) => { - if (provider && signer) { - const greeterContract = new Contract(GREETER_ADDRESS, GREETER_CONTRACT_ABI, signer); - - web3Context.setGreeterContractInstance(greeterContract); - - const fetchedGreeting = await greeterContract.greet(); - web3Context.setGreetingMessage(fetchedGreeting); - - const nftContract = new Contract(NFT_CONTRACT_ADDRESS, NFT_CONTRACT_ABI, signer); - - const address = await signer.getAddress(); - const balance = await nftContract.balanceOf(address); - if (balance > 0) { - let ownedStones: PowerStoneNft[] = []; - const ownedTokensResponse = await nftContract.tokensOfOwner(address); - - for (let i = 0; i < ownedTokensResponse.length; i++) { - const tokenId = ownedTokensResponse[i]; - - const tokenURI = await nftContract.tokenURI(tokenId); - if (tokenURI == undefined || tokenURI == '') { - continue; - } - - const response = await fetch(tokenURI); - if (!response.ok) { - continue; - } - - ownedStones.push((await response.json()) as PowerStoneNft); - } - - web3Context.setNfts(ownedStones); - } else { - web3Context.setNfts([]); - } - } -}; -``` - -We can now return to our running local page and click the 'Connect Wallet' button which should connect to your MetaMask -account as depicted in the below image. - -![Connected wallet](../../../assets/images/connected_wallet.png) - -We have connected our wallet to our application but we now need to add our `GreeterMessage` and `Input` components. - -### Importing the `GreeterMessage` and `Input` Components - -1. Navigate to `app/page.tsx` - -Scrolling to the button you can see the requirements outlined. We need to import our components and pass the specified -props. Let's first import our components at the top of the file: - -```typescript -import Greeting from './components/GreeterMessage'; -import Input from './components/Input'; -``` - -2. Add the components to the return statement and pass desired props - -```jsx -<Greeting greeting={web3Context.greeting} /> -<Input - greeterInstance={web3Context.greeterContractInstance} - setGreetingMessage={web3Context.setGreetingMessage} - provider={web3Context.provider} - nfts={web3Context.nfts} -/> -``` - -Now if we check our local page we can see our rendered Greeter message and Input box! - -![Greeter Message](../../../assets/images/greeter_message.png) - -### Fetching the Gas details and adding the `Modal` Component - -1. Navigate to `app/components/Input.tsx` component - -We need to write our `estimateGas` function as we will want to pass those details to our `Modal` component to display. - -2. Implement `estimateGas` function - -We want to display the current gas price, estimate the amount of gas required to execute our `setGreeting` transaction, -and store these variables to be used later. - -```typescript -async function getEstimate() { - if (!provider) return; - let gasPrice = await provider.getGasPrice(); - let price = ethers.utils.formatEther(gasPrice.toString()); - setPrice(price); - - if (!greeterInstance) return; - let gasEstimate = await greeterInstance.estimateGas['setGreeting'](message); - let gas = ethers.utils.formatEther(gasEstimate.toString()); - setGas(gas); - - let transactionCost = gasPrice.mul(gasEstimate); - let cost = ethers.utils.formatEther(transactionCost.toString()); - setCost(cost); -} -``` - -3. Add `Modal` component to return statement - -```jsx -{ - isOpen && ( - <Modal - closeModal={closeModal} - greeterInstance={greeterInstance} - message={message} - setGreetingMessage={setGreetingMessage} - cost={cost} - price={price} - gas={gas} - nfts={nfts} - /> - ); -} -``` - -This will open the `Modal` component once the "Change message" button is clicked. - -### Setup our Paymaster Hook - -We are ready to implement our paymaster hook which will be used if the connected wallet possesses one of the applicable -NFT's we minted earlier. - -1. Navigate to `app/hooks/usePaymaster.tsx` - -The requirements outline we need to prepare and return the `paymasterParams` to then be passed alongside the -`setGreeting` transaction. - -```typescript -const usePaymaster = async ({ greeterInstance, message, price }: PaymasterProps) => { - let gasPrice = ethers.utils.parseEther(price); - const paymasterParams = utils.getPaymasterParams(PAYMASTER_CONTRACT_ADDRESS, { - type: 'General', - innerInput: new Uint8Array(), - }); - - const gasLimit = await greeterInstance.estimateGas.setGreeting(message, { - customData: { - gasPerPubdata: utils.DEFAULT_GAS_PER_PUBDATA_LIMIT, - paymasterParams: paymasterParams, - }, - }); - - return { - maxFeePerGas: gasPrice, - maxPriorityFeePerGas: ethers.BigNumber.from(0), - gasLimit: gasLimit, - customData: { - gasPerPubdata: utils.DEFAULT_GAS_PER_PUBDATA_LIMIT, - paymasterParams: paymasterParams, - }, - }; -}; -``` - -We have prepared our `paymasterParams` to be used in our application! Let's navigate to our last component that needs to -be implemented, the `Checkout` component. - -### Implement `updateGreeting` function in the `Checkout` component - -This function is responsible for initiating the transaction that will interact with our Greeter.sol contract to update -the message. It will check if the connected wallet contains our specific NFT and if so, call our `usePaymaster` hook -created above to pass along the `paymasterParams` to facilitate a gasless transaction for the user. Without the NFT, the -user will be required to pay the gas fee. - -1. Import `usePaymaster` hook in the `Checkout` component - -```typescript -import usePaymaster from '../hooks/usePaymaster'; -``` - -2. Implement the `updateGreeting` function - -```typescript -const updateGreeting = async ({ message }: GreeterData) => { - try { - if (greeterInstance == null) { - return; - } - - let txHandle; - if (hasNFT) { - const params = await usePaymaster({ greeterInstance, message, price }); - txHandle = await greeterInstance.setGreeting(message, params); - } else { - txHandle = await greeterInstance.setGreeting(message); - } - - await txHandle.wait(); - - const updatedGreeting = await greeterInstance.greet(); - setGreetingMessage(updatedGreeting); - } catch (error) { - console.error('Failed to update greeting: ', error); - } -}; -``` - -Amazing we have successfully implemented all our frontend requirements! Now its time to test the application. - -## Step 4 — Test the Application - -Navigate to `http://localhost:3000` and refresh the page. Click on "Connect Wallet" to link your MetaMask account. -Ensure you connect the address that received the minted NFT during contract deployment; otherwise, you'll bear the gas -fees! - -1. Input your own message into the `Input` component -2. Click the "Change message" button -3. If you have the right NFT you should be presented with the below image: - -![Checkout component](../../../assets/images/checkout.png) - -4. Enjoy a gasless transaction! - -## Conclusion - -As we conclude, you've not only set up and run a seamless integration between a frontend and zkSync Era Testnet but have -also gained hands-on expertise. You've connected your MetaMask, engaged with smart contracts, and seen the magic of -paymasters unfold right on your local server. - -If you want to continue to learn about paymaster or see additional examples checkout the -[paymaster-examples repo](https://github.com/matter-labs/paymaster-examples) for further inspiration. diff --git a/content/20.build/tutorials/how-to/deposit-erc-20-to-l2.md b/content/20.build/tutorials/how-to/deposit-erc-20-to-l2.md deleted file mode 100644 index c43bf9a5..00000000 --- a/content/20.build/tutorials/how-to/deposit-erc-20-to-l2.md +++ /dev/null @@ -1,168 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Deposit ERC-20 to L2 | zkSync Docs ---- - -# Deposit ERC-20 to L2 - -Depositing ERC-20 tokens from Layer 1 (L1) to Layer 2 (L2) is a vital step to engage with zkSync efficiently. This guide -outlines the process of depositing ERC-20 tokens using the zkSync Javascript SDK, ensuring a streamlined transition of -assets to L2. In zkSync, assets deposited from L1 are secured in a smart contract, while corresponding representations -are created on L2, paving the way for swift and economical transactions. - -:::info Use the **`zks_getBridgeContracts`** endpoint or **`getDefaultBridgeAddresses`** method to get the default -bridge addresses. ::: - -<table><thead><tr><th width="166">Bridge Type</th><th width="101">Network</th><th width="206">L1 Address</th><th>L2 Address</th></tr></thead><tbody><tr><td>ERC-20 Default Bridge</td><td>Mainnet</td><td><code>0x57891966931eb4bb6fb81430e6ce0a03aabde063</code></td><td><code>0x11f943b2c77b743ab90f4a0ae7d5a4e7fca3e102</code></td></tr><tr><td>WETH Bridge</td><td>Mainnet</td><td><code>0x0000000000000000000000000000000000000000</code></td><td><code>0x0000000000000000000000000000000000000000</code></td></tr><tr><td>ERC-20 Default Bridge</td><td>Testnet</td><td><code>0x927ddfcc55164a59e0f33918d13a2d559bc10ce7</code></td><td><code>0x00ff932a6d70e2b8f1eb4919e1e09c1923e7e57b</code></td></tr><tr><td>WETH Bridge</td><td>Testnet</td><td><code>0x0000000000000000000000000000000000000000</code></td><td><code>0x0000000000000000000000000000000000000000</code></td></tr></tbody></table> - -### Prerequisites - -- **Node.js**: Ensure you have Node.js installed. If not, download it from [here](https://nodejs.org/). -- **Private Key**: Have access to a private key for the account you'll be using. -- **L1 RPC Endpoint**: A URL to an Ethereum node to interact with. You can find RPC endpoints for Sepolia and Ethereum - mainnet on [Chainlist](https://chainlist.org/) or use a node provider like Infura. - -### Step 1: Understand L1 - L2 Deposits - -Depositing assets from L1 to L2 involves calling the -[`deposit`](https://github.com/matter-labs/era-contracts/blob/6391c0d7bf6184d7f6718060e3991ba6f0efe4a7/ethereum/contracts/bridge/interfaces/IL1Bridge.sol#L21) -method on the L1 bridge contract. Here's a simplified breakdown of the process: - -1. **Locking L1 Tokens**: Initially, the specified tokens on L1 are sent to the L1 bridge, where they are locked. -2. **Initiating L1 to L2 Transaction**: The L1 bridge then initiates a transaction to the L2 bridge, marking the start - of the deposit process. -3. **Minting L2 Tokens**: Tokens corresponding to the deposit are minted on L2 and sent to the designated L2 address. - - If the token contract isn’t already present on zkSync Era, a new contract is deployed with a new L2 token address, - which is derived from the original L1 address, name, and symbol. -4. **Confirmation Logging**: Each executed L1 to L2 transaction is confirmed with a log message sent from L2 back to L1. -5. **Finalizing Deposit**: Finally, the - [`finalizeDeposit`](https://github.com/matter-labs/era-contracts/blob/6391c0d7bf6184d7f6718060e3991ba6f0efe4a7/zksync/contracts/bridge/L2ERC20Bridge.sol#L62) - method is called on the L2 bridge to complete the deposit process, ensuring the funds are minted on L2. - -This structured flow ensures a secure and orderly transfer of assets from L1 to L2, paving the way for further -interactions on the Layer 2 network. - -### Step 2: Set Up Environment - -Set up the node script: - -::: code-tabs @tab:active yarn - -```bash -mkdir deposit-erc20-script && cd deposit-erc20-script -yarn init -y -yarn add typescript ts-node ethers@^5.7.2 zksync-ethers@5 dotenv -``` - -@tab npm - -```bash -mkdir deposit-erc20-script && cd deposit-erc20-script -npm init -y -npm i typescript ts-node ethers@^5.7.2 zksync-ethers@5 dotenv -``` - -::: - -Create a `.env` file in the project root containing your private key and the L1 RPC endpoint. - -```bash -WALLET_PRIV_KEY=<YOUR_PRIVATE_KEY> -L1_RPC_ENDPOINT=<RPC_URL> -``` - -### Step 3: Create the Deposit Script - -Create a new file `deposit-erc20.ts` and insert the below code: - -#### ERC-20 deposit script - -```typescript -import { Wallet, Provider, utils } from 'zksync-ethers'; -import * as ethers from 'ethers'; - -// load env file -import dotenv from 'dotenv'; -dotenv.config(); - -// HTTP RPC endpoints -const L1_RPC_ENDPOINT = process.env.L1_RPC_ENDPOINT || ''; // or an RPC endpoint from Infura/Chainstack/QuickNode/etc. -const L2_RPC_ENDPOINT = process.env.L2_RPC_ENDPOINT || 'https://testnet.era.zksync.dev'; // or the zkSync Era mainnet - -// ERC-20 Token (DIA) address in L1 -const TOKEN_ADDRESS = '0x5C221E77624690fff6dd741493D735a17716c26B'; - -// Amount of tokens -const AMOUNT = '1'; - -const WALLET_PRIV_KEY = process.env.WALLET_PRIV_KEY || ''; - -if (!WALLET_PRIV_KEY) { - throw new Error('Wallet private key is not configured in env file'); -} - -if (!L1_RPC_ENDPOINT) { - throw new Error('Missing L1 RPC endpoint. Check chainlist.org or an RPC node provider'); -} - -if (!TOKEN_ADDRESS) { - throw new Error('Missing address of the ERC-20 token in L1'); -} - -async function main() { - console.log(`Running script to bridge ERC-20 to L2`); - - // Initialize the wallet. - const l1provider = new Provider(L1_RPC_ENDPOINT); - const l2provider = new Provider(L2_RPC_ENDPOINT); - const wallet = new Wallet(WALLET_PRIV_KEY, l2provider, l1provider); - - console.log(`L1 Balance is ${await wallet.getBalanceL1()}`); - console.log(`L2 Balance is ${await wallet.getBalance()}`); - - // Deposit token to L2 - const depositHandle = await wallet.deposit({ - to: wallet.address, // can bridge to a different address in L2 - token: TOKEN_ADDRESS, - amount: ethers.utils.parseEther(AMOUNT), // assumes ERC-20 has 18 decimals - // performs the ERC-20 approve action - approveERC20: true, - }); - console.log(`Deposit transaction sent ${depositHandle.hash}`); - console.log(`Please wait a few minutes for the deposit to be processed in L2`); -} - -main() - .then() - .catch((error) => { - console.error(error); - process.exitCode = 1; - }); -``` - -### Step 4: Run the Script - -Execute the script using the following command: - -```sh -npx ts-node deposit-erc20.ts -``` - -### Step 5: Verify the Deposit - -Upon running the script, you should see output similar to below, indicating the deposit transaction has been sent and is -being processed on L2: - -```txt -Running script to bridge ERC-20 to L2 -L1 Balance is 19500035772482145 -L2 Balance is 2969807401250000000 -Deposit transaction sent 0xffb8e302430b0584e2e0104dd6295a03688c98ba7b6e9279b01dba65188cc444 -``` - -### Conclusion - -By adhering to this guide, you have successfully deposited ERC-20 tokens from L1 to L2 using the zkSync Javascript SDK, -making a significant stride towards interacting with the zkSync Era. diff --git a/content/20.build/tutorials/how-to/deposit-eth-to-l2.md b/content/20.build/tutorials/how-to/deposit-eth-to-l2.md deleted file mode 100644 index a58c9432..00000000 --- a/content/20.build/tutorials/how-to/deposit-eth-to-l2.md +++ /dev/null @@ -1,160 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Deposit ETH to L2 | zkSync Docs ---- - -# Deposit ETH to L2 - -Depositing assets from L1 to L2 is a fundamental step to interact with zkSync. This guide demonstrates how to deposit -ETH using the Javascript SDK, ensuring a smooth transition of assets to L2. In zkSync, assets deposited from L1 are -locked in a smart contract and corresponding representations of these assets are minted on L2, enabling fast and cheap -transactions. - -:::info Use the **`zks_getBridgeContracts`** endpoint or **`getDefaultBridgeAddresses`** method to get the default -bridge addresses. ::: - -<table><thead><tr><th width="1488">Bridge Type</th><th width="101">Network</th><th width="226">L1 Address</th><th>L2 Address</th></tr></thead><tbody><tr><td>ERC-20 Default Bridge</td><td>Mainnet</td><td><code>0x57891966931eb4bb6fb81430e6ce0a03aabde063</code></td><td><code>0x11f943b2c77b743ab90f4a0ae7d5a4e7fca3e102</code></td></tr><tr><td>WETH Bridge</td><td>Mainnet</td><td><code>0x0000000000000000000000000000000000000000</code></td><td><code>0x0000000000000000000000000000000000000000</code></td></tr><tr><td>ERC-20 Default Bridge</td><td>Testnet</td><td><code>0x927ddfcc55164a59e0f33918d13a2d559bc10ce7</code></td><td><code>0x00ff932a6d70e2b8f1eb4919e1e09c1923e7e57b</code></td></tr><tr><td>WETH Bridge</td><td>Testnet</td><td><code>0x0000000000000000000000000000000000000000</code></td><td><code>0x0000000000000000000000000000000000000000</code></td></tr></tbody></table> - -### Prerequisites - -- **Node.js**: Ensure you have Node.js installed. If not, download it from [here](https://nodejs.org/). -- **Private Key**: Have access to a private key for the account you'll be using. -- **L1 RPC Endpoint**: A URL to an Ethereum node to interact with. You can find RPC endpoints for Sepolia and Ethereum - mainnet on [Chainlist](https://chainlist.org/) or use a node provider like Infura. - -### Step 1: Understand L1 - L2 Deposits - -Depositing assets from L1 to L2 involves calling the -[`deposit`](https://github.com/matter-labs/era-contracts/blob/6391c0d7bf6184d7f6718060e3991ba6f0efe4a7/ethereum/contracts/bridge/interfaces/IL1Bridge.sol#L21) -method on the L1 bridge contract. Here's a simplified breakdown of the process: - -1. **Locking L1 Tokens**: Initially, the specified tokens on L1 are sent to the L1 bridge, where they are locked. -2. **Initiating L1 to L2 Transaction**: The L1 bridge then initiates a transaction to the L2 bridge, marking the start - of the deposit process. -3. **Minting L2 Tokens**: Tokens corresponding to the deposit are minted on L2 and sent to the designated L2 address. - - If the token contract isn’t already present on zkSync Era, a new contract is deployed with a new L2 token address, - which is derived from the original L1 address, name, and symbol. -4. **Confirmation Logging**: Each executed L1 to L2 transaction is confirmed with a log message sent from L2 back to L1. -5. **Finalizing Deposit**: Finally, the - [`finalizeDeposit`](https://github.com/matter-labs/era-contracts/blob/6391c0d7bf6184d7f6718060e3991ba6f0efe4a7/zksync/contracts/bridge/L2ERC20Bridge.sol#L62) - method is called on the L2 bridge to complete the deposit process, ensuring the funds are minted on L2. - -This structured flow ensures a secure and orderly transfer of assets from L1 to L2, paving the way for further -interactions on the Layer 2 network. - -### Step 2: Setup Environment - -Setup the node script: - -::: code-tabs @tab:active yarn - -```bash -mkdir deposit-scripts && cd deposit-scripts -yarn init -y -yarn add typescript ts-node ethers@^5.7.2 zksync-ethers@5 dotenv -``` - -@tab npm - -```bash -mkdir deposit-scripts && cd deposit-scripts -npm init -y -npm i typescript ts-node ethers@^5.7.2 zksync-ethers@5 dotenv -``` - -::: - -Create a `.env` file in the project root containing your private key and the L1 RPC endpoint. - -```bash -WALLET_PRIV_KEY=<YOUR_PRIVATE_KEY> -L1_RPC_ENDPOINT=<RPC_URL> -``` - -### Step 3: Create the Deposit Script - -Create a new file `deposit.ts` and insert the below code: - -#### Deposit script - -```typescript -import { Wallet, Provider, utils } from 'zksync-ethers'; -import * as ethers from 'ethers'; - -// load env file -import dotenv from 'dotenv'; -dotenv.config(); - -// HTTP RPC endpoints -const L1_RPC_ENDPOINT = process.env.L1_RPC_ENDPOINT || ''; // or an RPC endpoint from Infura/Chainstack/QuickNode/etc. -const L2_RPC_ENDPOINT = process.env.L2_RPC_ENDPOINT || 'https://testnet.era.zksync.dev'; // or the zkSync Era mainnet - -// Amount in ETH -const AMOUNT = '0.00001'; - -const WALLET_PRIV_KEY = process.env.WALLET_PRIV_KEY || ''; - -if (!WALLET_PRIV_KEY) { - throw new Error('Wallet private key is not configured in env file'); -} - -if (!L1_RPC_ENDPOINT) { - throw new Error('Missing L1 RPC endpoint. Check chainlist.org or an RPC node provider'); -} - -async function main() { - console.log(`Running script to deposit ETH in L2`); - - // Initialize the wallet. - const l1provider = new Provider(L1_RPC_ENDPOINT); - const l2provider = new Provider(L2_RPC_ENDPOINT); - const wallet = new Wallet(WALLET_PRIV_KEY, l2provider, l1provider); - - console.log(`L1 Balance is ${await wallet.getBalanceL1()}`); - console.log(`L2 Balance is ${await wallet.getBalance()}`); - - // Deposit ETH to L2 - const depositHandle = await wallet.deposit({ - to: wallet.address, - token: utils.ETH_ADDRESS, - amount: ethers.utils.parseEther(AMOUNT), - }); - console.log(`Deposit transaction sent ${depositHandle.hash}`); - console.log(`Please wait a few minutes for the deposit to be processed in L2`); -} - -main() - .then() - .catch((error) => { - console.error(error); - process.exitCode = 1; - }); -``` - -### Step 4: Run the Script - -Execute the script using the following command: - -```sh -npx ts-node deposit.ts -``` - -### Step 5: Verify the Deposit - -Upon running the script, you should see output similar to below, indicating the deposit transaction has been sent and is -being processed on L2: - -```txt -Running script to deposit ETH in L2 -L1 Balance is 6539874840163375070 -L2 Balance is 5712612651486983637 -Deposit transaction sent 0xffb8e302430b0584e2e0104dd6295a03688c98ba7b6e9279b01dba65188cc444 -Please wait a few minutes for the deposit to be processed in L2 -``` - -### Conclusion - -By following this guide, you have successfully deposited ETH from L1 to L2 using the zkSync Javascript SDK. This is a -fundamental step towards interacting with the zkSync Era. diff --git a/content/20.build/tutorials/how-to/estimate-gas.md b/content/20.build/tutorials/how-to/estimate-gas.md deleted file mode 100644 index 12b87af9..00000000 --- a/content/20.build/tutorials/how-to/estimate-gas.md +++ /dev/null @@ -1,363 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Estimate Gas | zkSync Docs ---- - -# Estimate Gas - -### Estimation Methods - -The estimation methods in the zkSync Era JS SDK provide a way to estimate the gas required for various types of -transactions. These methods return a Promise that resolves to a BigNumber, representing the estimated gas cost in wei. - -At the bottom of this section you can see a working example using Stackblitz for each of the method operations. - -### `estimateGas` Method - -#### Overview - -The `estimateGas` method returns a `Promise` that resolves to a `BigNumber` representing an estimate of the amount of -gas required to submit a given transaction to the network. - -:::info Keep in mind that the estimate may not be entirely accurate. Network conditions, such as other transactions -being mined, can affect the actual gas required. ::: - -#### Method Signature - -```typescript -estimateGas(transaction: TransactionRequest): Promise<BigNumber> -``` - -**Parameters** - -| Parameter | Type | Description | -| ------------- | -------------------- | ---------------------------------------------------------------------------- | -| `transaction` | `TransactionRequest` | An object containing the details of the transaction you want to estimate for | - -**TransactionRequest Object** - -| Property | Type | Description | Example | -| -------- | ----------- | --------------------------------------- | ---------------------------------------------- | -| `to` | `string` | The recipient's address | `"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"` | -| `data` | `string` | The transaction data | `"0xd0e30db0"` | -| `value` | `BigNumber` | The value being sent in the transaction | `parseEther("1.0")` | - -#### Return Value - -Returns a `Promise` that resolves to a `BigNumber` representing the estimated gas cost. - -#### Example Usage - -Here's how you can use `estimateGas` to estimate the gas for a deposit transaction:\` - -::code-group - -```typescript [ts] -import { Provider } from 'zksync-ethers'; -import { utils } from 'ethers'; - -const provider = new Provider('https://testnet.era.zksync.dev'); - -const estimate = await provider.estimateGas({ - // Wrapped ETH address - to: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', - - // `function deposit() payable` - data: '0xd0e30db0', - - // 1 ether - value: utils.parseEther('1.0'), -}); - -console.log(estimate); -``` - -```go [go] -gas, err := client.EstimateGas(context.Background(), ethereum.CallMsg{ - From: wallet.Address(), - To: ReceiptAddress, - Data: calldata, -}) -if err != nil { - log.Panic(err) -} -``` - -```python [py] -web3.eth.estimate_gas({'to': '0xd3CdA913deB6f67967B99D67aCDFa1712C293601', 'from':web3.eth.coinbase, 'value': 12345}) -21000 -``` - -:: - -### `estimateGasL1` Method - -#### Overview - -The `estimateGasL1` method returns a `Promise` that resolves to a `BigNumber`, providing an estimate of the amount of -gas required to submit a transaction from Layer 1 (L1) to Layer 2 (L2). - -#### Method Signature - -```typescript -provider.estimateGasL1(transaction: <TransactionRequest>): Promise<BigNumber> -``` - -**Parameters** - -| Parameter | Type | Description | -| ------------- | -------------------- | ------------------------------------------------------------------------------------- | -| `transaction` | `TransactionRequest` | An object containing the details of the L1 to L2 transaction you want to estimate for | - -**TransactionRequest Object** - -| Property | Type | Description | Example | -| ------------ | ----------- | ------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------- | -| `to` | `string` | The recipient's address on L2 | `"0xYourL2AddressHere"` | -| `data` | `string` | The transaction data | `"0xYourDataHere"` | -| `value` | `BigNumber` | The value being sent in the transaction | `parseEther("1.0")` | -| `customData` | `any` | Custom data for the transaction (optional) | `<pre class="language-typescript" data-overflow="wrap"><code class="lang-typescript">customData: { gasPerPubdataByte: 0 } </code></pre>` | -| | | | | - -#### Return Value - -Returns a `Promise` that resolves to a `BigNumber` representing the estimated gas cost for the L1 to L2 transaction. - -#### Example Usage - -Here's how you can use `estimateGasL1` to estimate the gas for a transaction from L1 to L2: - -```typescript -import { Provider, utils } from 'zksync-ethers'; -import { utils } from 'ethers'; - -// Initialize a new Provider instance -const provider = new Provider('https://testnet.era.zksync.dev'); - -// Define the transaction details -const transaction = { - to: '0x1111111111111111111111111111111111111111', - data: '0xffffffff', - value: utils.parseEther('1.0'), - customData: { gasPerPubdataByte: 0 }, -}; - -// Estimate the gas -const estimate = await provider.estimateGasL1(transaction); - -// Log the estimated gas -console.log(`Estimated gas for L1 to L2 transaction: ${estimate}`); -``` - -### `estimateGasTransfer` Method - -#### Overview - -The `estimateGasTransfer` method returns a `Promise` that resolves to a `BigNumber`, providing an estimate of the amount -of gas required to execute a token transfer transaction. - -#### Method Signature - -```typescript -provider.estimateGasTransfer(transaction: { - to: Address; - amount: BigNumberish; - from?: Address; - token?: Address; - overrides?: ethers.CallOverrides; -}): Promise<BigNumber> -``` - -**Parameters** - -| Parameter | Type | Description | -| ------------- | -------- | ------------------------------------------------------------------------------------------- | -| `transaction` | `Object` | An object containing the details of the token transfer transaction you want to estimate for | - -**Transaction Object** - -| Property | Type | Description | Example | -| ----------- | --------------------------------- | ------------------------------- | -------------------------- | -| `to` | `Address` | The recipient's address | `"0xRecipientAddressHere"` | -| `amount` | `BigNumberish` | The amount of token to transfer | `1000` | -| `from` | `Address` (Optional) | The sender's address | `"0xSenderAddressHere"` | -| `token` | `Address` (Optional) | The token's contract address | `"0xTokenAddressHere"` | -| `overrides` | `ethers.CallOverrides` (Optional) | Ethers call overrides object | `{ gasLimit: 21000 }` | - -#### Return Value - -Returns a `Promise` that resolves to a `BigNumber` representing the estimated gas cost for the token transfer -transaction. - -#### Example Usage - -Here's how you can use `estimateGasTransfer` to estimate the gas for a token transfer transaction: - -```typescript -import { Provider } from 'zksync-ethers'; -import { BigNumber } from 'ethers'; - -// Initialize a new Provider instance -const provider = new Provider('https://testnet.era.zksync.dev'); - -// Define the transaction details -const transaction = { - to: '0xRecipientAddressHere', - amount: BigNumber.from('1000'), - from: '0xSenderAddressHere', - token: '0xTokenAddressHere', - overrides: { gasLimit: 21000 }, -}; - -// Estimate the gas -const estimate = await provider.estimateGasTransfer(transaction); - -// Log the estimated gas -console.log(`Estimated gas for token transfer: ${estimate}`); -``` - -### `estimateGasWithdraw` Method - -#### Overview - -The `estimateGasWithdraw` method returns a `Promise` that resolves to a `BigNumber`, providing an estimate of the amount -of gas required to execute a token withdrawal transaction. - -#### Method Signature - -```typescript -provider.estimateGasWithdraw(transaction: { - token: Address; - amount: BigNumberish; - from?: Address; - to?: Address; - bridgeAddress?: Address; - overrides?: ethers.CallOverrides; -}): Promise<BigNumber> -``` - -**Parameters** - -| Parameter | Type | Description | -| ------------- | -------- | --------------------------------------------------------------------------------------------- | -| `transaction` | `Object` | An object containing the details of the token withdrawal transaction you want to estimate for | - -**Transaction Object** - -| Property | Type | Description | Example | -| --------------- | --------------------------------- | ------------------------------- | -------------------------- | -| `token` | `Address` | The token's contract address | `"0xTokenAddressHere"` | -| `amount` | `BigNumberish` | The amount of token to withdraw | `1000` | -| `from` | `Address` (Optional) | The sender's address | `"0xSenderAddressHere"` | -| `to` | `Address` (Optional) | The recipient's address | `"0xRecipientAddressHere"` | -| `bridgeAddress` | `Address` (Optional) | The bridge contract address | `"0xBridgeAddressHere"` | -| `overrides` | `ethers.CallOverrides` (Optional) | Ethers call overrides object | `{ gasLimit: 21000 }` | - -#### Return Value - -Returns a `Promise` that resolves to a `BigNumber` representing the estimated gas cost for the token withdrawal -transaction. - -#### Example Usage - -Here's how you can use `estimateGasWithdraw` to estimate the gas for a token withdrawal transaction: - -```typescript -import { Provider } from 'zksync-ethers'; -import { BigNumber } from 'ethers'; - -// Initialize a new Provider instance -const provider = new Provider('https://testnet.era.zksync.dev'); - -// Define the transaction details -const transaction = { - token: '0xTokenAddressHere', - amount: BigNumber.from('1000'), - from: '0xSenderAddressHere', - to: '0xRecipientAddressHere', - bridgeAddress: '0xBridgeAddressHere', - overrides: { gasLimit: 21000 }, -}; - -// Estimate the gas -const estimate = await provider.estimateGasWithdraw(transaction); - -// Log the estimated gas -console.log(`Estimated gas for token withdrawal: ${estimate}`); -``` - -### `estimateL1ToL2Execute` Method - -#### Overview - -The `estimateL1ToL2Execute` method returns a `Promise` that resolves to a `BigNumber`, providing an estimate of the -amount of gas required to execute an L1 to L2 operation. - -#### Method Signature - -```typescript -provider.estimateL1ToL2Execute(transaction: { - contractAddress: Address; - calldata: BytesLike; - caller?: Address; - l2Value?: BigNumberish; - factoryDeps?: ethers.BytesLike[]; - gasPerPubdataByte?: BigNumberish; - overrides?: ethers.PayableOverrides; -}): Promise<BigNumber> -``` - -**Parameters** - -| Parameter | Type | Description | -| ------------- | -------- | ----------------------------------------------------------------------------------- | -| `transaction` | `Object` | An object containing the details of the L1 to L2 operation you want to estimate for | - -**Transaction Object** - -| Property | Type | Description | Example | -| ------------------- | ------------------------------------ | ---------------------------------------------------- | -------------------------------- | -| `contractAddress` | `Address` | The contract's address | `"0xContractAddressHere"` | -| `calldata` | `BytesLike` | The transaction call data | `"0xSomeCallDataHere"` | -| `caller` | `Address` (Optional) | The caller's address | `"0xCallerAddressHere"` | -| `l2Value` | `BigNumberish` (Optional) | Current L2 gas value | `1000` | -| `factoryDeps` | `ethers.BytesLike[]` (Optional) | Byte array containing contract bytecode | `["0xByteCode1", "0xByteCode2"]` | -| `gasPerPubdataByte` | `BigNumberish` (Optional) | Constant representing current amount of gas per byte | `100` | -| `overrides` | `ethers.PayableOverrides` (Optional) | Ethers payable overrides object | `{ gasLimit: 21000 }` | - -#### Return Value - -Returns a `Promise` that resolves to a `BigNumber` representing the estimated gas cost for the L1 to L2 operation. - -#### Example Usage - -Here's how you can use `estimateL1ToL2Execute` to estimate the gas for an L1 to L2 operation: - -```typescript -typescriptCopy codeimport { Provider } from "zksync-ethers"; -import { BigNumber } from "ethers"; - -// Initialize a new Provider instance -const provider = new Provider("https://testnet.era.zksync.dev"); - -// Define the transaction details -const transaction = { - contractAddress: "0xContractAddressHere", - calldata: "0xSomeCallDataHere", - caller: "0xCallerAddressHere", - l2Value: BigNumber.from("1000"), - factoryDeps: ["0xByteCode1", "0xByteCode2"], - gasPerPubdataByte: BigNumber.from("100"), - overrides: { gasLimit: 21000 } -}; - -// Estimate the gas -const estimate = await provider.estimateL1ToL2Execute(transaction); - -// Log the estimated gas -console.log(`Estimated gas for L1 to L2 operation: ${estimate}`); -``` - -#### Try out gas estimation diff --git a/content/20.build/tutorials/how-to/send-message-l2-l1.md b/content/20.build/tutorials/how-to/send-message-l2-l1.md deleted file mode 100644 index d4f082b3..00000000 --- a/content/20.build/tutorials/how-to/send-message-l2-l1.md +++ /dev/null @@ -1,365 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Send an L2 to L1 Message | zkSync Docs ---- - -# Send an L2 to L1 message - -It is impossible to send transactions directly from L2 to L1. - -Instead, you can send arbitrary-length messages from zkSync Era to Ethereum, and then handle the received message on -Ethereum with an L1 smart contract. - -:::warning What is a message? - -- A message is like an event on Ethereum. -- The difference is that a message publishes data on L1. - -- [Solidity representation](https://github.com/matter-labs/era-contracts/blob/6250292a98179cd442516f130540d6f862c06a16/l1-contracts/contracts/zksync/Storage.sol#L60): - `solidity struct L2Message { address sender; bytes data; uint256 txNumberInblock; } ` ::: - -:::tip Verification - -- Verification and confirmation is possible using Ethereum data. -- However, zkSync Era has an efficient [request proof function](#prove-the-result) which does the same. ::: - -## Common use cases - -Along with zkSync Era's built-in censorship resistance that requires multi-layer interoperability, there are some common -use cases that need L2 to L1 transaction functionality, such as: - -- Bridging funds from L2 to L1. -- Layer 2 governance. - -## Step-by-step - -1. Create a project folder and `cd` into it - -```sh -mkdir message-l2 -cd message-l2 -``` - -2. Run - -```sh -yarn init add -y -``` - -3. Run - -```sh -yarn add -D @matterlabs/zksync-contracts -``` - -4. Import the zkSync Era library or contract containing the required functionality. - -```sh -yarn add zksync-ethers@5 ethers@5 typescript @types/node ts-node -``` - -5. In the root folder add `.env` file with private key of wallet to use - -```js -'RICH_WALLET_PRIV_KEY=0x..'; -``` - -6. Create a `file.ts` file in the root directory with the next script: - -```ts -// The following script sends a message from L2 to L1, retrieves the message proof, and validates that the message received in L1 came from an L2 block. -import * as ethers from 'ethers'; -import { Provider, utils, Wallet } from 'zksync-ethers'; - -import dotenv from 'dotenv'; -dotenv.config(); - -const TEST_PRIVATE_KEY = process.env.WALLET_PRIVATE_KEY || ''; - -const MESSAGE = 'Some L2->L1 message'; - -const l2Provider = new Provider('https://sepolia.era.zksync.dev'); -const l1Provider = ethers.getDefaultProvider('sepolia'); - -const wallet = new Wallet(TEST_PRIVATE_KEY, l2Provider, l1Provider); - -async function sendMessageToL1(text: string) { - console.log(`Sending message to L1 with text ${text}`); - const textBytes = ethers.utils.toUtf8Bytes(MESSAGE); - - const messengerContract = new ethers.Contract(utils.L1_MESSENGER_ADDRESS, utils.L1_MESSENGER, wallet); - const tx = await messengerContract.sendToL1(textBytes); - await tx.wait(); - console.log('L2 trx hash is ', tx.hash); - return tx; -} - -async function getL2MessageProof(blockNumber: ethers.BigNumberish) { - console.log(`Getting L2 message proof for block ${blockNumber}`); - return await l2Provider.getMessageProof( - blockNumber, - wallet.address, - ethers.utils.keccak256(ethers.utils.toUtf8Bytes(MESSAGE)) - ); -} - -async function proveL2MessageInclusion(l1BatchNumber: ethers.BigNumberish, proof: any, trxIndex: number) { - const zkAddress = await l2Provider.getMainContractAddress(); - - const mailboxL1Contract = new ethers.Contract(zkAddress, utils.ZKSYNC_MAIN_ABI, l1Provider); - // all the information of the message sent from L2 - const messageInfo = { - txNumberInBlock: trxIndex, - sender: wallet.address, - data: ethers.utils.toUtf8Bytes(MESSAGE), - }; - - console.log(`Retrieving proof for batch ${l1BatchNumber}, transaction index ${trxIndex} and proof id ${proof.id}`); - - const res = await mailboxL1Contract.proveL2MessageInclusion(l1BatchNumber, proof.id, messageInfo, proof.proof); - - return res; -} - -/** - * Full end-to-end of an L2-L1 messaging with proof validation. - * Recommended to run in 3 steps: - * 1. Send message. - * 2. Wait for transaction to finalize and block verified - * 3. Wait for block to be verified and validate proof - */ -async function main() { - // Step 1: send message - const l2Trx = await sendMessageToL1(MESSAGE); - - console.log('Waiting for transaction to finalize...'); - - // Step 2: waiting to finalize can take a few minutes. - const l2Receipt = await l2Trx.waitFinalize(); - - // Step 3: get and validate proof (block must be verified) - const proof = await getL2MessageProof(l2Receipt.blockNumber); - - console.log(`Proof is: `, proof); - - const { l1BatchNumber, l1BatchTxIndex } = await l2Provider.getTransactionReceipt(l2Receipt.transactionHash); - - console.log('L1 Index for Tx in block :>> ', l1BatchTxIndex); - - console.log('L1 Batch for block :>> ', l1BatchNumber); - - // IMPORTANT: This method requires that the block is verified - // and sent to L1! - const result = await proveL2MessageInclusion( - l1BatchNumber, - proof, - // @ts-ignore - l1BatchTxIndex - ); - - console.log('Result is :>> ', result); - process.exit(); -} - -try { - main(); -} catch (error) { - console.error(error); -} -``` - -6. Add the following lines to your `package.json` in the root folder: - -```json -"scripts": { - "run-file": "ts-node file.ts" -} -``` - -7. To run the script, execute: - -```bash -yarn run-file -``` - -### Example output - -```sh -Sending message to L1 with text Some L2->L1 message -L2 trx hash is 0xb6816e16906788ea5867bf868693aa4e7a46b68ccd2091be345e286a984cb39b -Waiting for transaction to finalize... -Getting L2 message proof for block 5382192 -Proof is: { - id: 14, - proof: [ - '0xd92e806d774b16f21a00230a5ee93555dde30138daf8dbbc8c225ad4aa670edd', - '0xf970801623a03cf02838550dcca2ecf575ace6ae824e5a3339426e69a582c2d8', - '0x389719c677f61f2681950c2136df476e78e74016268806986d4f0599e8055a4b', - '0xb1bde90366b509799bd535f03da87f4c2b68e305bfb5166e694809c4caf0df69', - '0x94b863aefb6546c8465f7700ec701f6b97ddf71a165a6d1e1ce1dc3c41db2534', - '0x1798a1fd9c8fbb818c98cff190daa7cc10b6e5ac9716b4a2649f7c2ebcef2272', - '0x66d7c5983afe44cf15ea8cf565b34c6c31ff0cb4dd744524f7842b942d08770d', - '0xb04e5ee349086985f74b73971ce9dfe76bbed95c84906c5dffd96504e1e5396c', - '0xac506ecb5465659b3a927143f6d724f91d8d9c4bdb2463aee111d9aa869874db' - ], - root: '0xbc872eb80a7d5d35dd16283c1b1a768b1e1c36404000edaaa04868c7d6a5907c' -} -L1 Index for Tx in block :>> 32 -L1 Batch for block :>> 77512 -Retrieving proof for batch 77512, transaction index 32 and proof id 14 -Result is :>> true -``` - -## Send a message - -Two transactions are required: - -- An L2 transaction which sends a message of arbitrary length. -- An L1 read; implemented by a getter function on an L1 smart contract. - -1. Get a `Contract` object that represents the - [`L1Messenger`](../../../zk-stack/components/smart-contracts/system-contracts.md#l1messenger) contract. - -2. Transform the request into a raw bytes array. - -3. Use the - [`sendToL1`](https://github.com/matter-labs/era-contracts/blob/6250292a98179cd442516f130540d6f862c06a16/system-contracts/contracts/interfaces/IL1Messenger.sol#L44) - function from the - [`IL1Messenger.sol`](https://github.com/matter-labs/era-contracts/blob/6250292a98179cd442516f130540d6f862c06a16/system-contracts/contracts/interfaces/IL1Messenger.sol) - interface, passing the message as a raw bytes array. - -Each sent message emits an -[`L1MessageSent`](https://github.com/matter-labs/era-contracts/blob/6250292a98179cd442516f130540d6f862c06a16/system-contracts/contracts/interfaces/IL1Messenger.sol#L38) -event. - -```solidity -event L1MessageSent(address indexed _sender, bytes32 indexed _hash, bytes _message); - -function sendToL1(bytes memory _message) external returns (bytes32); -``` - -3.1 The return value from `sendToL1` is the `keccak256` hash of the message bytes. - -## Prove the result - -The -[`proveL2MessageInclusion`](https://github.com/matter-labs/era-contracts/blob/6250292a98179cd442516f130540d6f862c06a16/l1-contracts/contracts/zksync/facets/Mailbox.sol#L35) -function returns a boolean parameter indicating whether the message was sent successfully to L1. - -```solidity -function proveL2MessageInclusion( - uint256 _blockNumber, - uint256 _index, - L2Message memory _message, - bytes32[] calldata _proof -) public view returns (bool) { - return _proveL2LogInclusion(_blockNumber, _index, _L2MessageToLog(_message), _proof); -} -``` - -:::tip Parameter details - -- `_blockNumber`: L1 batch number in which the L2 block was included; retrievable using the `getBlock` method. -- `_index`: Index of the L2 log in the block; returned as `id` by the - [`zks_getL2ToL1LogProof`](../../api.md#zks-getl2tol1logproof) method. -- `_message`: Parameter holding the message data. It should be an object containing: - - `sender`: Address that sent the message from L2. - - `data`: Message sent in bytes. - - `txNumberInBlock`: Index of the transaction in the L2 block; returned as `transactionIndex` with - [`getTransactionReceipt`](https://docs.ethers.org/v5/single-page/#/v5/api/providers/provider/-%23-Provider-getTransactionReceipt) - on an Ethers `Provider` object. -- `_proof`: Merkle proof of the message inclusion; retrieved by observing Ethereum or using the `zks_getL2ToL1LogProof` - method of the zksync web3 API. ::: - -## Example - -::: code-tabs @tab Solidity 1 - -```solidity -// The Example contract below sends its address to L1 via the Messenger system contract. -//SPDX-License-Identifier: Unlicense -pragma solidity ^0.8.0; - -// Importing interfaces and addresses of the system contracts -import "@matterlabs/zksync-contracts/l2/system-contracts/Constants.sol"; - -contract Example { - function sendMessageToL1() external returns(bytes32 messageHash) { - // Construct the message directly on the contract - bytes memory message = abi.encode(address(this)); - - messageHash = L1_MESSENGER_CONTRACT.sendToL1(message); - } -} -``` - -@tab Solidity 2 - -```solidity -// This contract receives the information related to the transaction sent to the L2 messenger contract. -// It then proves that the message was included in an L2 block. -//SPDX-License-Identifier: Unlicense -pragma solidity ^0.8.0; - -// Importing zkSync contract interface -import "@matterlabs/zksync-contracts/l1/contracts/zksync/interfaces/IZkSync.sol"; - -contract Example { - // NOTE: The zkSync contract implements only the functionality for proving that a message belongs to a block - // but does not guarantee that such a proof was used only once. That's why a contract that uses L2 to L1 - // communication must take care of the double handling of the message. - /// @dev mapping L2 block number => message number => flag - /// @dev Used to indicated that zkSync L2 to L1 message was already processed - mapping(uint256 => mapping(uint256 => bool)) isL2ToL1MessageProcessed; - - function consumeMessageFromL2( - // The address of the zkSync smart contract. - // It is not recommended to hardcode it during the alpha testnet as regenesis may happen. - address _zkSyncAddress, - // zkSync block number in which the message was sent - uint256 _l2BlockNumber, - // Message index, that can be received via API - uint256 _index, - // The tx number in block - uint16 _l2TxNumberInBlock, - // The message that was sent from l2 - bytes calldata _message, - // Merkle proof for the message - bytes32[] calldata _proof - ) external { - // check that the message has not been processed yet - require(!isL2ToL1MessageProcessed[_l2BlockNumber][_index]); - - IZkSync zksync = IZkSync(_zkSyncAddress); - address someSender = 0x19A5bFCBE15f98Aa073B9F81b58466521479DF8D; - L2Message memory message = L2Message({sender: someSender, data: _message, txNumberInBlock:_l2TxNumberInBlock}); - - bool success = zksync.proveL2MessageInclusion( - _l2BlockNumber, - _index, - message, - _proof - ); - require(success, "Failed to prove message inclusion"); - - // Mark message as processed - isL2ToL1MessageProcessed[_l2BlockNumber][_index] = true; - } -} -``` - -@tab Python - -```sh -// In progress. Check back later. -``` - -@tab Go - -```sh -// In progress. Check back later. -``` - -::: diff --git a/content/20.build/tutorials/how-to/send-transaction-l1-l2.md b/content/20.build/tutorials/how-to/send-transaction-l1-l2.md deleted file mode 100644 index abf63833..00000000 --- a/content/20.build/tutorials/how-to/send-transaction-l1-l2.md +++ /dev/null @@ -1,441 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Send an L1 to L2 Transaction | zkSync Docs ---- - -# Send an L1 to L2 transaction - -The [zkSync Era smart contracts](https://github.com/matter-labs/era-contracts/tree/main/l1-contracts/contracts/zksync) -allow the sender to request transactions on Ethereum L1 and pass data to zkSync Era L2. - -## Common use cases - -Along with zkSync Era's built-in censorship resistance that requires multi-layer interoperability, there are some common -use cases that need L1 to L2 transaction functionality, such as: - -- Custom bridges. -- Multi-layer governing smart contracts. - -## Step-by-step - -1. Import the zkSync Era library or contract containing the required functionality. - - The import gives access to the - [`IZkSync.sol`](https://github.com/matter-labs/era-contracts/blob/main/l1-contracts/contracts/zksync/interfaces/IZkSync.sol) - inherited interfaces that include the gas estimation functionality. - - You can do it using yarn (recommended), or [download the contracts](https://github.com/matter-labs/era-contracts) - from the repo. - - ::: code-tabs @tab yarn - - ```shell - yarn init -y - yarn add -D @matterlabs/zksync-contracts - ``` - - ::: - -2. Get the current L1 gas price with Ethereum JSON-RPC method - [`eth_gasPrice`](https://ethereum.github.io/execution-apis/api-documentation/) called with the - [Ethers implementation](https://github.com/ethers-io/ethers.js/blob/f97b92bbb1bde22fcc44100af78d7f31602863ab/packages/providers/src.ts/base-provider.ts#L1428). - - ::: code-tabs @tab TypeScript - - ```ts - async getGasPrice(): Promise<BigNumber> { - await this.getNetwork(); - - const result = await this.perform("getGasPrice", { }); - try { - return BigNumber.from(result); - } catch (error) { - return logger.throwError("bad result from backend", Logger.errors.SERVER_ERROR, { - method: "getGasPrice", - result, error - }); - } - } - ``` - - ::: - -3. Apply an alias to the addresses in the request if the sender address is a contract. - - If the sender is an EOA, no aliasing is required. Aliasing is implemented by the - [`applyL1ToL2Alias`](https://github.com/matter-labs/era-contracts/blob/87cd8d7b0f8c02e9672c0603a821641a566b5dd8/l1-contracts/contracts/vendor/AddressAliasHelper.sol#L28) - Solidity function and called by the - [JavaScript SDK](https://github.com/zksync-sdk/zksync-ethers/blob/28d83cd7f0a8e2978c73f79867143c8e5e7e005f/src/utils.ts#L381). - - ::: code-tabs @tab Solidity - - ```solidity - function applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) { - unchecked { - l2Address = address(uint160(l1Address) + offset); - } - } - ``` - - @tab TypeScript - - ```ts - export function applyL1ToL2Alias(address: string): string { - return ethers.utils.hexlify(ethers.BigNumber.from(address).add(L1_TO_L2_ALIAS_OFFSET).mod(ADDRESS_MODULO)); - } - ``` - - ::: - -4. Call the JSON-RPC method [`zks_estimateGasL1toL2`](../../api.md#zks-estimategasl1tol2), wrapping the transaction data - in a `CallRequest` JSON object parameter. - - The method returns the amount of gas required for the transaction to succeed. - - :::tip Important This value is often referred to as **limit, or gas limit, or L2 gas limit** in our documented - examples. ::: - - ::: code-tabs @tab TypeScript - - ```ts - // available on a zkSync Era JS SDK Provider object - async estimateGasL1(transaction: utils.Deferrable<TransactionRequest>): Promise<BigNumber> { - await this.getNetwork(); - const params = await utils.resolveProperties({ - transaction: this._getTransactionRequest(transaction) - }); - if (transaction.customData != null) { - // @ts-ignore - params.transaction.customData = transaction.customData; - } - const result = await this.send('zks_estimateGasL1ToL2', [ - Provider.hexlifyTransaction(params.transaction, { from: true }) - ]); - try { - return BigNumber.from(result); - } catch (error) { - throw new Error(`bad result from backend (zks_estimateGasL1ToL2): ${result}`); - } - } - ``` - - ::: - -5. Get the base cost by calling the - [`l2TransactionBaseCost`](https://github.com/matter-labs/era-contracts/blob/87cd8d7b0f8c02e9672c0603a821641a566b5dd8/l1-contracts/contracts/zksync/interfaces/IMailbox.sol#L131) - function with: - - - The gas price returned at step 2 as `_gasPrice`. - - The gas value returned at step 3 as `_l2GasLimit`. - - A constant representing how much gas is required to publish a byte of data from L1 to L2 as - `_l2GasPerPubdataByteLimit`. At the time of writing, the JavaScript API provides this constant as - [`REQUIRED_L1_TO_L2_GAS_PER_PUBDATA_LIMIT`](../../sdks/js/utils.md#gas). - - ::: code-tabs @tab Solidity - - ```solidity - function l2TransactionBaseCost( - uint256 _gasPrice, - uint256 _l2GasLimit, - uint256 _l2GasPerPubdataByteLimit - ) external view returns (uint256); - ``` - - @tab TypeScript - - ```ts - async getBaseCost(params: { - gasLimit: BigNumberish; - gasPerPubdataByte?: BigNumberish; - gasPrice?: BigNumberish; - }): Promise<BigNumber> { - const zksyncContract = await this.getMainContract(); - const parameters = { ...layer1TxDefaults(), ...params }; - parameters.gasPrice ??= await this._providerL1().getGasPrice(); - parameters.gasPerPubdataByte ??= REQUIRED_L1_TO_L2_GAS_PER_PUBDATA_LIMIT; - - return BigNumber.from( - await zksyncContract.l2TransactionBaseCost( - parameters.gasPrice, - parameters.gasLimit, - parameters.gasPerPubdataByte - ) - ); - } - ``` - - ::: - -6. The return value is a 256-bit unsigned integer in hexadecimal representing the amount of gas the transaction uses. - - ```json - { - "jsonrpc": "2.0", - "result": "0x25f64db", - "id": 2 - } - ``` - -7. Send the transaction, including the gas price and base cost in the value parameters, by calling the - [`requestL2Transaction`](https://github.com/matter-labs/era-contracts/blob/87cd8d7b0f8c02e9672c0603a821641a566b5dd8/l1-contracts/contracts/zksync/interfaces/IMailbox.sol#L121) - function. - - Include the gas limit value from step 3 as `_l2GasLimit` and the `REQUIRED_L1_TO_L2_GAS_PER_PUBDATA_LIMIT` constant - as `_l2GasPerPubdataByteLimit`. - - The `_refundRecipient` address receives any remaining fee after the transaction completes. If `_refundRecipient = 0` - then L2 `msg.sender` is used. - - ::: code-tabs @tab Solidity - - ```solidity - function requestL2Transaction( - address _contractL2, - uint256 _l2Value, - bytes calldata _calldata, - uint256 _l2GasLimit, - uint256 _l2GasPerPubdataByteLimit, - bytes[] calldata _factoryDeps, - address _refundRecipient - ) external payable returns (bytes32 canonicalTxHash); - ``` - - @tab TypeScript - - ```ts - // Initiate L2 transfer via L1 and execute from zkSync Era wallet (or signer object) - const executeTx = await wallet.requestExecute({ - calldata, - l2GasLimit: gasLimit, - gasPerPubdataByte, - contractAddress: L2_CONTRACT_ADDRESS, - overrides: { - gasPrice, - value: txCostPrice, - }, - }); - ``` - - ::: - - :::tip Solidity parameters description - - - `_contractL2`: L2 address of the contract to be called. - - `_l2Value`: Amount of ETH to pass with the call to L2; used as `msg.value` for the transaction. - - `_calldata`: Calldata of the transaction call; encoded the same way as in Ethereum. - - `_l2GasLimit`: Gas limit of the transaction call obtained in step 3 above. - - `_l2GasPerPubdataByteLimit`: Constant described in step 4 above. - - `_factoryDeps`: Bytecodes array containing the bytecode of the contract being deployed. If the contract is a - factory contract, the array contains the bytecodes of the contracts it can deploy. - - `_refundRecipient`: Address that receives the rest of the fee after the transaction execution. If - `refundRecipient == 0`, L2 `msg.sender` is used. - - **Note**: If the `_refundRecipient` is a smart contract, then during the L1 to L2 transaction its address is aliased. - ::: - -8. Wait for a transaction response and output the details. - - :::info Responses - - - A **successful** L1 to L2 transaction produces an `L2Log` with `key = l2TxHash`, and `value = bytes32(1)`. - - A **failed** L1 to L2 transaction produces an `L2Log` with `key = l2TxHash`, and `value = bytes32(0)`. ::: - -### Example code - -User needs to perform next steps: - -1. Run local node dockerized containers. - [`Instructions how to run it`](https://github.com/matter-labs/local-setup/tree/main) or use - [`zksync-cli`](https://github.com/matter-labs/zksync-cli): - -```shell - npx zksync-cli dev config - // choose: Dockerized node - Persistent state, includes L1 and L2 nodes - // choose: BE and Portal (optional) - npx zksync-cli dev start -``` - -2. In the root folder of the imported project (step 1) create `file.js` and insert there code from example below -3. In the root folder add `.env` file with private key of wallet to use - -```js -'RICH_WALLET_PRIV_KEY=0x..'; -``` - -4. Add script to package.json file next script: - -```js -`"scripts": { "run": "node file.js"},``"type": "module",`; -``` - -5. Run `npm i --save-dev ethers` (in case it is not installed) -6. Run command `npm run` - -Please note, that if you want to run on local-node Dockerized setup use next `hardhat.config.ts`: - -```js -export const zkSyncTestnet = { - url: 'https://localhost:3051', - ethNetwork: 'https://localhost:8545', - zksync: true, -}; -``` - -For Testnet (recommended): - -```js -export const zkSyncTestnet = { - url: 'https://sepolia.era.zksync.dev', - ethNetwork: 'https://rpc.ankr.com/eth_sepolia', - zksync: true, -}; -``` - -And also insert same credentials in `file.js`: - -```js -const L1_RPC_ENDPOINT = '<insert network config here>'; //ethNetwork from instruction above -const L2_RPC_ENDPOINT = '<insert network config here>'; //url from instruction above -``` - -### Example code - -::: code-tabs @tab TypeScript - -```js -import { Contract, Wallet, Provider } from 'zksync-ethers'; -import * as ethers from 'ethers'; - -// load env file -import dotenv from 'dotenv'; -dotenv.config(); - -// Greeter contract ABI for example -const ABI = [ - { - inputs: [ - { - internalType: 'string', - name: '_greeting', - type: 'string', - }, - ], - stateMutability: 'nonpayable', - type: 'constructor', - }, - { - inputs: [], - name: 'greet', - outputs: [ - { - internalType: 'string', - name: '', - type: 'string', - }, - ], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [ - { - internalType: 'string', - name: '_greeting', - type: 'string', - }, - ], - name: 'setGreeting', - outputs: [], - stateMutability: 'nonpayable', - type: 'function', - }, -]; - -// HTTPS RPC endpoints (from local node) -const L1_RPC_ENDPOINT = 'http://localhost:8545'; -const L2_RPC_ENDPOINT = 'http://localhost:3050'; - -const WALLET_PRIV_KEY = process.env.RICH_WALLET_PRIV_KEY || ''; - -if (!WALLET_PRIV_KEY) { - throw new Error('Wallet private key is not configured in env file'); -} - -const L2_CONTRACT_ADDRESS = '0x...'; // - -async function main() { - console.log(`Running script for L1-L2 transaction`); - - // Initialize the wallet. - const l1provider = new Provider(L1_RPC_ENDPOINT); - const l2provider = new Provider(L2_RPC_ENDPOINT); - const wallet = new Wallet(WALLET_PRIV_KEY, l2provider, l1provider); - - // console.log(`L1 Balance is ${await wallet.getBalanceL1()}`); - console.log(`L2 Balance is ${await wallet.getBalance()}`); - - // retrieve L1 gas price - const l1GasPrice = await l1provider.getGasPrice(); - console.log(`L1 gasPrice ${ethers.utils.formatEther(l1GasPrice)} ETH`); - - const contract = new Contract(L2_CONTRACT_ADDRESS, ABI, wallet); - - const msg = await contract.greet(); - - console.log(`Message in contract is ${msg}`); - - const message = `Updated at ${new Date().toUTCString()}`; - - const tx = await contract.populateTransaction.setGreeting(message); - - // call to RPC method zks_estimateGasL1ToL2 to estimate L2 gas limit - const l2GasLimit = await l2provider.estimateGasL1(tx); - - console.log(`L2 gasLimit ${l2GasLimit.toString()}`); - - const baseCost = await wallet.getBaseCost({ - // L2 computation - gasLimit: l2GasLimit, - // L1 gas price - gasPrice: l1GasPrice, - }); - - console.log(`Executing this transaction will cost ${ethers.utils.formatEther(baseCost)} ETH`); - - const iface = new ethers.utils.Interface(ABI); - const calldata = iface.encodeFunctionData('setGreeting', [message]); - - const txReceipt = await wallet.requestExecute({ - contractAddress: L2_CONTRACT_ADDRESS, - calldata, - l2GasLimit: l2GasLimit, - refundRecipient: wallet.address, - overrides: { - // send the required amount of ETH - value: baseCost, - gasPrice: l1GasPrice, - }, - }); - - console.log('L1 tx hash is :>> ', txReceipt.hash); - - txReceipt.wait(); -} - -main() - .then() - .catch((error) => { - console.error(error); - process.exitCode = 1; - }); -``` - -@tab Solidity - -```solidity -// in progress -``` - -::: diff --git a/content/20.build/tutorials/how-to/transfer-token-l2.md b/content/20.build/tutorials/how-to/transfer-token-l2.md deleted file mode 100644 index ba3a0bab..00000000 --- a/content/20.build/tutorials/how-to/transfer-token-l2.md +++ /dev/null @@ -1,198 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Transfer a Token on L2 | zkSync Docs ---- - -# Transfer a token on L2 - -## Prerequisites - -- A [Node.js](https://nodejs.org/en/download) installation. -- The token's address from the [testnet tokens page](https://sepolia.explorer.zksync.io/tokenlist). This document uses - `MCRN` on testnet. - - Check the [mainnet tokens list](https://explorer.zksync.io/tokenlist) for mainnet token addresses. -- Be sure to have some of the token in your wallet. - - Use the [Macaron Swap](https://macaronswap.finance/swap) if you need to swap Sepolia ETH for `MCRN` token. -- You should also know - [how to get your private key from your MetaMask wallet](https://support.metamask.io/hc/en-us/articles/360015289632-How-to-export-an-account-s-private-key). - -## Setup - -### 1. Create a project folder and `cd` into it - -```sh -mkdir transfer-l2 -cd transfer-l2 -``` - -### 2. Add the libraries - -```sh -yarn add zksync-ethers@5 ethers@5 typescript @types/node ts-node -``` - -## Step-by-step - -### 1. Create a script - -```sh -touch transfer-l2.ts -``` - -### 2. Import the libraries - -Open the file and add the following imports: - -```ts -import * as zksync from 'zksync-ethers'; -import * as ethers from 'ethers'; -``` - -### 3. Create a wallet for the sender - -:::tip Check the [JSON-RPC API doc](../../api.md#rpc-endpoint-urls) for the correct RPC endpoint URL. ::: - -Create a zkSync Era provider on testnet and use it to build a zkSync Era wallet, replacing `<SENDER-PRIVATE-KEY>` with -your private key. - -```ts -const zkSyncProvider = new zksync.Provider('https://sepolia.era.zksync.dev'); -const zkSyncWallet = new zksync.Wallet('<SENDER-PRIVATE-KEY>', zkSyncProvider); -``` - -### 4. Store the recipient's public key - -Save the recipient's wallet address to a variable, replacing `<RECIPIENT-PUBLIC-KEY>` with their public key. - -```ts -const receiverWallet = '<RECIPIENT-PUBLIC-KEY>'; -``` - -### 5. Store the token information - -```ts -const l2TokenName = 'MCRN'; -const l2TokenAddress = '0xAFe4cA0Bbe6215cBdA12857e723134Bc3809F766'; -``` - -### 6. Transfer tokens to the recipient - -```ts -async function l2transfer() { - // Amount of Token to transfer - const amount = ethers.BigNumber.from('100000000'); // 0.0000000001 - console.log(`Amount of token to transfer: ${ethers.utils.formatEther(amount)} ${l2TokenName}`); - - // Log the balance of the accounts before transferring - console.log( - `FROM this L2 wallet: "${ethers.utils.formatUnits(await zkSyncProvider.getBalance(zkSyncWallet.address, 'latest', l2TokenAddress), 18)}" ${l2TokenName}` - ); - console.log( - `TO receiver account: "${ethers.utils.formatUnits(await zkSyncProvider.getBalance(receiverWallet, 'latest', l2TokenAddress), 18)}" ${l2TokenName}` - ); - - const transfer = await zkSyncWallet.transfer({ - to: receiverWallet, - token: l2TokenAddress, - amount, - }); - - // Await commitment - const transferReceipt = await transfer.wait(); - console.log(`Tx transfer hash for ${l2TokenName}: ${transferReceipt.blockHash}`); - - // Show the balance of wallets after transfer - console.log( - `FROM this L2 wallet: "${ethers.utils.formatUnits(await zkSyncProvider.getBalance(zkSyncWallet.address, 'latest', l2TokenAddress), 18)}" ${l2TokenName}` - ); - console.log( - `TO receiver wallet: "${ethers.utils.formatUnits(await zkSyncProvider.getBalance(receiverWallet, 'latest', l2TokenAddress), 18)}" ${l2TokenName}` - ); -} -``` - -### 7. Code the call to the transfer function - -```ts -l2transfer(); -``` - -## Full code - -```ts -// Import the relevant libraries -import * as zksync from 'zksync-ethers'; -import * as ethers from 'ethers'; - -// Create zkSync Era provider on testnet -const zkSyncProvider = new zksync.Provider('https://sepolia.era.zksync.dev'); - -// Create a zkSync wallet for the sender -const zkSyncWallet = new zksync.Wallet('<SENDER-PRIVATE-KEY>', zkSyncProvider); - -// Store the recipient public key -const receiverWallet = '<RECIPIENT-PUBLIC-KEY>'; - -// Store the L2 token address -const l2TokenName = 'MCRN'; -const l2TokenAddress = '0xAFe4cA0Bbe6215cBdA12857e723134Bc3809F766'; - -async function l2transfer() { - // Amount of Token to transfer - const amount = ethers.BigNumber.from('100000000'); // 0.0000000001 - console.log(`Amount of token to transfer: ${ethers.utils.formatEther(amount)} ${l2TokenName}`); - - // Log the balance of the accounts before transferring - console.log( - `FROM this L2 wallet: "${ethers.utils.formatUnits(await zkSyncProvider.getBalance(zkSyncWallet.address, 'latest', l2TokenAddress), 18)}" ${l2TokenName}` - ); - console.log( - `TO receiver account: "${ethers.utils.formatUnits(await zkSyncProvider.getBalance(receiverWallet, 'latest', l2TokenAddress), 18)}" ${l2TokenName}` - ); - - const transfer = await zkSyncWallet.transfer({ - to: receiverWallet, - token: l2TokenAddress, - amount, - }); - - // Await commitment - const transferReceipt = await transfer.wait(); - console.log(`Tx transfer hash for ${l2TokenName}: ${transferReceipt.blockHash}`); - - // Show the balance of wallets after transfer - console.log( - `FROM this L2 wallet: "${ethers.utils.formatUnits(await zkSyncProvider.getBalance(zkSyncWallet.address, 'latest', l2TokenAddress), 18)}" ${l2TokenName}` - ); - console.log( - `TO receiver wallet: "${ethers.utils.formatUnits(await zkSyncProvider.getBalance(receiverWallet, 'latest', l2TokenAddress), 18)}" ${l2TokenName}` - ); -} - -l2transfer(); -``` - -## Run the script - -```sh -yarn ts-node transfer-l2.ts -``` - -:::tip Try running the `ts-node transfer-l2.ts` command in case you receive an error with `yarn ts-node transfer-l2.ts`. -::: - -## Output - -You should see output like this: - -```txt -Amount of token to transfer: 0.0000000001 MCRN -FROM this L2 wallet: "0.00000004530161678" MCRN -TO receiver account: "0.0000000001" MCRN -Tx transfer hash for MCRN: 0x254d63addbf4bfaa3e584e6e9a211d769fc0dd56844ae2caa92a3f305c6c0d04 -FROM this L2 wallet: "0.00000004520161678" MCRN -TO receiver wallet: "0.0000000002" MCRN -✨ Done in 4.65s. -``` diff --git a/content/20.build/tutorials/how-to/verify-contracts.md b/content/20.build/tutorials/how-to/verify-contracts.md deleted file mode 100644 index e58ef9c2..00000000 --- a/content/20.build/tutorials/how-to/verify-contracts.md +++ /dev/null @@ -1,333 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Verify Contracts with Hardhat | zkSync Docs ---- - -# Verify Contracts with Hardhat - -Contract source-code verification ensures that the code running on-chain matches your published code. - -The verification process validates and authenticates contracts running on a blockchain network, and enhances -transparency, security, and trust in your smart contracts. - -This document shows you how to verify your contracts with the -[`hardhat-zksync-verify`](https://www.npmjs.com/package/@matterlabs/hardhat-zksync-verify) plugin. - -## Common use cases - -### Transparent contract deployment - -Using the plugin, developers can deploy their contracts on the zkSync Era network with transparency so that users and -other developers can independently verify the contract's source code, and ensure it behaves as expected. - -### Cross-chain interoperability - -For contracts operating across multiple chains, verifying contracts on each network assures users of the contract's -consistency across different networks. - -### Open source projects - -For open-source projects, verifying contracts enhances trust and encourages more developers to contribute. It assures -contributors that the deployed contracts match the source code. - -## Verifying contracts using `hardhat-zksync-verify` - -### 1. Project setup - -1. Scaffold a new project by running the command: - -```sh -npx zksync-cli create verify-greeter-contract --template hardhat_solidity -``` - -This creates a new zkSync Era project called `verify-greeter-contract` with a basic `Greeter` contract and all the -zkSync plugins and configurations. - -2. Proceed by moving into the project directory: - -```sh -cd verify-greeter-contract -``` - -### 2. Package installation for verification - -::: code-tabs @tab yarn - -```bash -yarn add -D @matterlabs/hardhat-zksync-verify @nomicfoundation/hardhat-verify -``` - -@tab npm - -```bash -npm i -D @matterlabs/hardhat-zksync-verify @nomicfoundation/hardhat-verify -``` - -::: - -### 3. Configuration of `hardhat.config.ts` - -Duplicate and insert the following code into the `hardhat.config.ts` file. Ensure the configuration includes the -`verifyURL` attribute that points towards the zkSync Era network. - -```ts -import { HardhatUserConfig } from 'hardhat/config'; - -import '@matterlabs/hardhat-zksync-deploy'; -import '@matterlabs/hardhat-zksync-solc'; -import '@matterlabs/hardhat-zksync-verify'; - -// dynamically alters endpoints for local tests -const zkSyncTestnet = - process.env.NODE_ENV == 'test' - ? { - url: 'http://localhost:3050', - ethNetwork: 'http://localhost:8545', - zksync: true, - } - : { - url: 'https://sepolia.era.zksync.dev', - ethNetwork: 'sepolia', - zksync: true, - verifyURL: 'https://explorer.sepolia.era.zksync.dev/contract_verification', // Verification endpoint - }; - -const config: HardhatUserConfig = { - zksolc: { - version: 'latest', // Uses latest available in https://github.com/matter-labs/zksolc-bin/ - settings: {}, - }, - defaultNetwork: 'zkSyncTestnet', - networks: { - hardhat: { - zksync: false, - }, - zkSyncTestnet, - }, - // etherscan: { // Optional - If you plan on verifying a smart contract on Ethereum within the same project - // apiKey: //<Your API key for Etherscan>, - // }, - solidity: { - version: '0.8.17', - }, -}; - -export default config; -``` - -- Feel free to assign an arbitrary zkSync Era network name utilizing the `defaultNetwork` property. -- The `verifyURL` attribute directs to the verification endpoint specific to the zkSync network. -- If you want to verify a smart contract in other supported block explorer you can set `verifyURL` to point to it's - verification API URL. For example for [L2scan](https://zksync-era.l2scan.co) on mainnet set `verifyURL` to - `https://zksync-era.l2scan.co/api/zksync_contract_verification`. -- If you intend to validate a smart contract on Ethereum within the same project, don't forget to include your - [Etherscan API key](https://docs.etherscan.io/getting-started/viewing-api-usage-statistics). - -### 4. Greeter contract compilation - -The [zkSync CLI](../../tooling/zksync-cli/getting-started.md) provides a `Greeter.sol` contract we will verify on zkSync -Era. - -Compile the contract using this command: - -```sh -yarn hardhat compile -``` - -### 5. Deploy the Greeter contract - -The [zkSync CLI](../../tooling/zksync-cli/getting-started.md) provides a `deploy/deploy-greeter.ts` script that we will -use to deploy the Greeter contract. - -To configure your private key, copy the `.env.example` file, rename the copy to `.env`, and add your wallet private key. - -```text -WALLET_PRIVATE_KEY=YourPrivateKeyHere.... -``` - -Your private key will be used for paying the costs of deploying the smart contract. - -Initiate contract deployment using this command: - -```sh -yarn hardhat deploy-zksync --script deploy-greeter.ts -``` - -Expect an output similar to this: - -```text -Running the deployment function for the Greeter contract -The deployment is estimated to cost 0.0265726735 ETH -constructor args:0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000094869207468657265210000000000000000000000000000000000000000000000 -The Greeter contract got deployed at 0xE84774C41F096Ba5BafA1439cEE787D9dD1A6b72 -``` - -Remember, you need the contract address to verify the contract on zkSync Era. - -### 6. Verify the contract - -Run the following command to verify your contract on the specified network, replacing `<contract address>` with your -deployed contract's address. - -```sh -yarn hardhat verify --network <network> <contract address> -``` - -For example, to verify our Greeter contract on the `zkSyncTestnet` network and our contract address is -`0xE84774C41F096Ba5BafA1439cEE787D9dD1A6b72`, use: - -```sh -yarn hardhat verify --network zkSyncTestnet 0xE84774C41F096Ba5BafA1439cEE787D9dD1A6b72 'Hi there!' -``` - -The verification task attempts to compare the compiled bytecode of all the contracts in your local environment with the -deployed bytecode of the deployed contract you are seeking to verify. If there is no match, it reports an error. - -### 6.1 Verify the contract with fully qualified name - -Specify which contract from your local setup you want to verify using the `--contract` parameter and providing its fully -qualified name. - -```sh -yarn hardhat verify --network <network> <contract address> --contract <fully qualified name> -``` - -A fully qualified name is, for example, `path/sourceName:contractName`. - -For instance, if the source name is `Greeter.sol`, the contract name is `Greeter`, and the contract lives in the -`contracts/` directory, the fully qualified contract name is: `contracts/Greeter.sol:Greeter`. - -Here's an example of command using the `--contract` flag: - -```sh -yarn hardhat verify --network zkSyncTestnet 0xE84774C41F096Ba5BafA1439cEE787D9dD1A6b72 'Hi there!' --contract contracts/Greeter.sol:Greeter -``` - -### 6.2 Verify the contract with constructor arguments - -If your contract was deployed with specific constructor arguments, you need to specify them when running the verify -task. - -```sh -yarn hardhat verify --network testnet <contract address> '<constructor argument>' -``` - -For example, if you're verifying the Greeter contract on the zkSyncTestnet network, your contract address is -`0xE84774C41F096Ba5BafA1439cEE787D9dD1A6b72`, and your constructor argument was 'Hi there!', use: - -```sh -yarn hardhat verify --network zkSyncTestnet 0xE84774C41F096Ba5BafA1439cEE787D9dD1A6b72 'Hi there!' -``` - -### 6.3 Handle complex lists of constructor arguments - -If your contract's constructor includes a complex list of arguments, create a separate JavaScript module to export these -arguments. Here's how you can achieve this: - -#### 6.3.1 Prepare the JavaScript module with arguments - -Start by creating an `arguments.js` file. This file should export an array of arguments that matches the order and types -of the arguments in your contract's constructor. - -For example, if your contract constructor has two string values, an address, and an integer, your `arguments.js` might -look like this: - -```javascript -module.exports = [ - 'string argument 1', // string - 'string argument 2', // string - '0x1234abc...', // address - 42, // integer -]; -``` - -:::warning Make sure the order of arguments in this array matches the order of arguments in your contract's constructor. -::: - -#### 6.3.2 Verify the contract with the constructor arguments file - -Once you have your `arguments.js` file prepared, you can reference it when verifying your contract. The -`--constructor-args` parameter allows you to specify a JavaScript module that exports your constructor arguments. - -Execute the `verify` command, substituting `<contract address>` with your actual contract address: - -```sh -yarn hardhat verify --network zkSyncTestnet <contract address> --constructor-args arguments.js -``` - -For instance, if your contract address was `0xE84774C41F096Ba5BafA1439cEE787D9dD1A6b72`, you'd use: - -```sh -yarn hardhat verify --network zkSyncTestnet 0xE84774C41F096Ba5BafA1439cEE787D9dD1A6b72 --constructor-args arguments.js -``` - -This command verifies the contract on the `zkSyncTestnet` network, using the specific contract address and the -constructor arguments defined in the `arguments.js` file. By following this procedure, you can handle contract -verification for constructors with complex argument types and arrangements. - -### 7. Check verification status - -Once you've submitted your contract for verification, you may want to check the status of your request. This can be -especially useful in cases where verification may take a long time, or if you wish to verify the successful receipt of -your request. - -Use the `verify-status` command to check the status of your verification request. Replace `<your verification id>` with -the verification ID you received when you submitted your contract for verification. - -```sh -yarn hardhat verify-status --verification-id <your verification id> -``` - -For instance, if your verification ID is `12345`, run the following: - -```sh -yarn hardhat verify-status --verification-id 12345 -``` - -This command returns the current status of your verification request. - -:::tip Depending on the network load and complexity of your contract, the verification process may take some time to -complete. ::: - -### 8. Verify smart contract programmatically - -There may be cases where you need to verify your contracts programmatically, for instance, as part of your project's -build or deployment scripts. - -To achieve this, use Hardhat's task runner to call the `verify:verify` task directly from your code. For example: - -```typescript -const contractAddress = '<your contract address>'; -const contractFullyQualifiedName = '<your contract fully qualified name>'; -const constructorArguments = [ - /* your decoded constructor arguments */ -]; - -const verificationId = await hre.run('verify:verify', { - address: contractAddress, - contract: contractFullyQualifiedName, - constructorArguments: constructorArguments, -}); - -console.log(`Verification ID: ${verificationId}`); -``` - -In this script: - -- `contractAddress` is the address of the deployed contract you wish to verify. -- `contractFullyQualifiedName` is the fully qualified name of your contract (including the path to your Solidity file - and contract name, separated by a colon e.g., `"contracts/Greeter.sol:Greeter"`). -- `constructorArguments` is an array containing the arguments used to deploy your contract (e.g. "Hi There"). - -Once this script runs, it prints the verification ID. If the verification request is successful, you can use this ID to -check the status of your verification request. If the request was not successful, the return value and printed ID is -`-1`. - -### 9. UI block explorer alternative - -Contract verification in zkSync Era ensures the integrity and trustworthiness of your contracts. The -[Smart Contract Verification in zkSync Era Block Explorer](https://explorer.zksync.io/contracts/verify) is a manual UI -process for doing the same, ideal for occasional use, while the `hardhat-zksync-verify` plugin facilitates an automated, -flexible approach for developers. diff --git a/content/20.build/tutorials/how-to/withdraw-erc-20-to-l1.md b/content/20.build/tutorials/how-to/withdraw-erc-20-to-l1.md deleted file mode 100644 index e73322f2..00000000 --- a/content/20.build/tutorials/how-to/withdraw-erc-20-to-l1.md +++ /dev/null @@ -1,158 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Withdraw ERC-20 to L1 | zkSync Docs ---- - -# Withdraw ERC-20 to L1 - -Withdrawing assets from Layer 2 (L2) back to Layer 1 (L1) is an essential procedure to retrieve your assets in zkSync. -This guide outlines how to withdraw ETH using the zkSync Javascript SDK, ensuring a successful transfer of assets to L1. -In zkSync, withdrawing involves burning tokens on L2 and unlocking the corresponding funds on the L1 bridge. - -:::info Use the **`zks_getBridgeContracts`** endpoint or **`getDefaultBridgeAddresses`** method to get the default -bridge addresses. ::: - -<table><thead><tr><th width="148">Bridge Type</th><th width="101">Network</th><th width="226">L1 Address</th><th>L2 Address</th></tr></thead><tbody><tr><td>ERC-20 Default Bridge</td><td>Mainnet</td><td><code>0x57891966931eb4bb6fb81430e6ce0a03aabde063</code></td><td><code>0x11f943b2c77b743ab90f4a0ae7d5a4e7fca3e102</code></td></tr><tr><td>WETH Bridge</td><td>Mainnet</td><td><code>0x0000000000000000000000000000000000000000</code></td><td><code>0x0000000000000000000000000000000000000000</code></td></tr><tr><td>ERC-20 Default Bridge</td><td>Testnet</td><td><code>0x927ddfcc55164a59e0f33918d13a2d559bc10ce7</code></td><td><code>0x00ff932a6d70e2b8f1eb4919e1e09c1923e7e57b</code></td></tr><tr><td>WETH Bridge</td><td>Testnet</td><td><code>0x0000000000000000000000000000000000000000</code></td><td><code>0x0000000000000000000000000000000000000000</code></td></tr></tbody></table> - -### Prerequisites - -- **Node.js**: Ensure Node.js is installed. If not, download it from [here](https://nodejs.org/). -- **Private Key**: Have access to a private key for the account you'll be using. -- **L1 RPC Endpoint**: A URL to an Ethereum node to interact with. You can find RPC endpoints for Sepolia and Ethereum - mainnet on [Chainlist](https://chainlist.org/) or use a node provider like Infura. - -### Step 1: Understanding L2 to L1 Withdrawals - -Withdrawing assets from L2 to L1 involves the following steps: - -1. **Burning L2 Tokens**: Initially, the specified tokens on L2 are burned. -2. **Sending L2 to L1 Message**: A message detailing the withdrawal is sent from L2 to L1. -3. **Finalizing Withdrawal**: The `finalizeWithdrawal` method is called on the L1 bridge to complete the withdrawal - process, unlocking the funds from the L1 bridge and sending them to the recipient. - -:::warning During the Alpha phase, **withdrawals in zkSync Era take 24 hours** for additional security. ::: - -### Step 2: Setup Environment - -Create a new directory for your withdrawal scripts and navigate into it: - -::: code-tabs @tab:active yarn - -```bash -mkdir withdraw-erc20-script && cd withdraw-erc20-script -yarn init -y -yarn add typescript ts-node ethers@^5.7.2 zksync-ethers@5 dotenv -``` - -@tab npm - -```bash -mkdir withdraw-erc20-script && cd withdraw-erc20-script -npm init -y -npm i typescript ts-node ethers@^5.7.2 zksync-ethers@5 dotenv -``` - -::: - -Set up environment variables by creating a `.env` file in the project root containing your private key and the L1 RPC -endpoint: - -```bash -WALLET_PRIV_KEY=<YOUR_PRIVATE_KEY> -L1_RPC_ENDPOINT=<RPC_URL> -``` - -### Step 3: Create the Withdrawal Script - -Create a new file `withdraw-erc20.ts` and insert the following code. This script utilizes the `withdraw` method from the -`Wallet` class of the zkSync Javascript SDK to withdraw ETH. Adjust the `AMOUNT` and `TOKEN_ADDRESS` variable if -necessary. - -#### withdraw-erc20.ts script - -```typescript -import { Wallet, Provider, utils } from 'zksync-ethers'; -import * as ethers from 'ethers'; - -// load env file -import dotenv from 'dotenv'; -dotenv.config(); - -// HTTP RPC endpoints -const L1_RPC_ENDPOINT = process.env.L1_RPC_ENDPOINT || ''; // or an RPC endpoint from Infura/Chainstack/QuickNode/etc. -const L2_RPC_ENDPOINT = process.env.L2_RPC_ENDPOINT || 'https://testnet.era.zksync.dev'; // or the zkSync Era mainnet - -// ERC-20 Token address in L2 -const TOKEN_ADDRESS = '<TOKEN_ADDRESS>'; - -// Amount of tokens -const AMOUNT = '5'; - -const WALLET_PRIV_KEY = process.env.WALLET_PRIV_KEY || ''; - -if (!WALLET_PRIV_KEY) { - throw new Error('Wallet private key is not configured in env file'); -} - -if (!L1_RPC_ENDPOINT) { - throw new Error('Missing L1 RPC endpoint. Check chainlist.org or an RPC node provider'); -} - -if (!TOKEN_ADDRESS) { - throw new Error('Missing address of the ERC-20 token in L1'); -} - -async function main() { - console.log(`Running script to bridge ERC-20 to L1`); - - // Initialize the wallet. - const l1provider = new Provider(L1_RPC_ENDPOINT); - const l2provider = new Provider(L2_RPC_ENDPOINT); - const wallet = new Wallet(WALLET_PRIV_KEY, l2provider, l1provider); - - console.log(`L1 Balance is ${await wallet.getBalanceL1()}`); - console.log(`L2 Balance is ${await wallet.getBalance()}`); - - // withdraw ERC-20 token to L2 - const withdrawErc20Handle = await wallet.withdraw({ - to: wallet.address, // can bridge to a different address in L1 - token: TOKEN_ADDRESS, - amount: ethers.utils.parseEther(AMOUNT), // assumes ERC-20 has 18 decimals - }); - console.log(`Withdraw ERC-20 transaction sent ${withdrawErc20Handle.hash}`); -} - -main() - .then() - .catch((error) => { - console.error(error); - process.exitCode = 1; - }); -``` - -### Step 4: Run the Script - -Execute the script using the following command: - -```sh -npx ts-node withdraw.ts -``` - -### Step 5: Verify the Output - -Upon running the script, you should see an output similar to below, indicating the withdrawal transaction has been sent -and is being processed on L1: - -```txt -Running script to bridge ERC-20 to L1 -L1 Balance is 19421054769191270 -L2 Balance is 2969626077250000000 -Withdraw ERC-20 transaction sent 0x280a2168f464c93e8c56df3291076bbb6cff78ebdc30fdaad22bc275d56aa3ed -``` - -### Conclusion - -By following this guide, you have successfully withdrawn ERC-20 token from L2 to L1 using the zkSync Javascript SDK. -This is a significant step towards managing your assets on the zkSync Era. diff --git a/content/20.build/tutorials/how-to/withdraw-eth-to-l1.md b/content/20.build/tutorials/how-to/withdraw-eth-to-l1.md deleted file mode 100644 index df63a2a1..00000000 --- a/content/20.build/tutorials/how-to/withdraw-eth-to-l1.md +++ /dev/null @@ -1,156 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Withdraw ETH to L1 | zkSync Docs ---- - -# Withdraw ETH to L1 - -Withdrawing assets from Layer 2 (L2) back to Layer 1 (L1) is an essential procedure to retrieve your assets in zkSync. -This guide outlines how to withdraw ETH using the zkSync Javascript SDK, ensuring a successful transfer of assets to L1. -In zkSync, withdrawing involves burning tokens on L2 and unlocking the corresponding funds on the L1 bridge. - -:::info Use the **`zks_getBridgeContracts`** endpoint or **`getDefaultBridgeAddresses`** method to get the default -bridge addresses. ::: - -<table><thead><tr><th width="148">Bridge Type</th><th width="101">Network</th><th width="226">L1 Address</th><th>L2 Address</th></tr></thead><tbody><tr><td>ERC-20 Default Bridge</td><td>Mainnet</td><td><code>0x57891966931eb4bb6fb81430e6ce0a03aabde063</code></td><td><code>0x11f943b2c77b743ab90f4a0ae7d5a4e7fca3e102</code></td></tr><tr><td>WETH Bridge</td><td>Mainnet</td><td><code>0x0000000000000000000000000000000000000000</code></td><td><code>0x0000000000000000000000000000000000000000</code></td></tr><tr><td>ERC-20 Default Bridge</td><td>Testnet</td><td><code>0x927ddfcc55164a59e0f33918d13a2d559bc10ce7</code></td><td><code>0x00ff932a6d70e2b8f1eb4919e1e09c1923e7e57b</code></td></tr><tr><td>WETH Bridge</td><td>Testnet</td><td><code>0x0000000000000000000000000000000000000000</code></td><td><code>0x0000000000000000000000000000000000000000</code></td></tr></tbody></table> - -### Prerequisites - -- **Node.js**: Ensure Node.js is installed. If not, download it from [here](https://nodejs.org/). -- **Private Key**: Have access to a private key for the account you'll be using. -- **L1 RPC Endpoint**: A URL to an Ethereum node to interact with. You can find RPC endpoints for Sepolia and Ethereum - mainnet on [Chainlist](https://chainlist.org/) or use a node provider like Infura. - -### Step 1: Understanding L2 to L1 Withdrawals - -Withdrawing assets from L2 to L1 involves the following steps: - -1. **Burning L2 Tokens**: Initially, the specified tokens on L2 are burned. -2. **Sending L2 to L1 Message**: A message detailing the withdrawal is sent from L2 to L1. -3. **Finalizing Withdrawal**: The `finalizeWithdrawal` method is called on the L1 bridge to complete the withdrawal - process, unlocking the funds from the L1 bridge and sending them to the recipient. - -:::warning During the Alpha phase, **withdrawals in zkSync Era take 24 hours** for additional security. ::: - -### Step 2: Setup Environment - -Create a new directory for your withdrawal scripts and navigate into it: - -::: code-tabs @tab:active yarn - -```bash -mkdir withdraw-scripts && cd withdraw-scripts -yarn init -y -yarn add typescript ts-node ethers@^5.7.2 zksync-ethers@5 dotenv -``` - -@tab npm - -```bash -mkdir withdraw-scripts && cd withdraw-scripts -npm init -y -npm i typescript ts-node ethers@^5.7.2 zksync-ethers@5 dotenv -``` - -::: - -Set up environment variables by creating a `.env` file in the project root containing your private key and the L1 RPC -endpoint: - -```bash -WALLET_PRIV_KEY=<YOUR_PRIVATE_KEY> -L1_RPC_ENDPOINT=<RPC_URL> -``` - -### Step 3: Create the Withdrawal Script - -Create a new file `withdraw.ts` and insert the following code. This script utilizes the `withdraw` method from the -`Wallet` class of the zkSync Javascript SDK to withdraw ETH. Adjust the `AMOUNT` variable if necessary. - -#### withdraw.ts script - -```typescript -import { Wallet, Provider, utils } from 'zksync-ethers'; -import * as ethers from 'ethers'; - -// load env file -import dotenv from 'dotenv'; -dotenv.config(); - -// HTTP RPC endpoints -const L1_RPC_ENDPOINT = process.env.L1_RPC_ENDPOINT || ''; // or an RPC endpoint from Infura/Chainstack/QuickNode/etc. -const L2_RPC_ENDPOINT = process.env.L2_RPC_ENDPOINT || 'https://testnet.era.zksync.dev'; // or the zkSync Era mainnet - -// Wallet -const WALLET_PRIV_KEY = process.env.WALLET_PRIV_KEY || ''; - -// Amount in ETH -const AMOUNT = '0.00001'; - -if (!WALLET_PRIV_KEY) { - throw new Error('Wallet private key is not configured in env file'); -} - -if (!L1_RPC_ENDPOINT) { - throw new Error('Missing L1 RPC endpoint. Check chainlist.org or an RPC node provider'); -} - -async function main() { - console.log(`Running script to withdraw ETH to L1`); - - // Initialize the wallet. - const l1provider = new Provider(L1_RPC_ENDPOINT); - const l2provider = new Provider(L2_RPC_ENDPOINT); - const wallet = new Wallet(WALLET_PRIV_KEY, l2provider, l1provider); - - console.log(`L1 Balance is ${await wallet.getBalanceL1()}`); - console.log(`L2 Balance is ${await wallet.getBalance()}`); - - try { - // withdraw ETH to L1 - const withdrawHandle = await wallet.withdraw({ - to: wallet.address, // can bridge to a different address in L1 - token: utils.ETH_ADDRESS, - amount: ethers.utils.parseEther(AMOUNT), - }); - console.log(`Withdraw transaction sent ${withdrawHandle.hash}`); - } catch (error: any) { - console.error(`Error withdrawing: ${error.message}`); - process.exitCode = 1; - } -} - -main() - .then() - .catch((error) => { - console.error(error); - process.exitCode = 1; - }); -``` - -### Step 4: Run the Script - -Execute the script using the following command: - -```sh -npx ts-node withdraw.ts -``` - -### Step 5: Verify the Output - -Upon running the script, you should see an output similar to below, indicating the withdrawal transaction has been sent -and is being processed on L1: - -```txt -Running script to withdraw ETH to L1 -L1 Balance is 6539874840163375070 -L2 Balance is 5712612651486983637 -Withdraw transaction sent 0x4905176d42b4c3b4ab10f611e688b2d849e761493f4583119b7c7731b4254cf4 -``` - -### Conclusion - -By following this guide, you have successfully withdrawn ETH from L2 to L1 using the zkSync Javascript SDK. This is a -significant step towards managing your assets on the zkSync Era. diff --git a/content/20.build/tutorials/smart-contract-development/account-abstraction/custom-aa-tutorial.md b/content/20.build/tutorials/smart-contract-development/account-abstraction/custom-aa-tutorial.md deleted file mode 100644 index ebdd1c41..00000000 --- a/content/20.build/tutorials/smart-contract-development/account-abstraction/custom-aa-tutorial.md +++ /dev/null @@ -1,1223 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Account Abstraction Multisig Tutorial | zkSync Docs ---- - -# Account Abstraction Multisig - -This tutorial shows you how to build and deploy a 2-of-2 multi-signature account via a factory contract, then test it by -sending a transaction. - -## Prerequisites - -- Make sure your machine satisfies the - [system requirements](https://github.com/matter-labs/era-compiler-solidity/tree/main#system-requirements). -- A [Node.js](https://nodejs.org/en/download) installation. -- For background learning, we recommend the following guides: - - Read about the [design](../../../developer-reference/account-abstraction.md) of the account abstraction protocol. - - Read the [introduction to the system contracts](../../../developer-reference/system-contracts.md). - - Read about [smart contract deployment](../../../developer-reference/contract-deployment.md) on zkSync Era. - - Read the [gas estimation for transaction](../../../developer-reference/fee-model.md#gas-estimation-for-transactions) - guide. - - If you haven't already, please refer to the first section of the - [quickstart tutorial](../../../quick-start/hello-world.md). -- You should also know - [how to get your private key from your MetaMask wallet](https://support.metamask.io/hc/en-us/articles/360015289632-How-to-export-an-account-s-private-key). - -::: tip Local zkSync Testing with zksync-cli Skip the hassle for test ETH by using `zksync-cli` for local testing. -Simply execute `npx zksync-cli dev start` to initialize a local zkSync development environment, which includes local -Ethereum and zkSync nodes. This method allows you to test contracts without requesting external testnet funds. Explore -more in the [zksync-cli documentation](../../../tooling/zksync-cli/getting-started.md). ::: - -## Complete Project - -Download the complete project [here](https://github.com/matter-labs/tutorials/tree/main/custom-aa). - -::: info Project available in Atlas IDE This entire tutorial can be run in under a minute using Atlas. Atlas is a smart -contract IDE that lets you write, deploy, and interact with contracts from your browser. -[Open this project in Atlas](https://app.atlaszk.com/projects?template=https://github.com/atlas-labs-inc/zksync-aa-multisig&open=/scripts/main.ts&chainId=300). -::: - -## Setup - -1. Initiate a new project by running the command: - -```sh -npx zksync-cli create custom-aa-tutorial --template hardhat_solidity -``` - -This creates a new zkSync Era project called `custom-aa-tutorial` with a few example contracts. - -2. Navigate into the project directory: - -```sh -cd custom-aa-tutorial -``` - -3. For the purposes of this tutorial, we don't need the example contracts related files. So, proceed by removing all the - files inside the `/contracts` and `/deploy` folders manually or by running the following commands:: - -```sh -rm -rf ./contracts/* -rm -rf ./deploy/* -``` - -4. Add the zkSync and OpenZeppelin contract libraries: - -```sh -yarn add -D @matterlabs/zksync-contracts @openzeppelin/contracts@4.9.5 -``` - -5. Include the `isSystem: true` setting in the `zksolc` section of the `hardhat.config.ts` configuration file to allow - interaction with system contracts: - -::: warning - -This project does not use the latest version available of `@openzeppelin/contracts`. Mae sure you install the specific -version mentioned above. - -::: - -```ts -import { HardhatUserConfig } from 'hardhat/config'; -import '@matterlabs/hardhat-zksync-deploy'; -import '@matterlabs/hardhat-zksync-solc'; - -import '@matterlabs/hardhat-zksync-verify'; - -const config: HardhatUserConfig = { - zksolc: { - version: 'latest', // Uses latest available in https://github.com/matter-labs/zksolc-bin/ - settings: { - isSystem: true, // ⚠️ Make sure to include this line - }, - }, - defaultNetwork: 'zkSyncTestnet', - - networks: { - zkSyncTestnet: { - url: 'https://sepolia.era.zksync.dev', - ethNetwork: 'sepolia', // Can also be the RPC URL of the network (e.g. `https://sepolia.infura.io/v3/<API_KEY>`) - zksync: true, - }, - }, - solidity: { - version: '0.8.20', - }, -}; - -export default config; -``` - -## Account Abstraction - -Each account must implement the [IAccount](../../../developer-reference/account-abstraction.md#iaccount-interface) -interface. Furthermore, since we are building an account with multiple signers, we should implement -[EIP1271](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/83277ff916ac4f58fec072b8f28a252c1245c2f1/contracts/interfaces/IERC1271.sol#L12). - -The skeleton code for the contract is given below. Use it to perform next steps, or you can skip and use completed code -from [Full example](#full-example) section. - -```solidity -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.17; - -import "@matterlabs/zksync-contracts/l2/system-contracts/interfaces/IAccount.sol"; -import "@matterlabs/zksync-contracts/l2/system-contracts/libraries/TransactionHelper.sol"; - -import "@openzeppelin/contracts/interfaces/IERC1271.sol"; - - -contract TwoUserMultisig is IAccount, IERC1271 { - // to get transaction hash - using TransactionHelper for Transaction; - - - bytes4 constant EIP1271_SUCCESS_RETURN_VALUE = 0x1626ba7e; - - modifier onlyBootloader() { - require( - msg.sender == BOOTLOADER_FORMAL_ADDRESS, - "Only bootloader can call this function" - ); - // Continue execution if called from the bootloader. - _; - } - - - function validateTransaction( - bytes32, - bytes32 _suggestedSignedHash, - Transaction calldata _transaction - ) external payable override onlyBootloader returns (bytes4 magic) { - magic = _validateTransaction(_suggestedSignedHash, _transaction); - } - - function _validateTransaction( - bytes32 _suggestedSignedHash, - Transaction calldata _transaction - ) internal returns (bytes4 magic) { - // TO BE IMPLEMENTED - } - - function executeTransaction( - bytes32, - bytes32, - Transaction calldata _transaction - ) external payable override onlyBootloader { - _executeTransaction(_transaction); - } - - function _executeTransaction(Transaction calldata _transaction) internal { - // TO BE IMPLEMENTED - } - - function executeTransactionFromOutside(Transaction calldata _transaction) - external - payable - { - _validateTransaction(bytes32(0), _transaction); - _executeTransaction(_transaction); - } - - function isValidSignature(bytes32 _hash, bytes memory _signature) - public - view - override - returns (bytes4 magic) - { - // TO BE IMPLEMENTED - } - - function payForTransaction( - bytes32, - bytes32, - Transaction calldata _transaction - ) external payable override onlyBootloader { - // TO BE IMPLEMENTED - } - - function prepareForPaymaster( - bytes32, // _txHash - bytes32, // _suggestedSignedHash - Transaction calldata _transaction - ) external payable override onlyBootloader { - // TO BE IMPLEMENTED - } - - // This function verifies that the ECDSA signature is both in correct format and non-malleable - function checkValidECDSASignatureFormat(bytes memory _signature) internal pure returns (bool) { - if(_signature.length != 65) { - return false; - } - - uint8 v; - bytes32 r; - bytes32 s; - // Signature loading code - // we jump 32 (0x20) as the first slot of bytes contains the length - // we jump 65 (0x41) per signature - // for v we load 32 bytes ending with v (the first 31 come from s) then apply a mask - assembly { - r := mload(add(_signature, 0x20)) - s := mload(add(_signature, 0x40)) - v := and(mload(add(_signature, 0x41)), 0xff) - } - if(v != 27 && v != 28) { - return false; - } - - // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature - // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines - // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most - // signatures from current libraries generate a unique signature with an s-value in the lower half order. - // - // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value - // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or - // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept - // these malleable signatures as well. - if(uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) { - return false; - } - - return true; - } - - function extractECDSASignature(bytes memory _fullSignature) internal pure returns (bytes memory signature1, bytes memory signature2) { - require(_fullSignature.length == 130, "Invalid length"); - - signature1 = new bytes(65); - signature2 = new bytes(65); - - // Copying the first signature. Note, that we need an offset of 0x20 - // since it is where the length of the `_fullSignature` is stored - assembly { - let r := mload(add(_fullSignature, 0x20)) - let s := mload(add(_fullSignature, 0x40)) - let v := and(mload(add(_fullSignature, 0x41)), 0xff) - - mstore(add(signature1, 0x20), r) - mstore(add(signature1, 0x40), s) - mstore8(add(signature1, 0x60), v) - } - - // Copying the second signature. - assembly { - let r := mload(add(_fullSignature, 0x61)) - let s := mload(add(_fullSignature, 0x81)) - let v := and(mload(add(_fullSignature, 0x82)), 0xff) - - mstore(add(signature2, 0x20), r) - mstore(add(signature2, 0x40), s) - mstore8(add(signature2, 0x60), v) - } - } - - fallback() external { - // fallback of default account shouldn't be called by bootloader under no circumstances - assert(msg.sender != BOOTLOADER_FORMAL_ADDRESS); - - // If the contract is called directly, behave like an EOA - } - - receive() external payable { - // If the contract is called directly, behave like an EOA. - // Note, that is okay if the bootloader sends funds with no calldata as it may be used for refunds/operator payments - } -} -``` - -:::tip The `onlyBootloader` modifier ensures that only the -[bootloader](../../../developer-reference/system-contracts.md#bootloader) calls the -`validateTransaction`/`executeTransaction`/`payForTransaction`/`prepareForPaymaster` functions. ::: - -The `executeTransactionFromOutside` function allows external users to initiate transactions from this account. We -implement it by calling `validateTransaction` and `executeTransaction`. - -In addition, `checkValidECDSASignatureFormat` and `extractECDSASignature` are helper functions for the -`isValidSignature` implementation. - -### Signature Validation - -We import OpenZeppelin's `ECDSA` library to use for signature validation. - -```solidity -// Used for signature validation -import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; -``` - -Since we are building a two-account multisig, we pass the owners' addresses to the constructor and save their state -variables. - -```solidity -// state variables for account owners -address public owner1; -address public owner2; - - -constructor(address _owner1, address _owner2) { - owner1 = _owner1; - owner2 = _owner2; -} -``` - -To validate the signature we have to implement the following: - -- Check if the length of the received signature is correct. -- Extract the two signatures from the received multisig using the helper function `extractECDSASignature`. -- Check if both signatures are valid using the helper function `checkValidECDSASignatureFormat`. -- Extract the addresses from the transaction hash and each signature using the `ECDSA.recover` function. -- Check if the addresses extracted match with the owners of the account. -- Return the `EIP1271_SUCCESS_RETURN_VALUE` value on success or `bytes4(0)` if validation fails. - -Below is the full implementation of the `isValidSignature` function: - -```solidity -function isValidSignature(bytes32 _hash, bytes memory _signature) - public - view - override - returns (bytes4 magic) -{ - magic = EIP1271_SUCCESS_RETURN_VALUE; - - if (_signature.length != 130) { - // Signature is invalid, but we need to proceed with the signature verification as usual - // in order for the fee estimation to work correctly - _signature = new bytes(130); - - // Making sure that the signatures look like a valid ECDSA signature and are not rejected rightaway - // while skipping the main verification process. - _signature[64] = bytes1(uint8(27)); - _signature[129] = bytes1(uint8(27)); - } - - (bytes memory signature1, bytes memory signature2) = extractECDSASignature(_signature); - - if(!checkValidECDSASignatureFormat(signature1) || !checkValidECDSASignatureFormat(signature2)) { - magic = bytes4(0); - } - - address recoveredAddr1 = ECDSA.recover(_hash, signature1); - address recoveredAddr2 = ECDSA.recover(_hash, signature2); - - // Note, that we should abstain from using the require here in order to allow for fee estimation to work - if(recoveredAddr1 != owner1 || recoveredAddr2 != owner2) { - magic = bytes4(0); - } -} -``` - -### Transaction Validation - -The transaction validation process is responsible for validating the signature of the transaction and incrementing the -nonce. - -:::info - -- There are some [limitations](../../../developer-reference/account-abstraction.md#limitations-of-the-verification-step) - on this function. ::: - -To increment the nonce, use the `incrementMinNonceIfEquals` function from the `NONCE_HOLDER_SYSTEM_CONTRACT` system -contract. It takes the nonce of the transaction and checks whether it is the same as the provided one. If not, the -transaction reverts; otherwise, the nonce increases. - -Even though the requirements above mean the accounts only touch their own storage slots, accessing your nonce in the -`NONCE_HOLDER_SYSTEM_CONTRACT` is a -[whitelisted](../../../developer-reference/account-abstraction.md#extending-the-set-of-slots-that-belong-to-a-user) -case, since it behaves in the same way as your storage, it just happens to be in another contract. - -To call the `NONCE_HOLDER_SYSTEM_CONTRACT`, we add the following import: - -```solidity -// Access zkSync system contracts for nonce validation via NONCE_HOLDER_SYSTEM_CONTRACT -import "@matterlabs/zksync-contracts/l2/system-contracts/Constants.sol"; -``` - -:::info - -- The non-view functions of the `NONCE_HOLDER_SYSTEM_CONTRACT` are called if the `isSystem` flag is on. -- Use the - [systemCallWithPropagatedRevert](https://github.com/matter-labs/era-contracts/blob/6250292a98179cd442516f130540d6f862c06a16/system-contracts/contracts/libraries/SystemContractsCaller.sol#L150) - function of the `SystemContractsCaller` library. -- Import this library also: - `solidity // to call non-view function of system contracts import "@matterlabs/zksync-contracts/l2/system-contracts/libraries/SystemContractsCaller.sol"; ` - ::: - -Use the `TransactionHelper` library, as imported above with `using TransactionHelper for Transaction;` to get the -transaction hash that should be signed. You can also implement your own signature scheme and use a different commitment -for signing the transaction, but in this example, we use the hash provided by this library. - -Finally, the `_validateTransaction` function has to return the constant `ACCOUNT_VALIDATION_SUCCESS_MAGIC` if the -validation is successful, or an empty value `bytes4(0)` if it fails. - -Here is the full implementation for the `_validateTransaction` function: - -```solidity -function _validateTransaction( - bytes32 _suggestedSignedHash, - Transaction calldata _transaction -) internal returns (bytes4 magic) { - // Incrementing the nonce of the account. - // Note, that reserved[0] by convention is currently equal to the nonce passed in the transaction - SystemContractsCaller.systemCallWithPropagatedRevert( - uint32(gasleft()), - address(NONCE_HOLDER_SYSTEM_CONTRACT), - 0, - abi.encodeCall(INonceHolder.incrementMinNonceIfEquals, (_transaction.nonce)) - ); - - bytes32 txHash; - // While the suggested signed hash is usually provided, it is generally - // not recommended to rely on it to be present, since in the future - // there may be tx types with no suggested signed hash. - if (_suggestedSignedHash == bytes32(0)) { - txHash = _transaction.encodeHash(); - } else { - txHash = _suggestedSignedHash; - } - - // The fact there is enough balance for the account - // should be checked explicitly to prevent user paying for fee for a - // transaction that wouldn't be included on Ethereum. - uint256 totalRequiredBalance = _transaction.totalRequiredBalance(); - require(totalRequiredBalance <= address(this).balance, "Not enough balance for fee + value"); - - if (isValidSignature(txHash, _transaction.signature) == EIP1271_SUCCESS_RETURN_VALUE) { - magic = ACCOUNT_VALIDATION_SUCCESS_MAGIC; - } else { - magic = bytes4(0); - } -} -``` - -### Paying Fees for the Transaction - -This section explains the `payForTransaction` function. - -The `TransactionHelper` library already provides us with the `payToTheBootloader` function, that sends -`_transaction.maxFeePerGas * _transaction.gasLimit` ETH to the bootloader. The implementation is straightforward: - -```solidity -function payForTransaction( - bytes32, - bytes32, - Transaction calldata _transaction - ) external payable override onlyBootloader { - bool success = _transaction.payToTheBootloader(); - require(success, "Failed to pay the fee to the operator"); - } -``` - -### Implementing Paymaster Support - -While the account abstraction protocol enables arbitrary actions when interacting with the paymasters, there are some -[common patterns](../../../developer-reference/account-abstraction.md#built-in-paymaster-flows) with built-in support -for EOAs. Unless you want to implement or restrict some specific paymaster use cases for your account, it is better to -keep it consistent with EOAs. - -The `TransactionHelper` library provides the `processPaymasterInput` which does exactly that: processes the paymaster -parameters the same it's done in EOAs. - -```solidity - -function prepareForPaymaster( - bytes32, // _txHash - bytes32, // _suggestedSignedHash - Transaction calldata _transaction - ) external payable override onlyBootloader { - _transaction.processPaymasterInput(); - } -``` - -### Transaction Execution - -To implementing transaction execution, extract the transaction data and execute it: - -```solidity -function _executeTransaction(Transaction calldata _transaction) internal { - uint256 to = _transaction.to; - // By convention, the `reserved[1]` field is msg.value - uint256 value = _transaction.reserved[1]; - bytes memory data = _transaction.data; - - bool success; - // execute transaction - assembly { - success := call(gas(), to, value, add(data, 0x20), mload(data), 0, 0) - } - - // Return value required for the transaction to be correctly processed by the server. - require(success); -} -``` - -Calling `ContractDeployer` is only possible by explicitly using the `isSystem` call flag. - -```solidity -function _executeTransaction(Transaction calldata _transaction) internal { - address to = address(uint160(_transaction.to)); - uint128 value = Utils.safeCastToU128(_transaction.value); - bytes memory data = _transaction.data; - - if (to == address(DEPLOYER_SYSTEM_CONTRACT)) { - uint32 gas = Utils.safeCastToU32(gasleft()); - - // Note, that the deployer contract can only be called - // with a "systemCall" flag. - SystemContractsCaller.systemCallWithPropagatedRevert(gas, to, value, data); - } else { - bool success; - assembly { - success := call(gas(), to, value, add(data, 0x20), mload(data), 0, 0) - } - require(success); - } -} -``` - -:::info - -- Whether or not the operator considers the transaction successful depends on whether the call to `executeTransactions` - is successful. -- Therefore, it is highly recommended to put `require(success)` for the transaction, so that users get the best UX. ::: - -### Full Code of the TwoUserMultisig Contract - -1. Create a file `TwoUserMultisig.sol` in the `contracts` folder and copy/paste the code below into it. - -```solidity -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.17; - -import "@matterlabs/zksync-contracts/l2/system-contracts/interfaces/IAccount.sol"; -import "@matterlabs/zksync-contracts/l2/system-contracts/libraries/TransactionHelper.sol"; - -import "@openzeppelin/contracts/interfaces/IERC1271.sol"; - -// Used for signature validation -import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; - -// Access zkSync system contracts for nonce validation via NONCE_HOLDER_SYSTEM_CONTRACT -import "@matterlabs/zksync-contracts/l2/system-contracts/Constants.sol"; -// to call non-view function of system contracts -import "@matterlabs/zksync-contracts/l2/system-contracts/libraries/SystemContractsCaller.sol"; - -contract TwoUserMultisig is IAccount, IERC1271 { - // to get transaction hash - using TransactionHelper for Transaction; - - // state variables for account owners - address public owner1; - address public owner2; - - bytes4 constant EIP1271_SUCCESS_RETURN_VALUE = 0x1626ba7e; - - modifier onlyBootloader() { - require( - msg.sender == BOOTLOADER_FORMAL_ADDRESS, - "Only bootloader can call this function" - ); - // Continue execution if called from the bootloader. - _; - } - - constructor(address _owner1, address _owner2) { - owner1 = _owner1; - owner2 = _owner2; - } - - function validateTransaction( - bytes32, - bytes32 _suggestedSignedHash, - Transaction calldata _transaction - ) external payable override onlyBootloader returns (bytes4 magic) { - return _validateTransaction(_suggestedSignedHash, _transaction); - } - - function _validateTransaction( - bytes32 _suggestedSignedHash, - Transaction calldata _transaction - ) internal returns (bytes4 magic) { - // Incrementing the nonce of the account. - // Note, that reserved[0] by convention is currently equal to the nonce passed in the transaction - SystemContractsCaller.systemCallWithPropagatedRevert( - uint32(gasleft()), - address(NONCE_HOLDER_SYSTEM_CONTRACT), - 0, - abi.encodeCall(INonceHolder.incrementMinNonceIfEquals, (_transaction.nonce)) - ); - - bytes32 txHash; - // While the suggested signed hash is usually provided, it is generally - // not recommended to rely on it to be present, since in the future - // there may be tx types with no suggested signed hash. - if (_suggestedSignedHash == bytes32(0)) { - txHash = _transaction.encodeHash(); - } else { - txHash = _suggestedSignedHash; - } - - // The fact there is enough balance for the account - // should be checked explicitly to prevent user paying for fee for a - // transaction that wouldn't be included on Ethereum. - uint256 totalRequiredBalance = _transaction.totalRequiredBalance(); - require(totalRequiredBalance <= address(this).balance, "Not enough balance for fee + value"); - - if (isValidSignature(txHash, _transaction.signature) == EIP1271_SUCCESS_RETURN_VALUE) { - magic = ACCOUNT_VALIDATION_SUCCESS_MAGIC; - } else { - magic = bytes4(0); - } - } - - function executeTransaction( - bytes32, - bytes32, - Transaction calldata _transaction - ) external payable override onlyBootloader { - _executeTransaction(_transaction); - } - - function _executeTransaction(Transaction calldata _transaction) internal { - address to = address(uint160(_transaction.to)); - uint128 value = Utils.safeCastToU128(_transaction.value); - bytes memory data = _transaction.data; - - if (to == address(DEPLOYER_SYSTEM_CONTRACT)) { - uint32 gas = Utils.safeCastToU32(gasleft()); - - // Note, that the deployer contract can only be called - // with a "systemCall" flag. - SystemContractsCaller.systemCallWithPropagatedRevert(gas, to, value, data); - } else { - bool success; - assembly { - success := call(gas(), to, value, add(data, 0x20), mload(data), 0, 0) - } - require(success); - } - } - - function executeTransactionFromOutside(Transaction calldata _transaction) - external - payable - { - _validateTransaction(bytes32(0), _transaction); - _executeTransaction(_transaction); - } - - function isValidSignature(bytes32 _hash, bytes memory _signature) - public - view - override - returns (bytes4 magic) - { - magic = EIP1271_SUCCESS_RETURN_VALUE; - - if (_signature.length != 130) { - // Signature is invalid anyway, but we need to proceed with the signature verification as usual - // in order for the fee estimation to work correctly - _signature = new bytes(130); - - // Making sure that the signatures look like a valid ECDSA signature and are not rejected rightaway - // while skipping the main verification process. - _signature[64] = bytes1(uint8(27)); - _signature[129] = bytes1(uint8(27)); - } - - (bytes memory signature1, bytes memory signature2) = extractECDSASignature(_signature); - - if(!checkValidECDSASignatureFormat(signature1) || !checkValidECDSASignatureFormat(signature2)) { - magic = bytes4(0); - } - - address recoveredAddr1 = ECDSA.recover(_hash, signature1); - address recoveredAddr2 = ECDSA.recover(_hash, signature2); - - // Note, that we should abstain from using the require here in order to allow for fee estimation to work - if(recoveredAddr1 != owner1 || recoveredAddr2 != owner2) { - magic = bytes4(0); - } - } - - // This function verifies that the ECDSA signature is both in correct format and non-malleable - function checkValidECDSASignatureFormat(bytes memory _signature) internal pure returns (bool) { - if(_signature.length != 65) { - return false; - } - - uint8 v; - bytes32 r; - bytes32 s; - // Signature loading code - // we jump 32 (0x20) as the first slot of bytes contains the length - // we jump 65 (0x41) per signature - // for v we load 32 bytes ending with v (the first 31 come from s) then apply a mask - assembly { - r := mload(add(_signature, 0x20)) - s := mload(add(_signature, 0x40)) - v := and(mload(add(_signature, 0x41)), 0xff) - } - if(v != 27 && v != 28) { - return false; - } - - // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature - // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines - // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most - // signatures from current libraries generate a unique signature with an s-value in the lower half order. - // - // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value - // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or - // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept - // these malleable signatures as well. - if(uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) { - return false; - } - - return true; - } - - function extractECDSASignature(bytes memory _fullSignature) internal pure returns (bytes memory signature1, bytes memory signature2) { - require(_fullSignature.length == 130, "Invalid length"); - - signature1 = new bytes(65); - signature2 = new bytes(65); - - // Copying the first signature. Note, that we need an offset of 0x20 - // since it is where the length of the `_fullSignature` is stored - assembly { - let r := mload(add(_fullSignature, 0x20)) - let s := mload(add(_fullSignature, 0x40)) - let v := and(mload(add(_fullSignature, 0x41)), 0xff) - - mstore(add(signature1, 0x20), r) - mstore(add(signature1, 0x40), s) - mstore8(add(signature1, 0x60), v) - } - - // Copying the second signature. - assembly { - let r := mload(add(_fullSignature, 0x61)) - let s := mload(add(_fullSignature, 0x81)) - let v := and(mload(add(_fullSignature, 0x82)), 0xff) - - mstore(add(signature2, 0x20), r) - mstore(add(signature2, 0x40), s) - mstore8(add(signature2, 0x60), v) - } - } - - function payForTransaction( - bytes32, - bytes32, - Transaction calldata _transaction - ) external payable override onlyBootloader { - bool success = _transaction.payToTheBootloader(); - require(success, "Failed to pay the fee to the operator"); - } - - function prepareForPaymaster( - bytes32, // _txHash - bytes32, // _suggestedSignedHash - Transaction calldata _transaction - ) external payable override onlyBootloader { - _transaction.processPaymasterInput(); - } - - fallback() external { - // fallback of default account shouldn't be called by bootloader under no circumstances - assert(msg.sender != BOOTLOADER_FORMAL_ADDRESS); - - // If the contract is called directly, behave like an EOA - } - - receive() external payable { - // If the contract is called directly, behave like an EOA. - // Note, that is okay if the bootloader sends funds with no calldata as it may be used for refunds/operator payments - } -} -``` - -## The Factory - -1. Create a new Solidity file in the `contracts` folder called `AAFactory.sol`. - -The contract is a factory that deploys the accounts. - -:::warning - -- To deploy the multisig smart contract, it is necessary to interact with the `DEPLOYER_SYSTEM_CONTRACT` and call the - `create2Account` function. -- If the code doesn't do this, you may see errors like `Validation revert: Sender is not an account`. -- Read the documentation on using - [`create2Account` during the deployment process](../../../developer-reference/account-abstraction.md#the-deployment-process) - for more information. ::: - -1. Copy/paste the following code into the file. - -```solidity -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.17; - -import "@matterlabs/zksync-contracts/l2/system-contracts/Constants.sol"; -import "@matterlabs/zksync-contracts/l2/system-contracts/libraries/SystemContractsCaller.sol"; - -contract AAFactory { - bytes32 public aaBytecodeHash; - - constructor(bytes32 _aaBytecodeHash) { - aaBytecodeHash = _aaBytecodeHash; - } - - function deployAccount( - bytes32 salt, - address owner1, - address owner2 - ) external returns (address accountAddress) { - (bool success, bytes memory returnData) = SystemContractsCaller - .systemCallWithReturndata( - uint32(gasleft()), - address(DEPLOYER_SYSTEM_CONTRACT), - uint128(0), - abi.encodeCall( - DEPLOYER_SYSTEM_CONTRACT.create2Account, - (salt, aaBytecodeHash, abi.encode(owner1, owner2), IContractDeployer.AccountAbstractionVersion.Version1) - ) - ); - require(success, "Deployment failed"); - - (accountAddress) = abi.decode(returnData, (address)); - } -} -``` - -It's worth remembering that, on zkSync Era, [contract deployments](../../../developer-reference/contract-deployment.md) -are not done via bytecode, but via bytecode hash. The bytecode itself is passed to the operator via the `factoryDeps` -field. Note that the `_aaBytecodeHash` must be formed in the following manner: - -- Firstly, it is hashed with sha256. -- Then, the first two bytes are replaced with the length of the bytecode in 32-byte words. - -This functionality is built into the SDK. - -## Deploy the Factory - -::: tip Make sure you deposit funds on zkSync Era using -[one of the available bridges](https://zksync.io/explore#bridges) before running the deployment script. ::: - -1. In the `deploy` folder, create the file `deploy-factory.ts` and copy/paste the following code, replacing - `<WALLET_PRIVATE_KET>` with your private key. - -```ts -import { utils, Wallet } from 'zksync-ethers'; -import * as ethers from 'ethers'; -import { HardhatRuntimeEnvironment } from 'hardhat/types'; -import { Deployer } from '@matterlabs/hardhat-zksync-deploy'; - -export default async function (hre: HardhatRuntimeEnvironment) { - // Private key of the account used to deploy - const wallet = new Wallet('<WALLET_PRIVATE_KEY>'); - const deployer = new Deployer(hre, wallet); - const factoryArtifact = await deployer.loadArtifact('AAFactory'); - const aaArtifact = await deployer.loadArtifact('TwoUserMultisig'); - - // Getting the bytecodeHash of the account - const bytecodeHash = utils.hashBytecode(aaArtifact.bytecode); - - const factory = await deployer.deploy(factoryArtifact, [bytecodeHash], undefined, [ - // Since the factory requires the code of the multisig to be available, - // we should pass it here as well. - aaArtifact.bytecode, - ]); - - const factoryAddress = await factory.getAddress(); - - console.log(`AA factory address: ${factoryAddress}`); -} -``` - -2. From the project root, compile and deploy the contracts. - -```sh -yarn hardhat compile -yarn hardhat deploy-zksync --script deploy-factory.ts -``` - -The output should look like this: - -```txt -AA factory address: 0x70696950F71BB1cCF36Dbd1B77Ae54f96a79b005 -✨ Done in 15.10s. -``` - -Note that the address will be different for each run. - -## Working with Accounts - -### Deploying an Account - -Now, let's deploy an account and use it to initiate a new transaction. - -:::warning This section assumes you have an EOA account with sufficient funds on zkSync Era to deploy a smart contract -account. ::: - -1. In the `deploy` folder, create a file called `deploy-multisig.ts`. - -The call to the `deployAccount` function deploys the AA. - -```ts -import { utils, Wallet, Provider, EIP712Signer, types } from 'zksync-ethers'; -import * as ethers from 'ethers'; -import { HardhatRuntimeEnvironment } from 'hardhat/types'; - -// Put the address of your AA factory -const AA_FACTORY_ADDRESS = '<FACTORY-ADDRESS>'; - -export default async function (hre: HardhatRuntimeEnvironment) { - const provider = new Provider('https://sepolia.era.zksync.dev'); - // Private key of the account used to deploy - const wallet = new Wallet('<WALLET-PRIVATE-KEY>').connect(provider); - - const factoryArtifact = await hre.artifacts.readArtifact('AAFactory'); - - const aaFactory = new ethers.Contract(AA_FACTORY_ADDRESS, factoryArtifact.abi, wallet); - - // The two owners of the multisig - const owner1 = Wallet.createRandom(); - const owner2 = Wallet.createRandom(); - - // For the simplicity of the tutorial, we will use zero hash as salt - const salt = ethers.ZeroHash; - - // deploy account owned by owner1 & owner2 - const tx = await aaFactory.deployAccount(salt, owner1.address, owner2.address); - await tx.wait(); - - // Getting the address of the deployed contract account - // Always use the JS utility methods - const abiCoder = new ethers.AbiCoder(); - const multisigAddress = utils.create2Address( - AA_FACTORY_ADDRESS, - await aaFactory.aaBytecodeHash(), - salt, - abiCoder.encode(['address', 'address'], [owner1.address, owner2.address]) - ); - console.log(`Multisig account deployed on address ${multisigAddress}`); -} -``` - -:::tip - -- zkSync has different address derivation rules from Ethereum. -- Always use the [`createAddress`](../../../sdks/js/utils.md#createaddress) and - [`create2Address`](../../../sdks/js/utils.md#create2address) utility functions of the `zksync-ethers` SDK. -- Read the documentation for more information on - [address derivation differences between Ethereum and zkSync](../../../developer-reference/differences-with-ethereum.md). - ::: - -### Start a Transaction from the Account - -Before the deployed account can submit transactions, we need to deposit some ETH to it for the transaction fees. - -```ts -console.log('Sending funds to multisig account'); - -// Send funds to the multisig account we just deployed -await( - await wallet.sendTransaction({ - to: multisigAddress, - // You can increase the amount of ETH sent to the multisig - value: ethers.parseEther('0.008'), - nonce: await wallet.getNonce(), - }) -).wait(); - -let multisigBalance = await provider.getBalance(multisigAddress); - -console.log(`Multisig account balance is ${multisigBalance.toString()}`); -``` - -Now we can try to deploy a new multisig; the initiator of the transaction will be our deployed account from the previous -part. - -```ts -// Transaction to deploy a new account using the multisig we just deployed -let aaTx = await aaFactory.deployAccount.populateTransaction( - salt, - // These are accounts that will own the newly deployed account - Wallet.createRandom().address, - Wallet.createRandom().address -); -``` - -Then, we need to fill all the transaction fields: - -```ts -const gasLimit = await provider.estimateGas({ ...aaTx, from: wallet.address }); -const gasPrice = await provider.getGasPrice(); - -aaTx = { - ...aaTx, - // deploy a new account using the multisig - from: multisigAddress, - gasLimit: gasLimit, - gasPrice: gasPrice, - chainId: (await provider.getNetwork()).chainId, - nonce: await provider.getTransactionCount(multisigAddress), - type: 113, - customData: { - gasPerPubdata: utils.DEFAULT_GAS_PER_PUBDATA_LIMIT, - } as types.Eip712Meta, - value: 0n, -}; -``` - -::: tip Note on gasLimit - -- Currently, we expect the `l2gasLimit` to cover both the verification and the execution steps. -- Currently, the gas returned by `estimateGas` is `execution_gas + 20000`, where `20000` is roughly equal to the - overhead needed for the defaultAA to have both fee charged and the signature verified. -- In the case that your AA has an expensive verification step, you should add some constant to the `l2gasLimit`. ::: - -Then, we need to sign the transaction and provide the `aaParamas` in the customData of the transaction. - -```ts -const signedTxHash = EIP712Signer.getSignedDigest(aaTx); - -// Sign the transaction with both owners -const signature = ethers.concat([ - ethers.Signature.from(owner1.signingKey.sign(signedTxHash)).serialized, - ethers.Signature.from(owner2.signingKey.sign(signedTxHash)).serialized, -]); - -aaTx.customData = { - ...aaTx.customData, - customSignature: signature, -}; -``` - -Finally, we are ready to send the transaction: - -```ts -console.log(`The multisig's nonce before the first tx is ${await provider.getTransactionCount(multisigAddress)}`); - -const sentTx = await provider.broadcastTransaction(types.Transaction.from(aaTx).serialized); -console.log(`Transaction sent from multisig with hash ${sentTx.hash}`); -await sentTx.wait(); - -// Checking that the nonce for the account has increased -console.log(`The multisig's nonce after the first tx is ${await provider.getTransactionCount(multisigAddress)}`); - -multisigBalance = await provider.getBalance(multisigAddress); - -console.log(`Multisig account balance is now ${multisigBalance.toString()}`); -``` - -### Full Example - -1. Copy/paste the following code into the deployment file, replacing the `<FACTORY-ADDRESS>` and private key - `<WALLET-PRIVATE-KEY>` placeholders with the relevant data. - -```ts -import { utils, Wallet, Provider, EIP712Signer, types } from 'zksync-ethers'; -import * as ethers from 'ethers'; -import { HardhatRuntimeEnvironment } from 'hardhat/types'; - -// Put the address of your AA factory -const AA_FACTORY_ADDRESS = '<FACTORY-ADDRESS>'; //sepolia - -export default async function (hre: HardhatRuntimeEnvironment) { - const provider = new Provider('https://sepolia.era.zksync.dev'); - // Private key of the account used to deploy - const wallet = new Wallet('<WALLET-PRIVATE-KEY>').connect(provider); - - const factoryArtifact = await hre.artifacts.readArtifact('AAFactory'); - - const aaFactory = new ethers.Contract(AA_FACTORY_ADDRESS, factoryArtifact.abi, wallet); - - // The two owners of the multisig - const owner1 = Wallet.createRandom(); - const owner2 = Wallet.createRandom(); - - // For the simplicity of the tutorial, we will use zero hash as salt - const salt = ethers.ZeroHash; - - // deploy account owned by owner1 & owner2 - const tx = await aaFactory.deployAccount(salt, owner1.address, owner2.address); - await tx.wait(); - - // Getting the address of the deployed contract account - // Always use the JS utility methods - const abiCoder = new ethers.AbiCoder(); - - const multisigAddress = utils.create2Address( - AA_FACTORY_ADDRESS, - await aaFactory.aaBytecodeHash(), - salt, - abiCoder.encode(['address', 'address'], [owner1.address, owner2.address]) - ); - console.log(`Multisig account deployed on address ${multisigAddress}`); - - console.log('Sending funds to multisig account'); - // Send funds to the multisig account we just deployed - await ( - await wallet.sendTransaction({ - to: multisigAddress, - // You can increase the amount of ETH sent to the multisig - value: ethers.parseEther('0.008'), - nonce: await wallet.getNonce(), - }) - ).wait(); - - let multisigBalance = await provider.getBalance(multisigAddress); - - console.log(`Multisig account balance is ${multisigBalance.toString()}`); - - // Transaction to deploy a new account using the multisig we just deployed - let aaTx = await aaFactory.deployAccount.populateTransaction( - salt, - // These are accounts that will own the newly deployed account - Wallet.createRandom().address, - Wallet.createRandom().address - ); - - const gasLimit = await provider.estimateGas({ ...aaTx, from: wallet.address }); - const gasPrice = await provider.getGasPrice(); - - aaTx = { - ...aaTx, - // deploy a new account using the multisig - from: multisigAddress, - gasLimit: gasLimit, - gasPrice: gasPrice, - chainId: (await provider.getNetwork()).chainId, - nonce: await provider.getTransactionCount(multisigAddress), - type: 113, - customData: { - gasPerPubdata: utils.DEFAULT_GAS_PER_PUBDATA_LIMIT, - } as types.Eip712Meta, - value: 0n, - }; - - const signedTxHash = EIP712Signer.getSignedDigest(aaTx); - - // Sign the transaction with both owners - const signature = ethers.concat([ - ethers.Signature.from(owner1.signingKey.sign(signedTxHash)).serialized, - ethers.Signature.from(owner2.signingKey.sign(signedTxHash)).serialized, - ]); - - aaTx.customData = { - ...aaTx.customData, - customSignature: signature, - }; - - console.log(`The multisig's nonce before the first tx is ${await provider.getTransactionCount(multisigAddress)}`); - - const sentTx = await provider.broadcastTransaction(types.Transaction.from(aaTx).serialized); - console.log(`Transaction sent from multisig with hash ${sentTx.hash}`); - - await sentTx.wait(); - - // Checking that the nonce for the account has increased - console.log(`The multisig's nonce after the first tx is ${await provider.getTransactionCount(multisigAddress)}`); - - multisigBalance = await provider.getBalance(multisigAddress); - - console.log(`Multisig account balance is now ${multisigBalance.toString()}`); -} -``` - -2. Run the script from the `deploy` folder. - -```sh -yarn hardhat deploy-zksync --script deploy-multisig.ts -``` - -The output should look something like this: - -```txt -Multisig account deployed on address 0x4A1e5F7AeA6830372dCa584cbFaaBa1F21298a01 -Sending funds to multisig account -Multisig account balance is 8000000000000000 -The multisig's nonce before the first tx is 0 -Transaction sent from multisig with hash 0xe91a8665f6777aa3c003844d9d0971a3b3ebbe1f8f3e0d941a3bc797963c7cca -The multisig's nonce after the first tx is 1 -Multisig account balance is now 7962859900000000 -``` - -::: tip If you get an error `Not enough balance to cover the fee.`, try increasing the amount of ETH sent to the -multisig wallet so it has enough funds to pay for the transaction fees. ::: - -## Learn More - -- To learn more about L1->L2 interaction on zkSync, check out the - [documentation](../../../developer-reference/l1-l2-interop.md). -- To learn more about the `zksync-ethers` SDK, check out its - [documentation](../../../sdks/js/zksync-ethers/getting-started.md). -- To learn more about the zkSync Era Hardhat plugins, check out the - [Hardhat documentation](../../../tooling/hardhat/getting-started.md). diff --git a/content/20.build/tutorials/smart-contract-development/account-abstraction/daily-spend-limit.md b/content/20.build/tutorials/smart-contract-development/account-abstraction/daily-spend-limit.md deleted file mode 100644 index 5cd36c76..00000000 --- a/content/20.build/tutorials/smart-contract-development/account-abstraction/daily-spend-limit.md +++ /dev/null @@ -1,1135 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Daily Spending Limit Tutorial | zkSync Docs ---- - -# Daily spending limit account - -This tutorial shows you how to create a smart contract account with a daily spending limit using the zkSync Era native -account abstraction. - -The daily limit feature prevents an account from spending more ETH than the limit set by the account's owner. - -## Prerequisites - -- Make sure your machine satisfies the - [system requirements](https://github.com/matter-labs/era-compiler-solidity/tree/main#system-requirements). -- [Node.js](https://nodejs.org/en/download/) and [Yarn](https://classic.yarnpkg.com/lang/en/docs/install/#mac-stable) - installed on your machine. -- If you are not already familiar with deploying smart contracts on zkSync Era, please refer to the - [quickstart tutorial](../../../quick-start/hello-world.md). -- A wallet with sufficient Sepolia `ETH` on Ethereum and zkSync Era Testnet to pay for deploying smart contracts. You - can get Sepolia ETH from the [network faucets](../../../tooling/network-faucets.md). -- You know - [how to get your private key from your MetaMask wallet](https://support.metamask.io/hc/en-us/articles/360015289632-How-to-export-an-account-s-private-key). -- We encourage you to read - [the basics of account abstraction on zkSync Era](../../../developer-reference/account-abstraction.md) and complete - the [multisig account tutorial](./custom-aa-tutorial.md) before attempting this tutorial. - -::: tip Local zkSync Testing with zksync-cli Skip the hassle for test ETH by using `zksync-cli` for local testing. -Simply execute `npx zksync-cli dev start` to initialize a local zkSync development environment, which includes local -Ethereum and zkSync nodes. This method allows you to test contracts without requesting external testnet funds. Explore -more in the [zksync-cli documentation](../../../tooling/zksync-cli/getting-started.md). ::: - -## Complete Project - -Download the complete project [here](https://github.com/matter-labs/tutorials/tree/main/spend-limit). Additionally, the -repository contains a test folder with more detailed tests for running on a zkSync Era local network. - -::: info Project available in Atlas IDE This entire tutorial can be run in under a minute using Atlas. Atlas is a smart -contract IDE that lets you write, deploy, and interact with contracts from your browser. -[Open this project in Atlas](https://app.atlaszk.com/projects?template=https://github.com/Atlas-labs-inc/zksync-daily-spend-limit&open=/scripts/main.ts&chainId=300). -::: - -## Project Setup - -We will use the [zkSync Era Hardhat plugins](../../../tooling/hardhat/getting-started.md) to build, deploy, and interact -with the smart contracts in this project. - -1. Initiate a new project by running the command: - -```sh -npx zksync-cli create custom-spendlimit-tutorial --template hardhat_solidity -``` - -This creates a new zkSync Era project called `custom-spendlimit-tutorial` with a with a few example contracts. - -1. Navigate into the project directory: - -```sh -cd custom-spendlimit-tutorial -``` - -3. For the purposes of this tutorial, we don't need the example contracts related files. So, proceed by removing all the - files inside the `/contracts` and `/deploy` folders manually or by running the following commands:: - -```sh -rm -rf ./contracts/* -rm -rf ./deploy/* -``` - -4. Add the zkSync and OpenZeppelin contract libraries: - -```sh -yarn add -D @matterlabs/zksync-contracts @openzeppelin/contracts@4.9.5 -``` - -::: warning This project does not use the latest version available of `@openzeppelin/contracts`. Mae sure you install -the specific version mentioned above. ::: - -5. Include the `isSystem: true` setting in the `zksolc` section of the `hardhat.config.ts` configuration file to allow - interaction with system contracts: - -```typescript -import { HardhatUserConfig } from 'hardhat/config'; - -import '@matterlabs/hardhat-zksync-node'; -import '@matterlabs/hardhat-zksync-deploy'; -import '@matterlabs/hardhat-zksync-solc'; -import '@matterlabs/hardhat-zksync-verify'; - -const config: HardhatUserConfig = { - defaultNetwork: 'zkSyncSepoliaTestnet', - networks: { - zkSyncSepoliaTestnet: { - url: 'https://sepolia.era.zksync.dev', - ethNetwork: 'sepolia', - zksync: true, - verifyURL: 'https://explorer.sepolia.era.zksync.dev/contract_verification', - }, - inMemoryNode: { - url: 'http://127.0.0.1:8011', - ethNetwork: 'localhost', // in-memory node doesn't support eth node; removing this line will cause an error - zksync: true, - }, - hardhat: { - zksync: true, - }, - // Additional networks - }, - zksolc: { - version: 'latest', - settings: { - isSystem: true, // ⚠️ Make sure to include this line - }, - }, - solidity: { - version: '0.8.17', - }, -}; - -export default config; -``` - -## Design - -Now let’s dive into the design and implementation of the daily spending limit feature. - -The `SpendLimit` contract inherits from the `Account` contract as a module that does the following: - -- Allows the account to enable/disable the daily spending limit in a token (ETH in this example). -- Allows the account to change (increase/decrease or remove) the daily spending limit. -- Rejects token transfer if the daily spending limit has been exceeded. -- Restores the available amount for spending after 24 hours. - -### Basic Structure - -Below you'll find the `SpendLimit` skeleton contract. - -```solidity -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.17; - -contract SpendLimit { - - uint public ONE_DAY = 24 hours; - - modifier onlyAccount() { - require( - msg.sender == address(this), - "Only the account that inherits this contract can call this method." - ); - _; - } - - function setSpendingLimit(address _token, uint _amount) public onlyAccount { - } - - function removeSpendingLimit(address _token) public onlyAccount { - } - - function _isValidUpdate(address _token) internal view returns(bool) { - } - - function _updateLimit(address _token, uint _limit, uint _available, uint _resetTime, bool _isEnabled) private { - } - - function _checkSpendingLimit(address _token, uint _amount) internal { - } - -} -``` - -The mapping `limits` and struct `Limit` below serve as data storage for the state of daily limits accounts enable. - -The roles of each variable in the struct are detailed in the comments. - -```solidity - /// This struct serves as data storage of daily spending limits users enable - /// limit: the amount of a daily spending limit - /// available: the available amount that can be spent - /// resetTime: block.timestamp at the available amount is restored - /// isEnabled: true when a daily spending limit is enabled - struct Limit { - uint limit; - uint available; - uint resetTime; - bool isEnabled; - } - - mapping(address => Limit) public limits; // token => Limit -``` - -Note that the `limits` mapping uses the token address as its key. This means that users can set limits for ETH and any -other ERC20 token. - -### Setting and Removing the Daily Spending Limit - -The code below sets and removes the limit. - -```solidity - /// this function enables a daily spending limit for specific tokens. - /// @param _token ETH or ERC20 token address that a given spending limit is applied. - /// @param _amount non-zero limit. - function setSpendingLimit(address _token, uint _amount) public onlyAccount { - require(_amount != 0, "Invalid amount"); - - uint resetTime; - uint timestamp = block.timestamp; // L2 block timestamp - - if (isValidUpdate(_token)) { - resetTime = timestamp + ONE_DAY; - } else { - resetTime = timestamp; - } - - _updateLimit(_token, _amount, _amount, resetTime, true); - } - - // this function disables an active daily spending limit, - // decreasing each uint number in the Limit struct to zero and setting isEnabled false. - function removeSpendingLimit(address _token) public onlyAccount { - require(isValidUpdate(_token), "Invalid Update"); - _updateLimit(_token, 0, 0, 0, false); - } - - // verify if the update to a Limit struct is valid - // Ensure that users can't freely modify(increase or remove) the daily limit to spend more. - function isValidUpdate(address _token) internal view returns (bool) { - // Reverts unless it is first spending after enabling - // or called after 24 hours have passed since the last update. - if (limits[_token].isEnabled) { - require( - limits[_token].limit == limits[_token].available || - block.timestamp > limits[_token].resetTime, - "Invalid Update" - ); - - return true; - } else { - return false; - } - } - - // storage-modifying private function called by either setSpendingLimit or removeSpendingLimit - function _updateLimit( - address _token, - uint _limit, - uint _available, - uint _resetTime, - bool _isEnabled - ) private { - Limit storage limit = limits[_token]; - limit.limit = _limit; - limit.available = _available; - limit.resetTime = _resetTime; - limit.isEnabled = _isEnabled; - } - -``` - -Both `setSpendingLimit` and `removeSpendingLimit` can only be called by account contracts that inherit the contract -`SpendLimit`. This is ensured by the `onlyAccount` modifier. They call `_updateLimit` and pass the arguments to modify -the storage data of the limit after the verification in `_isValidUpdate` succeeds. - -Specifically, `setSpendingLimit` sets a non-zero daily spending limit for a given token, and `removeSpendingLimit` -disables the active daily spending limit by decreasing `limit` and `available` to 0 and setting `isEnabled` to false. - -`_isValidUpdate` returns false if the spending limit is not enabled and also throws an `Invalid Update` error if the -user has spent some amount in the day (the available amount is different from the limit) or the function is called -before 24 hours have passed since the last update. This ensures that users can't freely modify (increase or remove) the -daily limit to spend more. - -### Checking Daily Spending Limit - -The `_checkSpendingLimit` function is internally called by the account contract before executing the transaction. - -```solidity - // this function is called by the account before execution. - // Verify the account is able to spend a given amount of tokens. And it records a new available amount. - function _checkSpendingLimit(address _token, uint _amount) internal { - Limit memory limit = limits[_token]; - - // return if spending limit hasn't been enabled yet - if (!limit.isEnabled) return; - - uint timestamp = block.timestamp; // L2 block timestamp - - // Renew resetTime and available amount, which is only performed - // if a day has already passed since the last update: timestamp > resetTime - if (limit.limit != limit.available && timestamp > limit.resetTime) { - limit.resetTime = timestamp + ONE_DAY; - limit.available = limit.limit; - - // Or only resetTime is updated if it's the first spending after enabling limit - } else if (limit.limit == limit.available) { - limit.resetTime = timestamp + ONE_DAY; - } - - // reverts if the amount exceeds the remaining available amount. - require(limit.available >= _amount, "Exceed daily limit"); - - // decrement `available` - limit.available -= _amount; - limits[_token] = limit; - } -``` - -If the daily spending limit is disabled, the checking process immediately stops. - -```solidity -if(!limit.isEnabled) return; -``` - -Before checking the spending amount, this method renews the `resetTime` and `available` amount if a day has already -passed since the last update: `timestamp > resetTime`. It only updates the `resetTime` if the transaction is the first -spending after enabling the limit. This way the daily limit actually starts with the first transaction. - -```solidity -if (limit.limit != limit.available && timestamp > limit.resetTime) { - limit.resetTime = timestamp + ONE_DAY; - limit.available = limit.limit; - - // Or only resetTime is updated if it's the first spending after enabling limit -} else if (limit.limit == limit.available) { - limit.resetTime = timestamp + ONE_DAY; -} -``` - -Finally, the method checks if the account can spend a specified amount of the token. If the amount doesn't exceed the -available amount, it decrements the `available` in the limit: - -```solidity -require(limit.available >= _amount, 'Exceed daily limit'); - -limit.available -= _amount; -``` - -### Full Code for the `SpendLimit` Contract - -1. In the folder `contracts`, add a file called `SpendLimit.sol` - -2. Copy/paste the complete code below. - -:::warning - -- The value of the `ONE_DAY` variable is set to `1 minutes` instead of `24 hours`. -- This is just for testing purposes (we don't want to wait a full day to see if it works!). -- Don't forget to change the value before deploying the contract. - -::: - -```solidity -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.17; - -contract SpendLimit { - // uint public ONE_DAY = 24 hours; - uint public ONE_DAY = 1 minutes; // set to 1 min for tutorial - - /// This struct serves as data storage of daily spending limits users enable - /// limit: the amount of a daily spending limit - /// available: the available amount that can be spent - /// resetTime: block.timestamp at the available amount is restored - /// isEnabled: true when a daily spending limit is enabled - struct Limit { - uint limit; - uint available; - uint resetTime; - bool isEnabled; - } - - mapping(address => Limit) public limits; // token => Limit - - modifier onlyAccount() { - require( - msg.sender == address(this), - "Only the account that inherits this contract can call this method." - ); - _; - } - - /// this function enables a daily spending limit for specific tokens. - /// @param _token ETH or ERC20 token address that a given spending limit is applied. - /// @param _amount non-zero limit. - function setSpendingLimit(address _token, uint _amount) public onlyAccount { - require(_amount != 0, "Invalid amount"); - - uint resetTime; - uint timestamp = block.timestamp; // L2 block timestamp - - if (isValidUpdate(_token)) { - resetTime = timestamp + ONE_DAY; - } else { - resetTime = timestamp; - } - - _updateLimit(_token, _amount, _amount, resetTime, true); - } - - // this function disables an active daily spending limit, - // decreasing each uint number in the Limit struct to zero and setting isEnabled false. - function removeSpendingLimit(address _token) public onlyAccount { - require(isValidUpdate(_token), "Invalid Update"); - _updateLimit(_token, 0, 0, 0, false); - } - - // verify if the update to a Limit struct is valid - // Ensure that users can't freely modify(increase or remove) the daily limit to spend more. - function isValidUpdate(address _token) internal view returns (bool) { - // Reverts unless it is first spending after enabling - // or called after 24 hours have passed since the last update. - if (limits[_token].isEnabled) { - require( - limits[_token].limit == limits[_token].available || - block.timestamp > limits[_token].resetTime, - "Invalid Update" - ); - - return true; - } else { - return false; - } - } - - // storage-modifying private function called by either setSpendingLimit or removeSpendingLimit - function _updateLimit( - address _token, - uint _limit, - uint _available, - uint _resetTime, - bool _isEnabled - ) private { - Limit storage limit = limits[_token]; - limit.limit = _limit; - limit.available = _available; - limit.resetTime = _resetTime; - limit.isEnabled = _isEnabled; - } - - // this function is called by the account before execution. - // Verify the account is able to spend a given amount of tokens. And it records a new available amount. - function _checkSpendingLimit(address _token, uint _amount) internal { - Limit memory limit = limits[_token]; - - // return if spending limit hasn't been enabled yet - if (!limit.isEnabled) return; - - uint timestamp = block.timestamp; // L2 block timestamp - - // Renew resetTime and available amount, which is only performed - // if a day has already passed since the last update: timestamp > resetTime - if (limit.limit != limit.available && timestamp > limit.resetTime) { - limit.resetTime = timestamp + ONE_DAY; - limit.available = limit.limit; - - // Or only resetTime is updated if it's the first spending after enabling limit - } else if (limit.limit == limit.available) { - limit.resetTime = timestamp + ONE_DAY; - } - - // reverts if the amount exceeds the remaining available amount. - require(limit.available >= _amount, "Exceed daily limit"); - - // decrement `available` - limit.available -= _amount; - limits[_token] = limit; - } -} -``` - -### `Account` and `AAFactory` Contracts - -Let's create the account contract `Account.sol`, and the factory contract that deploys account contracts, in -`AAFactory.sol`. As noted earlier, those two contracts are based on the implementations of -[the multisig account abstraction tutorial](./custom-aa-tutorial.md). The main difference is that our account has a -single signer. - -#### `Account.sol` - -1. Create a file `Account.sol` in the `contracts` folder. - -2. Copy/paste the code below. - -The account implements the [IAccount](../../../developer-reference/account-abstraction.md#iaccount-interface) interface -and inherits the `SpendLimit` contract we just created. Since we are building an account with signers, we should also -implement -[EIP1271](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/83277ff916ac4f58fec072b8f28a252c1245c2f1/contracts/interfaces/IERC1271.sol#L12). - -The `isValidSignature` method will take care of verifying the signature and making sure the extracted address matches -with the owner of the account. - -```solidity -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -import "@matterlabs/zksync-contracts/l2/system-contracts/interfaces/IAccount.sol"; -import "@matterlabs/zksync-contracts/l2/system-contracts/libraries/TransactionHelper.sol"; -import "@openzeppelin/contracts/interfaces/IERC1271.sol"; -// Used for signature validation -import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; -// Access zkSync system contracts for nonce validation via NONCE_HOLDER_SYSTEM_CONTRACT -import "@matterlabs/zksync-contracts/l2/system-contracts/Constants.sol"; -// to call non-view function of system contracts -import "@matterlabs/zksync-contracts/l2/system-contracts/libraries/SystemContractsCaller.sol"; -import "./SpendLimit.sol"; - -contract Account is IAccount, IERC1271, SpendLimit { - // to get transaction hash - using TransactionHelper for Transaction; - - // state variable for account owner - address public owner; - - bytes4 constant EIP1271_SUCCESS_RETURN_VALUE = 0x1626ba7e; - - modifier onlyBootloader() { - require( - msg.sender == BOOTLOADER_FORMAL_ADDRESS, - "Only bootloader can call this method" - ); - // Continue execution if called from the bootloader. - _; - } - - constructor(address _owner) { - owner = _owner; - } - - function validateTransaction( - bytes32, - bytes32 _suggestedSignedHash, - Transaction calldata _transaction - ) external payable override onlyBootloader returns (bytes4 magic) { - return _validateTransaction(_suggestedSignedHash, _transaction); - } - - function _validateTransaction( - bytes32 _suggestedSignedHash, - Transaction calldata _transaction - ) internal returns (bytes4 magic) { - // Incrementing the nonce of the account. - // Note, that reserved[0] by convention is currently equal to the nonce passed in the transaction - SystemContractsCaller.systemCallWithPropagatedRevert( - uint32(gasleft()), - address(NONCE_HOLDER_SYSTEM_CONTRACT), - 0, - abi.encodeCall( - INonceHolder.incrementMinNonceIfEquals, - (_transaction.nonce) - ) - ); - - bytes32 txHash; - // While the suggested signed hash is usually provided, it is generally - // not recommended to rely on it to be present, since in the future - // there may be tx types with no suggested signed hash. - if (_suggestedSignedHash == bytes32(0)) { - txHash = _transaction.encodeHash(); - } else { - txHash = _suggestedSignedHash; - } - - // The fact there is are enough balance for the account - // should be checked explicitly to prevent user paying for fee for a - // transaction that wouldn't be included on Ethereum. - uint256 totalRequiredBalance = _transaction.totalRequiredBalance(); - require( - totalRequiredBalance <= address(this).balance, - "Not enough balance for fee + value" - ); - - if ( - isValidSignature(txHash, _transaction.signature) == - EIP1271_SUCCESS_RETURN_VALUE - ) { - magic = ACCOUNT_VALIDATION_SUCCESS_MAGIC; - } else { - magic = bytes4(0); - } - } - - function executeTransaction( - bytes32, - bytes32, - Transaction calldata _transaction - ) external payable override onlyBootloader { - _executeTransaction(_transaction); - } - - function _executeTransaction(Transaction calldata _transaction) internal { - address to = address(uint160(_transaction.to)); - uint128 value = Utils.safeCastToU128(_transaction.value); - bytes memory data = _transaction.data; - - // Call SpendLimit contract to ensure that ETH `value` doesn't exceed the daily spending limit - if (value > 0) { - _checkSpendingLimit(address(ETH_TOKEN_SYSTEM_CONTRACT), value); - } - - if (to == address(DEPLOYER_SYSTEM_CONTRACT)) { - uint32 gas = Utils.safeCastToU32(gasleft()); - - // Note, that the deployer contract can only be called - // with a "systemCall" flag. - SystemContractsCaller.systemCallWithPropagatedRevert( - gas, - to, - value, - data - ); - } else { - bool success; - assembly { - success := call( - gas(), - to, - value, - add(data, 0x20), - mload(data), - 0, - 0 - ) - } - require(success); - } - } - - function executeTransactionFromOutside( - Transaction calldata _transaction - ) external payable { - _validateTransaction(bytes32(0), _transaction); - _executeTransaction(_transaction); - } - - function isValidSignature( - bytes32 _hash, - bytes memory _signature - ) public view override returns (bytes4 magic) { - magic = EIP1271_SUCCESS_RETURN_VALUE; - - if (_signature.length != 65) { - // Signature is invalid anyway, but we need to proceed with the signature verification as usual - // in order for the fee estimation to work correctly - _signature = new bytes(65); - - // Making sure that the signatures look like a valid ECDSA signature and are not rejected rightaway - // while skipping the main verification process. - _signature[64] = bytes1(uint8(27)); - } - - // extract ECDSA signature - uint8 v; - bytes32 r; - bytes32 s; - // Signature loading code - // we jump 32 (0x20) as the first slot of bytes contains the length - // we jump 65 (0x41) per signature - // for v we load 32 bytes ending with v (the first 31 come from s) then apply a mask - assembly { - r := mload(add(_signature, 0x20)) - s := mload(add(_signature, 0x40)) - v := and(mload(add(_signature, 0x41)), 0xff) - } - - if (v != 27 && v != 28) { - magic = bytes4(0); - } - - // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature - // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines - // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most - // signatures from current libraries generate a unique signature with an s-value in the lower half order. - // - // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value - // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or - // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept - // these malleable signatures as well. - if ( - uint256(s) > - 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0 - ) { - magic = bytes4(0); - } - - address recoveredAddress = ecrecover(_hash, v, r, s); - - // Note, that we should abstain from using the require here in order to allow for fee estimation to work - if (recoveredAddress != owner && recoveredAddress != address(0)) { - magic = bytes4(0); - } - } - - function payForTransaction( - bytes32, - bytes32, - Transaction calldata _transaction - ) external payable override onlyBootloader { - bool success = _transaction.payToTheBootloader(); - require(success, "Failed to pay the fee to the operator"); - } - - function prepareForPaymaster( - bytes32, // _txHash - bytes32, // _suggestedSignedHash - Transaction calldata _transaction - ) external payable override onlyBootloader { - _transaction.processPaymasterInput(); - } - - fallback() external { - // fallback of default account shouldn't be called by bootloader under no circumstances - assert(msg.sender != BOOTLOADER_FORMAL_ADDRESS); - - // If the contract is called directly, behave like an EOA - } - - receive() external payable { - // If the contract is called directly, behave like an EOA. - // Note, that is okay if the bootloader sends funds with no calldata as it may be used for refunds/operator payments - } -} - -``` - -:::warning Note 1 - -- The formal ETH address on zkSync Era is `0x000000000000000000000000000000000000800a`. -- Neither the well-known `0xEee...EEeE` used by protocols as a placeholder on Ethereum, nor the zero address - `0x000...000`, that ([`zksync-ethers` provides](../../../sdks/js/utils.md#useful-addresses)) has a more user-friendly - alias. - -::: - -:::info Note 2 - -- `SpendLimit` is token-agnostic. -- This means an extension is also possible: add a check for whether or not the execution is an ERC20 transfer by - extracting the function selector in bytes from transaction calldata. - -::: - -#### `AAFactory.sol` - -The `AAFactory.sol` contract is responsible for deploying instances of the `Account.sol` contract. - -1. Create the `AAFactory.sol` file in the `contracts` folder and copy/paste the code below. - -```solidity -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.17; - -import "@matterlabs/zksync-contracts/l2/system-contracts/Constants.sol"; -import "@matterlabs/zksync-contracts/l2/system-contracts/libraries/SystemContractsCaller.sol"; - -contract AAFactory { - bytes32 public aaBytecodeHash; - - constructor(bytes32 _aaBytecodeHash) { - aaBytecodeHash = _aaBytecodeHash; - } - - function deployAccount( - bytes32 salt, - address owner - ) external returns (address accountAddress) { - (bool success, bytes memory returnData) = SystemContractsCaller - .systemCallWithReturndata( - uint32(gasleft()), - address(DEPLOYER_SYSTEM_CONTRACT), - uint128(0), - abi.encodeCall( - DEPLOYER_SYSTEM_CONTRACT.create2Account, - ( - salt, - aaBytecodeHash, - abi.encode(owner), - IContractDeployer.AccountAbstractionVersion.Version1 - ) - ) - ); - require(success, "Deployment failed"); - - (accountAddress) = abi.decode(returnData, (address)); - } -} -``` - -## Compile and Deploy the Smart Contracts - -1. Compile the contracts from the project root. - -```sh -yarn hardhat compile -``` - -2. Create a file named `deploy/deployFactoryAccount.ts`. Then, copy and paste the following code into it. Remember to - add your `DEPLOYER_PRIVATE_KEY` to the .env file. - -The script deploys the factory, creates a new smart contract account, and funds it with some ETH. - -```typescript -import { utils, Wallet, Provider } from 'zksync-ethers'; -import * as ethers from 'ethers'; -import { HardhatRuntimeEnvironment } from 'hardhat/types'; -import { Deployer } from '@matterlabs/hardhat-zksync-deploy'; - -// load env file -import dotenv from 'dotenv'; -dotenv.config(); - -const DEPLOYER_PRIVATE_KEY = process.env.WALLET_PRIVATE_KEY || ''; - -export default async function (hre: HardhatRuntimeEnvironment) { - // @ts-ignore target zkSyncSepoliaTestnet in config file which can be testnet or local - const provider = new Provider(hre.config.networks.zkSyncSepoliaTestnet.url); - const wallet = new Wallet(DEPLOYER_PRIVATE_KEY, provider); - const deployer = new Deployer(hre, wallet); - const factoryArtifact = await deployer.loadArtifact('AAFactory'); - const aaArtifact = await deployer.loadArtifact('Account'); - - // Bridge funds if the wallet on zkSync doesn't have enough funds. - // const depositAmount = ethers.parseEther('0.1'); - // const depositHandle = await deployer.zkWallet.deposit({ - // to: deployer.zkWallet.address, - // token: utils.ETH_ADDRESS, - // amount: depositAmount, - // }); - // await depositHandle.wait(); - - const factory = await deployer.deploy(factoryArtifact, [utils.hashBytecode(aaArtifact.bytecode)], undefined, [ - aaArtifact.bytecode, - ]); - const factoryAddress = await factory.getAddress(); - console.log(`AA factory address: ${factoryAddress}`); - - const aaFactory = new ethers.Contract(factoryAddress, factoryArtifact.abi, wallet); - - const owner = Wallet.createRandom(); - console.log('SC Account owner pk: ', owner.privateKey); - - const salt = ethers.ZeroHash; - const tx = await aaFactory.deployAccount(salt, owner.address); - await tx.wait(); - - const abiCoder = new ethers.AbiCoder(); - const accountAddress = utils.create2Address( - factoryAddress, - await aaFactory.aaBytecodeHash(), - salt, - abiCoder.encode(['address'], [owner.address]) - ); - - console.log(`SC Account deployed on address ${accountAddress}`); - - console.log('Funding smart contract account with some ETH'); - await ( - await wallet.sendTransaction({ - to: accountAddress, - value: ethers.parseEther('0.02'), - }) - ).wait(); - console.log(`Done!`); -} -``` - -3. Run the script. - -```sh -yarn hardhat deploy-zksync --script deployFactoryAccount.ts -``` - -You should see something like this: - -```txt -AA factory address: 0x0d3205bc8134A11f9402fBA01947Bf377FaE4C39 -SC Account owner pk: 0x4ze1f87c5e575dsb6b35afe70ftu93fs53bca24592f6ng25f3v1a4f6fsd3vz -SC Account deployed on address 0x29d0D17857bdA971F40FF11145859eED7bD15c00 -Funding smart contract account with some ETH -Done! -✨ Done in 10.85s. -``` - -Open up the [zkSync Era block explorer](https://sepolia.explorer.zksync.io) and search for the deployed Account contract -address in order to track transactions and changes in the balance. - -:::tip - -- For contract verification, please refer to [this section of the documentation](../../how-to/verify-contracts.md). ::: - -## Set the daily spending limit - -1. Create the file `setLimit.ts` in the `deploy` folder and copy/paste the example code below. - -2. Replace `<DEPLOYED_ACCOUNT_ADDRESS>` and `<DEPLOYED_ACCOUNT_OWNER_PRIVATE_KEY>` with the output from the previous - section in your `.env` file. - -To enable the daily spending limit, we execute the `setSpendingLimit` function with two parameters: token address and -limit amount. The token address is `ETH_ADDRESS` and the limit parameter is `0.0005` in the example below (and can be -any amount). - -```typescript -import { utils, Wallet, Provider, Contract, EIP712Signer, types } from 'zksync-ethers'; -import * as ethers from 'ethers'; -import { HardhatRuntimeEnvironment } from 'hardhat/types'; - -// load env file -import dotenv from 'dotenv'; -dotenv.config(); - -// load the values into .env file after deploying the FactoryAccount -const DEPLOYED_ACCOUNT_OWNER_PRIVATE_KEY = process.env.DEPLOYED_ACCOUNT_OWNER_PRIVATE_KEY || ''; -const ETH_ADDRESS = process.env.ETH_ADDRESS || '0x000000000000000000000000000000000000800A'; -const ACCOUNT_ADDRESS = process.env.DEPLOYED_ACCOUNT_ADDRESS || ''; - -export default async function (hre: HardhatRuntimeEnvironment) { - // @ts-ignore target zkSyncSepoliaTestnet in config file which can be testnet or local - const provider = new Provider(hre.config.networks.zkSyncSepoliaTestnet.url); - - const owner = new Wallet(DEPLOYED_ACCOUNT_OWNER_PRIVATE_KEY, provider); - - const accountArtifact = await hre.artifacts.readArtifact('Account'); - const account = new Contract(ACCOUNT_ADDRESS, accountArtifact.abi, owner); - - let setLimitTx = await account.setSpendingLimit.populateTransaction(ETH_ADDRESS, ethers.parseEther('0.0005')); - - setLimitTx = { - ...setLimitTx, - from: ACCOUNT_ADDRESS, - chainId: (await provider.getNetwork()).chainId, - nonce: await provider.getTransactionCount(ACCOUNT_ADDRESS), - type: 113, - customData: { - gasPerPubdata: utils.DEFAULT_GAS_PER_PUBDATA_LIMIT, - } as types.Eip712Meta, - value: BigInt(0), - }; - - setLimitTx.gasPrice = await provider.getGasPrice(); - setLimitTx.gasLimit = await provider.estimateGas(setLimitTx); - - const signedTxHash = EIP712Signer.getSignedDigest(setLimitTx); - - const signature = ethers.concat([ethers.Signature.from(owner.signingKey.sign(signedTxHash)).serialized]); - - setLimitTx.customData = { - ...setLimitTx.customData, - customSignature: signature, - }; - - console.log('Setting limit for account...'); - const sentTx = await provider.broadcastTransaction(types.Transaction.from(setLimitTx).serialized); - - await sentTx.wait(); - - const limit = await account.limits(ETH_ADDRESS); - console.log('Account limit enabled?: ', limit.isEnabled); - console.log('Account limit: ', limit.limit.toString()); - console.log('Available limit today: ', limit.available.toString()); - console.log('Time to reset limit: ', limit.resetTime.toString()); -} -``` - -3. Run the script. - -```sh -yarn hardhat deploy-zksync --script setLimit.ts -``` - -You should see something like this: - -```text -Setting limit for account... -Account limit enabled?: true -Account limit: 500000000000000 -Available limit today: 500000000000000 -Time to reset limit: 1708688165 -``` - -## Perform ETH Transfer - -Let's test the `SpendLimit` contract works to make it refuse ETH transfers that exceed the daily limit. - -1. Create `transferETH.ts` and copy/paste the example code below, replacing the placeholder constants as before and - adding an account address for `RECEIVER_ACCOUNT`. - -```typescript -import { utils, Wallet, Provider, Contract, EIP712Signer, types } from 'zksync-ethers'; -import * as ethers from 'ethers'; -import { HardhatRuntimeEnvironment } from 'hardhat/types'; - -// load env file -import dotenv from 'dotenv'; -dotenv.config(); - -// load the values into .env file after deploying the FactoryAccount -const DEPLOYED_ACCOUNT_OWNER_PRIVATE_KEY = process.env.DEPLOYED_ACCOUNT_OWNER_PRIVATE_KEY || ''; -const ETH_ADDRESS = process.env.ETH_ADDRESS || '0x000000000000000000000000000000000000800A'; -const ACCOUNT_ADDRESS = process.env.DEPLOYED_ACCOUNT_ADDRESS || ''; -const RECEIVER_ACCOUNT = process.env.RECEIVER_ACCOUNT || ''; - -export default async function (hre: HardhatRuntimeEnvironment) { - // @ts-ignore target zkSyncSepoliaTestnet in config file which can be testnet or local - const provider = new Provider(hre.config.networks.zkSyncSepoliaTestnet.url); - - const owner = new Wallet(DEPLOYED_ACCOUNT_OWNER_PRIVATE_KEY, provider); - - // ⚠️ update this amount to test if the limit works; 0.00051 fails but 0.00049 succeeds - const transferAmount = '0.00051'; - - let ethTransferTx = { - from: ACCOUNT_ADDRESS, - to: RECEIVER_ACCOUNT, // account that will receive the ETH transfer - chainId: (await provider.getNetwork()).chainId, - nonce: await provider.getTransactionCount(ACCOUNT_ADDRESS), - type: 113, - customData: { - gasPerPubdata: utils.DEFAULT_GAS_PER_PUBDATA_LIMIT, - } as types.Eip712Meta, - - value: ethers.parseEther(transferAmount), - gasPrice: await provider.getGasPrice(), - gasLimit: BigInt(20000000), // constant 20M since estimateGas() causes an error and this tx consumes more than 15M at most - data: '0x', - }; - const signedTxHash = EIP712Signer.getSignedDigest(ethTransferTx); - const signature = ethers.concat([ethers.Signature.from(owner.signingKey.sign(signedTxHash)).serialized]); - - ethTransferTx.customData = { - ...ethTransferTx.customData, - customSignature: signature, - }; - - const accountArtifact = await hre.artifacts.readArtifact('Account'); - - // read account limits - const account = new Contract(ACCOUNT_ADDRESS, accountArtifact.abi, owner); - const limitData = await account.limits(ETH_ADDRESS); - - console.log('Account ETH limit is: ', limitData.limit.toString()); - console.log('Available today: ', limitData.available.toString()); - - // L1 timestamp tends to be undefined in latest blocks. So it should find the latest L1 Batch first. - let l1BatchRange = await provider.getL1BatchBlockRange(await provider.getL1BatchNumber()); - let l1TimeStamp = (await provider.getBlock(l1BatchRange[1])).l1BatchTimestamp; - - console.log('L1 timestamp: ', l1TimeStamp); - console.log('Limit will reset on timestamp: ', limitData.resetTime.toString()); - - // actually do the ETH transfer - console.log('Sending ETH transfer from smart contract account'); - const sentTx = await provider.broadcastTransaction(types.Transaction.from(ethTransferTx).serialized); - await sentTx.wait(); - console.log(`ETH transfer tx hash is ${sentTx.hash}`); - - console.log('Transfer completed and limits updated!'); - - const newLimitData = await account.limits(ETH_ADDRESS); - console.log('Account limit: ', newLimitData.limit.toString()); - console.log('Available today: ', newLimitData.available.toString()); - console.log('Limit will reset on timestamp:', newLimitData.resetTime.toString()); - - if (newLimitData.resetTime.toString() == limitData.resetTime.toString()) { - console.log('Reset time was not updated as not enough time has passed'); - } else { - console.log('Limit timestamp was reset'); - } - return; -} -``` - -2. Run the script to attempt to make a transfer. - -```shell -yarn hardhat deploy-zksync --script transferETH.ts -``` - -You should see an error message with the following content so we know it failed because the amount exceeded the limit. - -```shell -An unexpected error occurred: -Error: transaction failed... - -shortMessage: 'execution reverted: "Exceed daily limit"' -``` - -You can also search the transaction in the explorer to see the error reason. - -After the error, we can rerun the code with a different ETH amount that doesn't exceed the limit, say "0.00049", to see -if the `SpendLimit` contract doesn't refuse the amount lower than the limit. - -If the transaction succeeds, the output should look something like this: - -```shell -Account ETH limit is: 500000000000000 -Available today: 494900000000000 -Limit will reset on timestamp: 1708689912 -Sending ETH transfer from smart contract account -ETH transfer tx hash is 0x6e7742e6555a88ca1489a06992711d413a12358f77c611cca96aba112ced812b -Transfer completed and limits updated! -Account limit: 500000000000000 -Available today: 449000000000000 -Limit will reset on timestamp: 1708690236 -Current timestamp: 1708690185 -Reset time was not updated as not enough time has passed -``` - -The `available` value in the `Limit` struct updates to the initial limit minus the amount we transferred. - -Since `ONE_DAY` is set to 1 minute for this test in the `SpendLimit.sol` contract, you should expect it to reset after -60 seconds. - -## Common Errors - -- Insufficient gasLimit: Transactions often fail due to insufficient gasLimit. Please increase the value manually when - transactions fail without clear reasons. -- Insufficient balance in account contract: transactions may fail due to the lack of balance in the deployed account - contract. Please transfer funds to the account using MetaMask or `wallet.sendTransaction()` method used in - `deploy/deployFactoryAccount.ts`. -- Transactions submitted in a close range of time will have the same `block.timestamp` as they can be added to the same - L1 batch and might cause the spend limit to not work as expected. - -## Learn More - -- To find out more about L1->L2 interaction on zkSync Era, check out the - [documentation](../../../developer-reference/l1-l2-interop.md). -- To learn more about the zksync-ethers SDK, check out its - [documentation](../../../sdks/js/zksync-ethers/getting-started.md). -- To learn more about the zkSync Era Hardhat plugins, check out their - [documentation](../../../tooling/hardhat/getting-started.md). - -## Credits - -Written by [porco-rosso](https://linktr.ee/porcorossoj) for the GitCoin bounty. diff --git a/content/20.build/tutorials/smart-contract-development/cross-chain-tutorial.md b/content/20.build/tutorials/smart-contract-development/cross-chain-tutorial.md deleted file mode 100644 index 8907fdc9..00000000 --- a/content/20.build/tutorials/smart-contract-development/cross-chain-tutorial.md +++ /dev/null @@ -1,664 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Cross-chain Governance | zkSync Docs ---- - -# Cross-chain Governance - -This tutorial shows you how to implement communication between L1 and L2 with the following example: - -- A **Governance** Solidity smart contract is deployed on layer 1. This contract has a function that sends a transaction - to zkSync layer 2. -- A **Counter** Solidity smart contract is deployed on zkSync layer 2. This contract stores a number that is incremented - by calling the `increment` method. The `Governance` contract on layer 1 calls this function. - -## Prerequisites - -- Make sure your machine satisfies the - [system requirements](https://github.com/matter-labs/era-compiler-solidity/tree/main#system-requirements). -- You are already familiar with deploying smart contracts on zkSync Era. If not, please refer to the first section of - the [quickstart tutorial](../../quick-start/hello-world.md). -- You already have some experience working with Ethereum. -- A wallet with sufficient Sepolia or Göerli `ETH` on Ethereum and zkSync Era Testnet to pay for deploying smart - contracts. You can get Sepolia ETH from the [network faucets](../../tooling/network-faucets.md). - - Get testnet `ETH` for zkSync Era using [bridges](https://zksync.io/explore#bridges) to bridge funds to zkSync. -- You know how to get your - [private key from your MetaMask wallet](https://support.metamask.io/hc/en-us/articles/360015289632-How-to-export-an-account-s-private-key). - -::: tip Local zkSync Testing with zksync-cli Skip the hassle for test ETH by using `zksync-cli` for local testing. -Simply execute `npx zksync-cli dev start` to initialize a local zkSync development environment, which includes local -Ethereum and zkSync nodes. This method allows you to test contracts without requesting external testnet funds. Explore -more in the [zksync-cli documentation](../../tooling/zksync-cli/getting-started.md). ::: - -### Complete Project - -Download the complete project [here](https://github.com/matter-labs/tutorials/tree/main/cross-chain). - -## Project Setup - -Open a terminal window, create a new folder for the project tutorial, e.g. `mkdir cross-chain-tutorial`, and `cd` into -the folder. - -Now create separate folders to store contracts and scripts on L1 and L2. For now we will start with L1-governance -folder. - -```sh -mkdir L1-governance -``` - -::: note - -- The `L1-governance` code is a default Hardhat project used to deploy a contract on L1. -- The `L2-counter` code includes all zkSync dependencies and configurations for L2. ::: - -## L1 Governance - -1. `cd` into `L1-governance`. - -2. Run the following to initialise and set up the L1 project: - -```sh -npx hardhat -``` - -Select the option **Create a Typescript project** and accept the defaults for everything else. - -:::info To interact with the zkSync bridge contract using Solidity, you need the zkSync contract interface. There are -two ways to get it: - -- Import it from the `@matterlabs/zksync-contracts` npm package (preferred). -- Download it from the [contracts repo](https://github.com/matter-labs/era-contracts). ::: - -1. Install the following dependencies: - -Make sure you use actual node (lts version) and actual npm version ::: code-tabs @tab yarn - -```sh -yarn add -D typescript ts-node @openzeppelin/contracts @matterlabs/zksync-contracts @nomicfoundation/hardhat-ethers @typechain/ethers-v6 @typechain/hardhat typechain ethers -``` - -@tab npm - -```sh -npm i -D typescript ts-node @openzeppelin/contracts @matterlabs/zksync-contracts @nomicfoundation/hardhat-ethers @typechain/ethers-v6 @typechain/hardhat typechain ethers -``` - -::: - -### Create L1 Governance Contract - -:::tip Make sure you're still in the `L1-governance` folder. ::: - -The following Solidity code defines the Governance smart contract. - -The constructor sets the contract creator as the single governor. The `callZkSync` function calls a transaction on L2 -which can only be called by the governor. - -1. Remove existing `/test` directory and any contracts that exist in `/contracts`. - -2. `cd` into the `contracts\` folder. - -3. Create a file called `Governance.sol` and copy/paste the code below into it. - -```solidity -// SPDX-License-Identifier: Unlicense -pragma solidity ^0.8.13; - -import "@matterlabs/zksync-contracts/l1/contracts/zksync/interfaces/IZkSync.sol"; - -contract Governance { - address public governor; - - constructor() { - governor = msg.sender; - } - - function callZkSync( - address zkSyncAddress, - address contractAddr, - bytes memory data, - uint256 gasLimit, - uint256 gasPerPubdataByteLimit - ) external payable { - require(msg.sender == governor, "Only governor is allowed"); - - IZkSync zksync = IZkSync(zkSyncAddress); - zksync.requestL2Transaction{value: msg.value}(contractAddr, 0, - data, gasLimit, gasPerPubdataByteLimit, new bytes[](0), msg.sender); - } -} -``` - -### Deploy L1 Governance Contract - -1. Create the file `L1-Governance/sepolia.json` and copy/paste the code below, filling in the relevant values. Find node - provider urls [here](https://chainlist.org/chain/11155111). You have to connect your wallet to the network and add - the network to the wallet in advance. - -`L1-Governance/sepolia.json` file - -```json -{ - "nodeUrl": "<SEPOLIA NODE URL>", - "deployerPrivateKey": "<YOUR PRIVATE KEY>" -} -``` - -2. Replace the code in `hardhat.config.ts` with the following: - -```ts -import '@nomicfoundation/hardhat-ethers'; -import { HardhatUserConfig } from 'hardhat/config'; - -// import file with Sepolia params -const sepolia = require('./sepolia.json'); - -const config: HardhatUserConfig = { - solidity: { - version: '0.8.20', - }, - networks: { - // Sepolia network - sepolia: { - url: sepolia.nodeUrl, - accounts: [sepolia.deployerPrivateKey], - }, - }, -}; - -export default config; -``` - -3. Navigate to the `scripts` folder and copy/paste the following code into the `deploy.ts` file (removing any previous - code): - -```ts -// We require the Hardhat Runtime Environment explicitly here. This is optional -// but useful for running the script in a standalone fashion through `node <script>`. -// -// When running the script with `npx hardhat run <script>` you'll find the Hardhat -// Runtime Environment's members available in the global scope. -import { ethers } from 'hardhat'; - -async function main() { - // We get the contract to deploy - const Governance = await ethers.getContractFactory('Governance'); - - const contract = await Governance.deploy(); - const receipt = await contract.deploymentTransaction()?.wait(); - - console.log(`Governance contract was successfully deployed at ${receipt?.contractAddress}`); -} - -// We recommend always using this async/await pattern to properly handle errors. -main().catch((error) => { - console.error(error); - process.exitCode = 1; -}); -``` - -4. From the `L1-governance` folder root, compile and deploy the contract: - -::: code-tabs @tab yarn - -```sh -# compile contract -yarn hardhat compile - -# deploy contract -yarn hardhat run --network sepolia ./scripts/deploy.ts -``` - -@tab npm - -```sh -# compile contract -npx hardhat compile - -# deploy contract -npx hardhat run --network sepolia ./scripts/deploy.ts -``` - -::: - -You should see output like this: - -```sh -Governance contract was successfully deployed at 0xf28Df77fa8ff56cA3084bd11c1CAF5033A7b8C4A -``` - -Save the address to use in a later step. - -## L2 Counter - -Now that we have an address for the L1 governance contract, we can build, deploy, and test the counter contract on L2. - -1. `cd` out of `L1-governance` and initialize the `L2-counter` project: - -```sh -npx zksync-cli create L2-counter --template hardhat_solidity -``` - -::: tip In case of any issues on this step (f.e. you did not have a yarn), you may get errors during the recreation of -the project environment. Clean your current environment in advance or create another folder and create environment -there. ::: - -2. For the purposes of this tutorial, we don't need the Greeter related files generated by the zkSync-CLI. So, proceed - with removing `Greeter.sol` from our `/contracts` directory: - -```sh -rm -rf ./contracts/Greeter.sol -``` - -3. Similarly, remove the deploy scripts associated with the Greeter contract: - -```sh -rm -rf ./deploy/deploy-greeter.ts && rm -rf ./deploy/use-greeter.ts -``` - -### Create L2 Counter Contract - -1. In the `L2-counter/contracts/` directory, create a new file `Counter.sol`. - -This contract contains the address of the governance contract deployed previously on layer 1, and an incrementable -counter which can only be invoked by the governance contract. - -2. Copy/paste the following code into the file: - -```solidity -// SPDX-License-Identifier: Unlicense - -pragma solidity ^0.8.20; - -contract Counter { - uint256 public value = 0; - address public governance; - - constructor(address newGovernance) { - governance = newGovernance; - } - - function increment() public { - require(msg.sender == governance, "Only governance is allowed"); - - value += 1; - } -} -``` - -3. Compile the contract from the `L2-counter` root: ::: tip Compilations happens only after the installation of a - compiler ::: - -::: code-tabs @tab yarn - -```sh -yarn hardhat compile -``` - -@tab npm - -```sh -npx hardhat compile -``` - -::: - -### Deploy L2 Counter Contract - -1. Copy/paste the following code into `L2-counter/deploy/deploy.ts`, replacing `<GOVERNANCE-ADDRESS>` with the address - of the Governance contract we just deployed, and `<WALLET-PRIVATE-KEY>` with your private key: - -```typescript -import { utils, Wallet } from 'zksync-ethers'; -import { HardhatRuntimeEnvironment } from 'hardhat/types'; -import { Deployer } from '@matterlabs/hardhat-zksync-deploy'; -// load env file -import dotenv from 'dotenv'; -dotenv.config(); - -// Insert the address of the governance contract -const GOVERNANCE_ADDRESS = '<GOVERNANCE-ADDRESS>'; - -// An example of a deploy script that will deploy and call a simple contract. -export default async function (hre: HardhatRuntimeEnvironment) { - console.log(`Running deploy script for the Counter contract`); - - const PRIVATE_KEY = process.env.WALLET_PRIVATE_KEY || ''; - if (!PRIVATE_KEY) throw '⛔️ Private key not detected! Add it to the .env file!'; - // Initialize the wallet. - const wallet = new Wallet(PRIVATE_KEY); - - // Create deployer object and load the artifact of the contract you want to deploy. - const deployer = new Deployer(hre, wallet); - const artifact = await deployer.loadArtifact('Counter'); - - // Deploy this contract. The returned object will be of a `Contract` type, similar to the ones in `ethers`. - // The address of the governance is an argument for contract constructor. - const counterContract = await deployer.deploy(artifact, [utils.applyL1ToL2Alias(GOVERNANCE_ADDRESS)]); - - const receipt = await counterContract.deploymentTransaction()?.wait(); - - // Show the contract info. - const contractAddress = receipt?.contractAddress; - console.log(`${artifact.contractName} was deployed to ${contractAddress}`); -} -``` - -::: tip Deposit funds during deployment The deployment script contains a deposit from Sepolia to zkSync Era testnet, -which can take a few minutes to finish. If your wallet already has funds in L2, you can skip that part to save you some -time. ::: - -2. Now deploy the contract from the `L2-counter/` folder root to zkSync: - -::: code-tabs @tab yarn - -```sh -yarn hardhat deploy-zksync -``` - -@tab npm - -```sh -npx hardhat deploy-zksync -``` - -::: - -You should see output like this: - -```txt -Running deploy script for the Counter contract -Counter was deployed to 0x3c5A6AB2390F6217C78d2F6F403A9dFb7e7784FC -``` - -::: tip For more information about deploying contracts, check out the -[quickstart tutorial](../../quick-start/hello-world.md) or the documentation for the zkSync -[hardhat plugins](../../tooling/hardhat/getting-started.md). ::: - -## Read the Counter Value - -Now both contracts are deployed, we can create a script to retrieve the value of the counter. - -1. Create the `scripts` directory under `L2-counter`. - -2. Copy the `abi` array from the compilation artifact located at - `/L2-counter/artifacts-zk/contracts/Counter.sol/Counter.json`. - -3. Create a new file `/L2-counter/scripts/counter.json` and paste in the `abi` array. - -4. Create a `/L2-counter/scripts/display-value.ts` file and paste in the following code, adding the counter contract - address: - -```ts -import { Contract, Provider } from 'zksync-ethers'; - -const COUNTER_ADDRESS = '<COUNTER-ADDRESS>'; -const COUNTER_ABI = require('./counter.json'); - -async function main() { - // Initialize the provider - const l2Provider = new Provider('https://sepolia.era.zksync.dev'); - - const counterContract = new Contract(COUNTER_ADDRESS, COUNTER_ABI, l2Provider); - - const value = (await counterContract.value()).toString(); - - console.log(`The counter value is ${value}`); -} - -main().catch((error) => { - console.error(error); - process.exitCode = 1; -}); -``` - -5. Run the script: - -::: code-tabs @tab yarn - -```sh -yarn ts-node ./scripts/display-value.ts -``` - -@tab npm - -```sh -npx ts-node ./scripts/display-value.ts -``` - -::: - -The output should be: - -```txt -The counter value is 0 -``` - -## Call L2 Contract from L1 - -Now, let's call the `increment` method on Layer 2 from Layer 1. - -1. Copy the `abi` array from the compilation artifact located at: - -`/L1-governance/artifacts/contracts/Governance.sol/Governance.json`. - -You have to copy only abi content from the file after the keyword abi, an example below: - -```json -[ - { - "inputs": [ - { - "internalType": "address", - "name": "newGovernance", - "type": "address" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "inputs": [], - "name": "governance", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "increment", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "value", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - } -] -``` - -2. Paste it into a new file: `/L2-counter/scripts/governance.json`. - -3. Create the `L2-counter/scripts/increment-counter.ts` file and paste in the following code, replacing the following - details: - -- GOVERNANCE-ADDRESS: the address of the contract deployed in L1. -- COUNTER-ADDRESS: the address of the contract deployed in L2. -- WALLET-PRIVATE-KEY: the private key of your account. -- RPC-URL: the same url you used in the `sepolia.json` file. - -```ts -import { Contract, Wallet, Interface } from 'ethers'; -import { Provider, utils } from 'zksync-ethers'; -// load env file -import dotenv from 'dotenv'; -dotenv.config(); - -const GOVERNANCE_ABI = require('./governance.json'); -const GOVERNANCE_ADDRESS = '<GOVERNANCE-ADDRESS>'; -const COUNTER_ABI = require('./counter.json'); -const COUNTER_ADDRESS = '<COUNTER-ADDRESS>'; - -const PRIVATE_KEY = process.env.WALLET_PRIVATE_KEY || ''; -if (!PRIVATE_KEY) throw '⛔️ Private key not detected! Add it to the .env file!'; -// Initialize the wallet. - -async function main() { - // Enter your Ethereum L1 provider RPC URL. - const l1Provider = new Provider('<L1-RPC-URL>'); - // Set up the Governor wallet to be the same as the one that deployed the governance contract. - const wallet = new Wallet(PRIVATE_KEY, l1Provider); - // Set a constant that accesses the Layer 1 contract. - const govcontract = new Contract(GOVERNANCE_ADDRESS, GOVERNANCE_ABI, wallet); - - // Initialize the L2 provider. - const l2Provider = new Provider('https://sepolia.era.zksync.dev'); - // Get the current address of the zkSync L1 bridge. - const zkSyncAddress = await l2Provider.getMainContractAddress(); - // Get the `Contract` object of the zkSync bridge. - const zkSyncContract = new Contract(zkSyncAddress, utils.ZKSYNC_MAIN_ABI, wallet); - - // Encoding the L1 transaction is done in the same way as it is done on Ethereum. - // Use an Interface which gives access to the contract functions. - const counterInterface = new Interface(COUNTER_ABI); - const data = counterInterface.encodeFunctionData('increment', []); - - // The price of an L1 transaction depends on the gas price used. - // You should explicitly fetch the gas price before making the call. - const gasPrice = await l1Provider.getGasPrice(); - - // Define a constant for gas limit which estimates the limit for the L1 to L2 transaction. - const gasLimit = await l2Provider.estimateL1ToL2Execute({ - contractAddress: COUNTER_ADDRESS, - calldata: data, - caller: utils.applyL1ToL2Alias(GOVERNANCE_ADDRESS), - }); - // baseCost takes the price and limit and formats the total in wei. - // For more information on `REQUIRED_L1_TO_L2_GAS_PER_PUBDATA_LIMIT` see the [fee model documentation](../developer-guides/transactions/fee-model.md). - const baseCost = await zkSyncContract.l2TransactionBaseCost( - gasPrice, - gasLimit, - utils.REQUIRED_L1_TO_L2_GAS_PER_PUBDATA_LIMIT - ); - - // !! If you don't include the gasPrice and baseCost in the transaction, a re-estimation of fee may generate errors. - const tx = await govcontract.callZkSync( - zkSyncAddress, - COUNTER_ADDRESS, - data, - gasLimit, - utils.REQUIRED_L1_TO_L2_GAS_PER_PUBDATA_LIMIT, - { - // Pass the necessary ETH `value` to cover the fee for the operation - value: baseCost, - gasPrice, - } - ); - - // Wait until the L1 tx is complete. - await tx.wait(); - - // Get the TransactionResponse object for the L2 transaction corresponding to the execution call. - const l2Response = await l2Provider.getL2TransactionFromPriorityOp(tx); - - // Output the receipt of the L2 transaction corresponding to the call to the counter contract. - const l2Receipt = await l2Response.wait(); - console.log(l2Receipt); -} - -// We recommend always using this async/await pattern to properly handle errors. -main().catch((error) => { - console.error(error); - process.exitCode = 1; -}); -``` - -:::tip - -- Executing transactions from L1 requires the caller to pay a fee to the L2 operator. The fee depends on the length of - the calldata and the `gasLimit`. This is similar to the `gasLimit` on Ethereum. You can read more about the - [zkSync fee model here](../../developer-reference/fee-model.md). -- The fee also depends on the gas price that is used during the transaction call. So to have a predictable fee for the - call, the gas price should be fetched from the L1 provider. - -::: - -1. Run the script with the following command: - -::: code-tabs @tab yarn - -```sh -yarn ts-node ./scripts/increment-counter.ts -``` - -@tab npm - -```sh -npx ts-node ./scripts/increment-counter.ts -``` - -::: - -In the output, you should see the full transaction receipt in L2. You can take the `transactionHash` and track it in the -[zkSync explorer](https://sepolia.explorer.zksync.io/). It should look something like this: - -```json -{ - to: '0x9b379893bfAD08c12C2167C3e3dBf591BeD9410a', - from: '0xE2EA97507a6cb610c81c4A9c157B8060E2ED7036', - contractAddress: null, - transactionIndex: 0, - root: '0xb9ca78c288163a322a797ee671db8e9ab430eb00e38c4a989f2246ea22493945', - gasUsed: BigNumber { _hex: '0x05c3df', _isBigNumber: true }, - logsBloom: '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', - blockHash: '0xb9ca78c288163a322a797ee671db8e9ab430eb00e38c4a989f2246ea22493945', - transactionHash: '0x1fb19cc0aca8fcccaf5fbafd9174550f3151d0d2aa15d99eb820e0394313e409', - logs: [ - { - transactionIndex: 0, - blockNumber: 4119331, - transactionHash: '0x1fb19cc0aca8fcccaf5fbafd9174550f3151d0d2aa15d99eb820e0394313e409', - address: '0x000000000000000000000000000000000000800A', - topics: [Array], - ... - -``` - -5. Verify that the transaction was successful by running the `display-value` script again. - -```sh -npx ts-node ./scripts/display-value.ts -``` - -You should see an incremented value in the output: - -```txt -The counter value is 1 -``` - -## Learn More - -- To learn more about L1->L2 interaction on zkSync, check out the - [documentation](../../developer-reference/l1-l2-interop.md). -- To learn more about the `zksync-ethers` SDK, check out its - [documentation](../../sdks/js/zksync-ethers/getting-started.md). -- To learn more about the zkSync hardhat plugins, check out their - [documentation](../../tooling/hardhat/getting-started.md). diff --git a/content/20.build/tutorials/smart-contract-development/paymasters/allowlist.md b/content/20.build/tutorials/smart-contract-development/paymasters/allowlist.md deleted file mode 100644 index bd8a2ba5..00000000 --- a/content/20.build/tutorials/smart-contract-development/paymasters/allowlist.md +++ /dev/null @@ -1,235 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: AllowList | zkSync Docs ---- - -# AllowList - -### Introduction - -zkSync offers native account abstraction enabling contracts to pay transaction fees on behalf of users. The -**AllowlistPaymaster** contract is one such way to utilize this, paying fees for a specified list of approved users, -hence enhancing user experience by alleviating gas cost concerns. - -This guide will outline the process of creating an AllowlistPaymaster contract to cover the gas fees of certain users. -It provides an overview of the smart contract developed, and the steps required to deploy and operate it.; - -:::info For detailed explanations of the IPaymaster interface please refer to the documentation -[here](../../../developer-reference/account-abstraction.md#ipaymaster-interface). ::: - -### Prerequisites - -- **Knowledge Base**: You should be familiar with Solidity and Hardhat. -- **Wallet Setup**: Have MetaMask installed and set up, ensuring there's a balance on the zkSync testnet.; -- **Tooling**: This guide utilizes [`zksync-cli`](../../../tooling/zksync-cli/getting-started.md). Ensure you have it - accessible or installed in your environment. - -### Step 1 — Understanding the AllowlistPaymaster Contract - -The `AllowlistPaymaster` contract is designed to be owned by an account that controls its operations. It maintains a -list of addresses which are allowed to have their gas fees paid for by this contract. - -Key components: - -- **allowList**: A mapping to track addresses that are allowed to utilize this Paymaster. -- **validateAndPayForPaymasterTransaction**: The validation logic that checks if a given address is on the allow list.; -- **setBatchAllowance**: Allows the owner to update the allowList in batches for efficiency. - -Each paymaster should implement the -[IPaymaster](https://github.com/matter-labs/era-contracts/blob/main/l2-contracts/contracts/interfaces/IPaymaster.sol) -interface. We will be using `zksync-cli` to bootstrap the boilerplate code for this paymaster. - -### Step 2 — Environment Setup - -Using `zksync-cli` we will create a new project with the required dependencies and boilerplate paymaster -implementations: - -```sh -npx zksync-cli@latest create gaslessPaymaster -``` - -Choose the following options: - -```sh -? What type of project do you want to create? Contracts -? Ethereum framework Ethers v6 -? Template Hardhat + Solidity -? Private key of the wallet responsible for deploying contracts (optional) -? Package manager yarn -``` - -The contract for this guide exists under `/contracts/GeneralPaymaster.sol`. - -**Update the Environment File**: - -If you didn't enter your wallet private key in the CLI prompt, enter it in the `.env` file. - -Ensure your account has a sufficient balance. - -### Step 3 — Updating the Contract - -For convenience, rename the `GeneralPaymaster.sol` contract to `AllowlistPaymaster.sol` also changing the name of the -contract in the source file. - -Add the `allowList` mapping and event emit line to the contract: - -```solidity -contract AllowlistPaymaster is IPaymaster, Ownable { - // The paymaster will pay the gas fee for the accounts in allowList - mapping(address => bool) public allowList; - // Emits events when list has been updated - event UpdateAllowlist(address _target, bool _allowed); -``` - -The `allowList` mapping will be used to track addresses that are allowed to utilize this Paymaster, and we will emit an -event whenever the list has been updated. - -Add a constructor method that adds the owner to the list: - -```solidity -constructor() { - // adds owner to allow list - allowList[msg.sender] = true; -} -``` - -We need to include the validation logic in the `validateAndPayForPaymasterTransaction` function in the contract. Insert -the following code under the `if(paymasterInputSelector == IPaymasterFlow.general.selector){` condition check: - -```solidity -// extract the address from the Transaction object -address userAddress = address(uint160(_transaction.from)); - -// checks if account is in allowList -bool isAllowed = allowList[userAddress]; -// validates if address is on the allowList -require(isAllowed, "Account is not in allow list"); -``` - -During the validation step, the contract will check if the address is included in our `allowList` mapping, if not the -account will be required to pay their gas costs. - -Next, we need to include the ability to update the `allowList` in batches. Add the following function to the contract: - -```solidity -function setBatchAllowance( - address[] calldata _targets, - bool[] calldata _allowances -) external onlyOwner { - uint256 targetsLength = _targets.length; - require( - targetsLength == _allowances.length, - "Account and permission lists should have the same length" - ); // The size of arrays should be equal - - for (uint256 i = 0; i < targetsLength; i++) { - _setAllowance(_targets[i], _allowances[i]); - } -} - -function _setAllowance(address _target, bool _allowed) internal { - bool isAllowed = allowList[_target]; - - if (isAllowed != _allowed) { - allowList[_target] = _allowed; - emit UpdateAllowlist(_target, _allowed); - } -} -``` - -The contract checks if the number of addresses in `_targets` matches the number of permissions in `_allowances`. If they -don't match, it reverts the transaction with an error message. For each address, it sets its allowance using the -`_setAllowance` function. Fetching the current allowance status of the `_target` address, compares the current status -with the new status `_allowed`. If the statuses differ, it updates the `allowList` mapping with the new status. - -### Step 4 — Deploy the Contract - -Create a new file under `/deploy`, for example `deploy-allowListPaymaster.ts`. Insert the provided script: - -```typescript -import { Provider, Wallet } from 'zksync-ethers'; -import * as ethers from 'ethers'; -import { HardhatRuntimeEnvironment } from 'hardhat/types'; -import { Deployer } from '@matterlabs/hardhat-zksync-deploy'; - -// load env file -import dotenv from 'dotenv'; -dotenv.config(); - -// load wallet private key from env file -const PRIVATE_KEY = process.env.WALLET_PRIVATE_KEY || ''; - -if (!PRIVATE_KEY) throw '⛔️ Private key not detected! Add it to the .env file!'; - -export default async function (hre: HardhatRuntimeEnvironment) { - console.log(`Running deploy script for the AllowlistPaymaster contract...`); - const provider = new Provider('https://sepolia.era.zksync.dev'); - - // The wallet that will deploy the token and the paymaster - // It is assumed that this wallet already has sufficient funds on zkSync - const wallet = new Wallet(PRIVATE_KEY); - const deployer = new Deployer(hre, wallet); - - // Deploying the paymaster - const paymasterArtifact = await deployer.loadArtifact('AllowlistPaymaster'); - const deploymentFee = await deployer.estimateDeployFee(paymasterArtifact, []); - const parsedFee = ethers.formatEther(deploymentFee.toString()); - console.log(`The deployment is estimated to cost ${parsedFee} ETH`); - // Deploy the contract - const paymaster = await deployer.deploy(paymasterArtifact, []); - const paymasterAddress = await paymaster.getAddress(); - console.log(`Paymaster address: ${paymasterAddress}`); - console.log(`Contract owner added to allow list: ${wallet.address}`); - - console.log('Funding paymaster with ETH'); - // Supplying paymaster with ETH - await ( - await deployer.zkWallet.sendTransaction({ - to: paymasterAddress, - value: ethers.parseEther('0.005'), - }) - ).wait(); - - let paymasterBalance = await provider.getBalance(paymasterAddress); - console.log(`Paymaster ETH balance is now ${paymasterBalance.toString()}`); - console.log(`Done!`); -} -``` - -:::info Be sure to add your private key to the `.env` file.; ::: - -The provided script takes care of loading environment variables, setting up a deployment wallet with the private key -specified in an `.env` file, contract deployment and funding the paymaster. You can adjust the amount of ETH to fund the -paymaster to your needs.; - -Compile the contract: - -```bash -yarn hardhat compile -``` - -Once compiled, deploy using: - -```bash -yarn hardhat deploy-zksync --script deploy-allowListPaymaster.ts -``` - -### Step 5 — Managing the Allowlist - -As the owner of the contract, you can now: - -- **Add users to the allowList**: Use `setBatchAllowance` to add multiple users at once. Provide an array of addresses - and a corresponding array of boolean values (true for allowing). -- **Remove users from the allowList**: Again use `setBatchAllowance`, but provide `false` for the addresses you want to - remove. - -### Conclusion - -The AllowlistPaymaster contract on zkSync Era offers a streamlined approach to improve user experience by covering their -gas fees. Through an effective management of the allowList, dApp developers and businesses can absorb transaction costs -for their users, fostering growth and adoption. - -For a deeper dive and further optimization of the AllowlistPaymaster, consider consulting zkSync's official -documentation and developer community forums. diff --git a/content/20.build/tutorials/smart-contract-development/paymasters/custom-paymaster-tutorial.md b/content/20.build/tutorials/smart-contract-development/paymasters/custom-paymaster-tutorial.md deleted file mode 100644 index c0e49d3e..00000000 --- a/content/20.build/tutorials/smart-contract-development/paymasters/custom-paymaster-tutorial.md +++ /dev/null @@ -1,577 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Custom Paymaster Tutorial | zkSync Docs ---- - -# Building a Custom Paymaster - -This tutorial shows you how to build a custom paymaster that allows users to pay fees with any ERC20 token. You will: - -- Create a paymaster that assumes a single unit of an ERC20 token is enough to cover any transaction fee. -- Create the ERC20 token contract and send some tokens to a new wallet. -- Send a `mint` transaction from the newly created wallet via the paymaster. Although the transaction normally requires - ETH to pay the gas fee, our paymaster executes the transaction in exchange for 1 unit of the ERC20 token. - -## Prerequisites - -- Make sure your machine satisfies the - [system requirements](https://github.com/matter-labs/era-compiler-solidity/tree/main#system-requirements). -- A [Node.js](https://nodejs.org/en/download) installation running Node.js version 16. -- Some familiarity with deploying smart contracts on zkSync. If not, please refer to the first section of the - [quickstart tutorial](../../../quick-start/hello-world.md). -- Some background knowledge on the concepts covered by the tutorial would be helpful too. Have a look at the following - docs: - - [Account abstraction protocol](../../../developer-reference/account-abstraction.md). - - [Introduction to system contracts](../../../developer-reference/system-contracts.md). - - [Smart contract deployment](../../../developer-reference/contract-deployment.md) on zkSync Era. - - [Gas estimation for transactions](../../../developer-reference/fee-model.md#gas-estimation-for-transactions) guide. -- You should also know - [how to get your private key from your MetaMask wallet](https://support.metamask.io/hc/en-us/articles/360015289632-How-to-export-an-account-s-private-key). - -## Complete Project - -The tutorial code is available [here](https://github.com/matter-labs/tutorials/tree/main/custom-paymaster). - -::: info Project available in Atlas IDE - -This entire tutorial can be run in under a minute using Atlas. Atlas is a smart contract IDE that lets you write, -deploy, and interact with contracts from your browser. -[Open this project in Atlas](https://app.atlaszk.com/projects?template=https://github.com/atlas-labs-inc/zksync-custom-paymaster&open=/scripts/main.ts&chainId=280) -::: - -## Setup the Project - -1. Initiate a new project by running the command: - -```sh -npx zksync-cli create custom-paymaster-tutorial --template hardhat_solidity -``` - -This creates a new zkSync Era project called `custom-paymaster-tutorial` with a basic `Greeter` contract. - -2. Navigate into the project directory: - -```sh -cd custom-paymaster-tutorial -``` - -::: info The template project includes multiple example contracts. Feel free to delete them. ::: - -## Design - -### Paymaster Solidity Contract - -The contract code defines an ERC20 token and allows it to be used to pay the fees for transactions. - -The skeleton contract looks like this: - -```solidity -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; - -import {IPaymaster, ExecutionResult, PAYMASTER_VALIDATION_SUCCESS_MAGIC} from "@matterlabs/zksync-contracts/l2/system-contracts/interfaces/IPaymaster.sol"; -import {IPaymasterFlow} from "@matterlabs/zksync-contracts/l2/system-contracts/interfaces/IPaymasterFlow.sol"; -import {TransactionHelper, Transaction} from "@matterlabs/zksync-contracts/l2/system-contracts/libraries/TransactionHelper.sol"; - -import "@matterlabs/zksync-contracts/l2/system-contracts/Constants.sol"; - -contract MyPaymaster is IPaymaster { - uint256 constant PRICE_FOR_PAYING_FEES = 1; - - address public allowedToken; - - modifier onlyBootloader() { - require(msg.sender == BOOTLOADER_FORMAL_ADDRESS, "Only bootloader can call this method"); - // Continue execution if called from the bootloader. - _; - } - - constructor(address _erc20) { - allowedToken = _erc20; - } - - function validateAndPayForPaymasterTransaction ( - bytes32, - bytes32, - Transaction calldata _transaction - ) external payable onlyBootloader returns (bytes4 magic, bytes memory context) { - // TO BE IMPLEMENTED - } - - function postTransaction ( - bytes calldata _context, - Transaction calldata _transaction, - bytes32, - bytes32, - ExecutionResult _txResult, - uint256 _maxRefundedGas - ) external payable onlyBootloader override { - } - - receive() external payable {} -} -``` - -:::info - -- Only the [bootloader](../../../developer-reference/system-contracts.md#bootloader) is allowed to call the - `validateAndPayForPaymasterTransaction` and `postTransaction` functions. -- To implement that, the `onlyBootloader` modifier is used on these functions. ::: - -### Parsing the Paymaster Input - -The paymaster pays the transaction fees and charges the user one unit of the `allowedToken` in exchange. - -The input that the paymaster receives is encoded in the `paymasterInput` within the -`validateAndPayForPaymasterTransaction` function. - -As described in [the paymaster documentation](../../../developer-reference/account-abstraction.md#paymasters), there are -standardized ways to encode user interactions with `paymasterInput`. To charge the user, we require that she has -provided enough allowance of the ERC20 token to the paymaster contract. This allowance is done in the `approvalBased` -flow behind the scenes. - -Firstly, we check that the `paymasterInput` is encoded as in the `approvalBased` flow, and that the token sent in -`paymasterInput` is the one the paymaster accepts. - -```solidity -magic = PAYMASTER_VALIDATION_SUCCESS_MAGIC; - -require( - _transaction.paymasterInput.length >= 4, - "The standard paymaster input must be at least 4 bytes long" -); - -bytes4 paymasterInputSelector = bytes4(_transaction.paymasterInput[0:4]); -if (paymasterInputSelector == IPaymasterFlow.approvalBased.selector) { - (address token, uint256 minAllowance, bytes memory data) = abi.decode(_transaction.paymasterInput[4:], (address, uint256, bytes)); - - // We verify that the user has provided enough allowance - require(token == allowedToken, "Invalid token"); - - // - // ... - // -} else { - revert("Unsupported paymaster flow"); -} -``` - -Next, we check the user provided enough allowance: - -```solidity -// We verify that the user has provided enough allowance -address userAddress = address(uint160(_transaction.from)); - -address thisAddress = address(this); - -uint256 providedAllowance = IERC20(token).allowance( - userAddress, - thisAddress -); -require(providedAllowance >= PRICE_FOR_PAYING_FEES, "Min allowance too low"); -``` - -Finally, we check the price of transaction fees, transfer the ERC20 tokens to the paymaster, and transfer the -correspondent gas fee from the paymaster to the bootloader to cover the transaction fees. - -```solidity -// Note, that while the minimal amount of ETH needed is tx.gasPrice * tx.gasLimit, -// neither paymaster nor account are allowed to access this context variable. -uint256 requiredETH = _transaction.gasLimit * - _transaction.maxFeePerGas; - -try - IERC20(token).transferFrom(userAddress, thisAddress, amount) -{} catch (bytes memory revertReason) { - // If the revert reason is empty or represented by just a function selector, - // we replace the error with a more user-friendly message - if (revertReason.length <= 4) { - revert("Failed to transferFrom from users' account"); - } else { - assembly { - revert(add(0x20, revertReason), mload(revertReason)) - } - } -} - -// Transfer fees to the bootloader -(bool success, ) = payable(BOOTLOADER_FORMAL_ADDRESS).call{ - value: requiredETH -}(""); -require(success, "Failed to transfer tx fee to the bootloader. Paymaster balance might not be enough."); -``` - -::: tip Validate all requirements first The -[validation steps](../../../developer-reference/account-abstraction.md#the-validation-step) ensure that the paymaster -won't throttle if the first storage read which has a different value from the execution on the API is a storage slot -that belongs to the user. - -This is why it is important to verify transaction prerequisites _before_ performing any logic and why we _first_ check -that the user provided enough allowance before calling `transferFrom`. ::: - -## Paymaster Contract Full Code - -Create the `contracts/MyPaymaster.sol` file and copy/paste the following: - -```solidity -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; - -import {IPaymaster, ExecutionResult, PAYMASTER_VALIDATION_SUCCESS_MAGIC} from "@matterlabs/zksync-contracts/l2/system-contracts/interfaces/IPaymaster.sol"; -import {IPaymasterFlow} from "@matterlabs/zksync-contracts/l2/system-contracts/interfaces/IPaymasterFlow.sol"; -import {TransactionHelper, Transaction} from "@matterlabs/zksync-contracts/l2/system-contracts/libraries/TransactionHelper.sol"; - -import "@matterlabs/zksync-contracts/l2/system-contracts/Constants.sol"; - -contract MyPaymaster is IPaymaster { - uint256 constant PRICE_FOR_PAYING_FEES = 1; - - address public allowedToken; - - modifier onlyBootloader() { - require( - msg.sender == BOOTLOADER_FORMAL_ADDRESS, - "Only bootloader can call this method" - ); - // Continue execution if called from the bootloader. - _; - } - - constructor(address _erc20) { - allowedToken = _erc20; - } - - function validateAndPayForPaymasterTransaction( - bytes32, - bytes32, - Transaction calldata _transaction - ) - external - payable - onlyBootloader - returns (bytes4 magic, bytes memory context) - { - // By default we consider the transaction as accepted. - magic = PAYMASTER_VALIDATION_SUCCESS_MAGIC; - require( - _transaction.paymasterInput.length >= 4, - "The standard paymaster input must be at least 4 bytes long" - ); - - bytes4 paymasterInputSelector = bytes4( - _transaction.paymasterInput[0:4] - ); - if (paymasterInputSelector == IPaymasterFlow.approvalBased.selector) { - // While the transaction data consists of address, uint256 and bytes data, - // the data is not needed for this paymaster - (address token, uint256 amount, bytes memory data) = abi.decode( - _transaction.paymasterInput[4:], - (address, uint256, bytes) - ); - - // Verify if token is the correct one - require(token == allowedToken, "Invalid token"); - - // We verify that the user has provided enough allowance - address userAddress = address(uint160(_transaction.from)); - - address thisAddress = address(this); - - uint256 providedAllowance = IERC20(token).allowance( - userAddress, - thisAddress - ); - require( - providedAllowance >= PRICE_FOR_PAYING_FEES, - "Min allowance too low" - ); - - // Note, that while the minimal amount of ETH needed is tx.gasPrice * tx.gasLimit, - // neither paymaster nor account are allowed to access this context variable. - uint256 requiredETH = _transaction.gasLimit * - _transaction.maxFeePerGas; - - try - IERC20(token).transferFrom(userAddress, thisAddress, amount) - {} catch (bytes memory revertReason) { - // If the revert reason is empty or represented by just a function selector, - // we replace the error with a more user-friendly message - if (revertReason.length <= 4) { - revert("Failed to transferFrom from users' account"); - } else { - assembly { - revert(add(0x20, revertReason), mload(revertReason)) - } - } - } - - // The bootloader never returns any data, so it can safely be ignored here. - (bool success, ) = payable(BOOTLOADER_FORMAL_ADDRESS).call{ - value: requiredETH - }(""); - require( - success, - "Failed to transfer tx fee to the bootloader. Paymaster balance might not be enough." - ); - } else { - revert("Unsupported paymaster flow"); - } - } - - function postTransaction( - bytes calldata _context, - Transaction calldata _transaction, - bytes32, - bytes32, - ExecutionResult _txResult, - uint256 _maxRefundedGas - ) external payable override onlyBootloader { - } - - receive() external payable {} -} -``` - -## Create ERC20 Contract - -For the sake of simplicity we will use a modified OpenZeppelin ERC20 implementation: - -Create the `contracts/MyERC20.sol` file and copy/paste the following: - -```solidity -// SPDX-License-Identifier: UNLICENSED - -pragma solidity ^0.8.0; - -import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; - -contract MyERC20 is ERC20 { - uint8 private _decimals; - - constructor( - string memory name_, - string memory symbol_, - uint8 decimals_ - ) ERC20(name_, symbol_) { - _decimals = decimals_; - } - - function mint(address _to, uint256 _amount) public returns (bool) { - _mint(_to, _amount); - return true; - } - - function decimals() public view override returns (uint8) { - return _decimals; - } -} -``` - -## Compile and Deploy the Contracts - -The script below deploys the ERC20 contract and the paymaster contract. It also mints some `MyERC20` tokens into the -account we use to deploy the contracts to use them with the paymaster at a later step. In addition, the script sends -`0.06ETH` to the paymaster contract so it can pay the transaction fees we send later on. - -1. In the `deploy` folder, create the file `deploy-paymaster.ts` and copy/paste the following. Make sure the private key - of the account used to deploy the contracts is configured in the `.env` file of the project.: - -```ts -import { deployContract, getWallet, getProvider } from './utils'; -import * as ethers from 'ethers'; - -export default async function () { - const erc20 = await deployContract('MyERC20', ['MyToken', 'MyToken', 18]); - const erc20Address = await erc20.getAddress(); - const paymaster = await deployContract('MyPaymaster', [erc20Address]); - - const paymasterAddress = await paymaster.getAddress(); - - // Supplying paymaster with ETH - console.log('Funding paymaster with ETH...'); - const wallet = getWallet(); - await ( - await wallet.sendTransaction({ - to: paymasterAddress, - value: ethers.parseEther('0.06'), - }) - ).wait(); - - const provider = getProvider(); - const paymasterBalance = await provider.getBalance(paymasterAddress); - console.log(`Paymaster ETH balance is now ${paymasterBalance.toString()}`); - - // Supplying the ERC20 tokens to the wallet: - // We will give the wallet 3 units of the token: - await (await erc20.mint(wallet.address, 3)).wait(); - - console.log('Minted 3 tokens for the wallet'); - console.log(`Done!`); -} -``` - -2. Compile and the contracts from the project root: - -```sh -yarn hardhat compile -``` - -3. Execute the deployment script: - -```sh -yarn hardhat deploy-zksync --script deploy-paymaster.ts -``` - -The output should be roughly the following: - -``` -Starting deployment process of "MyERC20"... -Estimated deployment cost: 0.00077890075 ETH - -"MyERC20" was successfully deployed: - - Contract address: 0x26b368C3Ed16313eBd6660b72d8e4439a697Cb0B - - Contract source: contracts/MyERC20.sol:MyERC20 - - Encoded constructor arguments: 0x000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000074d79546f6b656e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000074d79546f6b656e00000000000000000000000000000000000000000000000000 - - -Starting deployment process of "MyPaymaster"... -Estimated deployment cost: 0.000545256 ETH - -"MyPaymaster" was successfully deployed: - - Contract address: 0x094499Df5ee555fFc33aF07862e43c90E6FEe501 - - Contract source: contracts/MyPaymaster.sol:MyPaymaster - - Encoded constructor arguments: 0x00000000000000000000000026b368c3ed16313ebd6660b72d8e4439a697cb0b - -Funding paymaster with ETH... -Paymaster ETH balance is now 60000000000000000 -Minted 3 tokens for the wallet -Done! -``` - -:::tip - -- Addresses and private keys are different on each run. -- Make sure you delete the `artifacts-zk` and `cache-zk` folders before recompiling. ::: - -## Using the Paymaster - -1. Create the `use-paymaster.ts` script in the `deploy` folder, replacing the parameter placeholders with the details - from the previous deploy step. - -::: warning Make sure you use the private key of the wallet created by the previous script as that wallet contains the -ERC20 tokens. ::: - -```ts -import { utils, Wallet } from 'zksync-ethers'; -import { getWallet, getProvider } from './utils'; -import * as ethers from 'ethers'; -import { HardhatRuntimeEnvironment } from 'hardhat/types'; - -// Put the address of the deployed paymaster here -const PAYMASTER_ADDRESS = '<PAYMASTER_ADDRESS>'; - -// Put the address of the ERC20 token here: -const TOKEN_ADDRESS = '<TOKEN_ADDRESS>'; - -function getToken(hre: HardhatRuntimeEnvironment, wallet: Wallet) { - const artifact = hre.artifacts.readArtifactSync('MyERC20'); - return new ethers.Contract(TOKEN_ADDRESS, artifact.abi, wallet); -} - -export default async function (hre: HardhatRuntimeEnvironment) { - const provider = getProvider(); - const wallet = getWallet(); - - console.log(`ERC20 token balance of the wallet before mint: ${await wallet.getBalance(TOKEN_ADDRESS)}`); - - let paymasterBalance = await provider.getBalance(PAYMASTER_ADDRESS); - console.log(`Paymaster ETH balance is ${paymasterBalance.toString()}`); - - const erc20 = getToken(hre, wallet); - const gasPrice = await provider.getGasPrice(); - - // Encoding the "ApprovalBased" paymaster flow's input - const paymasterParams = utils.getPaymasterParams(PAYMASTER_ADDRESS, { - type: 'ApprovalBased', - token: TOKEN_ADDRESS, - // set minimalAllowance as we defined in the paymaster contract - minimalAllowance: BigInt('1'), - // empty bytes as testnet paymaster does not use innerInput - innerInput: new Uint8Array(), - }); - - // Estimate gas fee for mint transaction - const gasLimit = await erc20.mint.estimateGas(wallet.address, 5, { - customData: { - gasPerPubdata: utils.DEFAULT_GAS_PER_PUBDATA_LIMIT, - paymasterParams: paymasterParams, - }, - }); - - const fee = gasPrice * gasLimit; - console.log('Transaction fee estimation is :>> ', fee.toString()); - - console.log(`Minting 5 tokens for the wallet via paymaster...`); - await ( - await erc20.mint(wallet.address, 5, { - // paymaster info - customData: { - paymasterParams: paymasterParams, - gasPerPubdata: utils.DEFAULT_GAS_PER_PUBDATA_LIMIT, - }, - }) - ).wait(); - - console.log(`Paymaster ERC20 token balance is now ${await erc20.balanceOf(PAYMASTER_ADDRESS)}`); - paymasterBalance = await provider.getBalance(PAYMASTER_ADDRESS); - - console.log(`Paymaster ETH balance is now ${paymasterBalance.toString()}`); - console.log(`ERC20 token balance of the the wallet after mint: ${await wallet.getBalance(TOKEN_ADDRESS)}`); -} -``` - -2. Run the script: - -```sh -yarn hardhat deploy-zksync --script use-paymaster.ts -``` - -The output should look something like this: - -```txt -ERC20 token balance of the wallet before mint: 3 -Paymaster ETH balance is 60000000000000000 -Transaction fee estimation is :>> 568750000000000 -Minting 5 tokens for the wallet via paymaster... -Paymaster ERC20 token balance is now 1 -Paymaster ETH balance is now 59650952750000000 -ERC20 token balance of the the wallet after mint: 7 -``` - -The wallet had 3 tokens after running the deployment script and, after sending the transaction to `mint` 5 more tokens, -the balance is 7 as 1 token was used to pay the transaction fee to the paymaster. The paymaster paid the fees for the -mint transaction with ETH. - -## Common Errors - -- If the `use-paymaster.ts` script fails with the error - `Failed to submit transaction: Failed to validate the transaction. Reason: Validation revert: Paymaster validation error: Failed to transfer tx fee to the bootloader. Paymaster balance might not be enough.`, - please try sending additional ETH to the paymaster so it has enough funds to pay for the transaction. You can use - [zkSync native bridge or ecosystem partners](https://zksync.io/explore#bridges) (make sure Sepolia testnet is - supported by selected bridge). -- If the `use-paymaster.ts` script fails when minting new ERC20 tokens with the error `Error: transaction failed`, and - the transactions appear with status "Failed" in the [zkSync explorer](https://explorer.zksync.io/), please reach out - to us on [our Discord](https://join.zksync.dev/). As a workaround, try including a specific `gasLimit` value in the - transaction. - -## Learn More - -- Learn more about [L1->L2 interaction on zkSync](../../../developer-reference/l1-l2-interop.md). -- Learn more about [the `zksync-ethers` SDK](../../../sdks/js/zksync-ethers/getting-started.md). -- Learn more about [the zkSync hardhat plugins](../../../tooling/hardhat/getting-started.md). diff --git a/content/20.build/tutorials/smart-contract-development/paymasters/erc20fixed.md b/content/20.build/tutorials/smart-contract-development/paymasters/erc20fixed.md deleted file mode 100644 index 612cc930..00000000 --- a/content/20.build/tutorials/smart-contract-development/paymasters/erc20fixed.md +++ /dev/null @@ -1,384 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: ERC20Fixed | zkSync Docs ---- - -# ERC20Fixed - -### Introduction - -zkSync's native account abstraction allows contracts to cover transaction fees on behalf of users, significantly -improving user experience. The **`ERC20FixedPaymaster`** contract, discussed in this guide, offers transactions gas -coverage for accounts that have a balance of a specific ERC20 token. - -:::info For detailed explanations of the IPaymaster interface please refer to the documentation -[here](../../../developer-reference/account-abstraction.md#ipaymaster-interface). ::: - -### Prerequisites - -- **Knowledge Base**: You should be familiar with Solidity and Hardhat. -- **Wallet Setup**: Ensure your zkSync testnet wallet holds a balance in both ETH and the specific ERC-20 token intended - for the paymaster contract -- **Tooling**: This guide utilizes [`zksync-cli`](../../../tooling/zksync-cli/getting-started.md). Ensure you have it - accessible or installed in your environment. - -### **Step 1 — Understanding the ERC20FixedPaymaster contract** - -The provided `ApprovalPaymaster` contract allows transactions to have the gas covered in a specified ERC-20 token for -accounts that hold a balance of a specific ERC20 token. For the purposes of this guide we will make use of the -[DAI ERC-20 token](https://sepolia.explorer.zksync.io/address/0x6Ff473f001877D553833B6e312C89b3c8fACa7Ac). - -**Key components**: - -- `validateAndPayForPaymasterTransaction`: Validates the user's token balance, checks the transaction allowance, - calculates the required ETH, and pays the bootloader. - -Each paymaster should implement the `IPaymaster` interface. We will be using `zksync-cli` to bootstrap the boilerplate -code for this paymaster. - -### **Step 2 — Environment setup** - -Using `zksync-cli` create a new project with required dependencies: - -```bash -npx zksync-cli create erc20FixedPaymaster -``` - -Choose the following options: - -```sh -? What type of project do you want to create? Contracts -? Ethereum framework Ethers v6 -? Template Hardhat + Solidity -? Private key of the wallet responsible for deploying contracts (optional) -? Package manager yarn -``` - -The contract for this guide exists under `/contracts/ApprovalPaymaster.sol`. - -**Update the Environment File**: - -If you didn't enter your wallet private key in the CLI prompt, enter it in the `.env` file. - -Ensure your account has a sufficient balance. - -### Step 3 — Updating the Contract - -No modifications are needed for ERC20Fixed paymaster since the provided `ApprovalPaymaster` contract is already -configured for this purpose. - -Reviewing the `validateAndPayForPaymasterTransaction` function reveals its simplicity: it verifies if the token is -correct, the user holds the token and has provided enough allowance. - -```solidity -(address token, uint256 amount, bytes memory data) = abi.decode( - _transaction.paymasterInput[4:], - (address, uint256, bytes) -); - -// Verify if token is the correct one -require(token == allowedToken, "Invalid token"); - -// We verify that the user has provided enough allowance -address userAddress = address(uint160(_transaction.from)); - -address thisAddress = address(this); - -uint256 providedAllowance = IERC20(token).allowance( - userAddress, - thisAddress -); -require( - providedAllowance >= PRICE_FOR_PAYING_FEES, - "Min allowance too low" -); -``` - -### Step 4 — Deploy the Contract - -Create a new file under `/deploy`, for example `deploy-erc20FixedPaymaster.ts`. Insert the provided script: - -#### deploy-erc20FixedPaymaster.ts - -```typescript -import { Provider, Wallet } from 'zksync-ethers'; -import * as ethers from 'ethers'; -import { HardhatRuntimeEnvironment } from 'hardhat/types'; -import { Deployer } from '@matterlabs/hardhat-zksync-deploy'; - -// load env file -import dotenv from 'dotenv'; -dotenv.config(); - -// load wallet private key from env file -const PRIVATE_KEY = process.env.WALLET_PRIVATE_KEY || ''; -// The address of the DAI token contract -const TOKEN_ADDRESS = '0x6Ff473f001877D553833B6e312C89b3c8fACa7Ac'; - -if (!PRIVATE_KEY) throw '⛔️ Private key not detected! Add it to the .env file!'; - -if (!TOKEN_ADDRESS) throw '⛔️ TOKEN_ADDRESS not detected! Add it to the TOKEN_ADDRESS variable!'; - -export default async function (hre: HardhatRuntimeEnvironment) { - console.log(`Running deploy script for the ApprovalPaymaster contract...`); - const provider = new Provider('https://sepolia.era.zksync.dev'); - // The wallet that will deploy the token and the paymaster - // It is assumed that this wallet already has sufficient funds on zkSync - const wallet = new Wallet(PRIVATE_KEY); - const deployer = new Deployer(hre, wallet); - - // Deploying the paymaster - const paymasterArtifact = await deployer.loadArtifact('ApprovalPaymaster'); - const deploymentFee = await deployer.estimateDeployFee(paymasterArtifact, [TOKEN_ADDRESS]); - const parsedFee = ethers.formatEther(deploymentFee.toString()); - console.log(`The deployment is estimated to cost ${parsedFee} ETH`); - // Deploy the contract - const paymaster = await deployer.deploy(paymasterArtifact, [TOKEN_ADDRESS]); - const paymasterAddress = await paymaster.getAddress(); - console.log(`Paymaster address: ${paymasterAddress}`); - - console.log('Funding paymaster with ETH'); - // Supplying paymaster with ETH - await ( - await deployer.zkWallet.sendTransaction({ - to: paymasterAddress, - value: ethers.parseEther('0.005'), - }) - ).wait(); - - let paymasterBalance = await provider.getBalance(paymasterAddress); - console.log(`Paymaster ETH balance is now ${paymasterBalance.toString()}`); - - // Verify contract programmatically - // - // Contract MUST be fully qualified name (e.g. path/sourceName:contractName) - const contractFullyQualifedName = 'contracts/paymasters/ApprovalPaymaster.sol:ApprovalPaymaster'; - const verificationId = await hre.run('verify:verify', { - address: paymasterAddress, - contract: contractFullyQualifedName, - constructorArguments: [TOKEN_ADDRESS], - bytecode: paymasterArtifact.bytecode, - }); - console.log(`${contractFullyQualifedName} verified! VerificationId: ${verificationId}`); - - console.log(`Done!`); -} -``` - -:::info Update the `TOKEN_ADDRESS` variable to the address of your preferred token. ::: - -Compile the contract: - -```bash -yarn hardhat compile -``` - -Deploy the contract: - -```bash -yarn hardhat deploy-zksync --script deploy-erc20FixedPaymaster.ts -``` - -### Step 5 — Testing the Contract - -To test the functionality, you can utilize a mock ERC-20 token contract. This will help confirm that the paymaster -operates as expected. Inside the `/contracts/` directory, create a file named `ERC20.sol` and insert the following -contract: - -#### ERC20.sol - -```solidity -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; - -/** - * @dev This contract is for basic demonstration purposes only. It should not be used in production. - * It is for the convenience of the ERC20fixedPaymaster.sol contract and its corresponding test file. - */ -contract MyERC20 is ERC20 { - uint8 private _decimals; - - constructor( - string memory name, - string memory symbol, - uint8 decimals_ - ) payable ERC20(name, symbol) { - _decimals = decimals_; - } - - function mint(address _to, uint256 _amount) public returns (bool) { - _mint(_to, _amount); - return true; - } - - function decimals() public view override returns (uint8) { - return _decimals; - } - - function burn(address from, uint256 amount) public { - _burn(from, amount); - } -} -``` - -To further validate the operations of the ERC20FixedPaymaster contract, we've provided a test script. Create a file -named `erc20FixedPaymaster.test.ts` within the `/test` directory, then populate it with the subsequent script:. - -#### erc20FixedPaymaster.test.ts - -```typescript -import { expect } from 'chai'; -import { Wallet, Provider, Contract, utils } from 'zksync-ethers'; -import hardhatConfig from '../hardhat.config'; -import { Deployer } from '@matterlabs/hardhat-zksync-deploy'; -import * as ethers from 'ethers'; -import * as hre from 'hardhat'; - -// load env file -import dotenv from 'dotenv'; -dotenv.config(); - -// test pk rich wallet from in-memory node -const PRIVATE_KEY = '0x7726827caac94a7f9e1b160f7ea819f172f7b6f9d2a97f992c38edeab82d4110'; - -describe.only('ERC20fixedPaymaster', function () { - let provider: Provider; - let wallet: Wallet; - let deployer: Deployer; - let userWallet: Wallet; - let ownerInitialBalance: BigInt; - let paymaster: Contract; - let greeter: Contract; - let token: Contract; - let paymasterAddress: string; - let tokenAddress: string; - let greeterAddress: string; - - before(async function () { - const deployUrl = hardhatConfig.networks.inMemoryNode.url; - // setup deployer - [provider, wallet, deployer] = setupDeployer(deployUrl, PRIVATE_KEY); - // setup new wallet - const emptyWallet = Wallet.createRandom(); - console.log(`Empty wallet's address: ${emptyWallet.address}`); - userWallet = new Wallet(emptyWallet.privateKey, provider); - // deploy contracts - token = await deployContract(deployer, 'MyERC20', ['MyToken', 'MyToken', 18]); - tokenAddress = await token.getAddress(); - paymaster = await deployContract(deployer, 'ApprovalPaymaster', [tokenAddress]); - paymasterAddress = await paymaster.getAddress(); - greeter = await deployContract(deployer, 'Greeter', ['Hi']); - greeterAddress = await greeter.getAddress(); - // fund paymaster - await fundAccount(wallet, paymasterAddress, '3'); - ownerInitialBalance = await wallet.getBalance(); - }); - - async function executeGreetingTransaction(user: Wallet) { - const gasPrice = await provider.getGasPrice(); - - const paymasterParams = utils.getPaymasterParams(paymasterAddress, { - type: 'ApprovalBased', - token: tokenAddress, - minimalAllowance: BigInt(1), - // empty bytes as testnet paymaster does not use innerInput - innerInput: new Uint8Array(), - }); - - await greeter.connect(user); - const setGreetingTx = await greeter.setGreeting('Hola, mundo!', { - maxPriorityFeePerGas: BigInt(0), - maxFeePerGas: gasPrice, - // hardcoded for testing - gasLimit: 6000000, - customData: { - gasPerPubdata: utils.DEFAULT_GAS_PER_PUBDATA_LIMIT, - paymasterParams, - }, - }); - - await setGreetingTx.wait(); - - return wallet.getBalance(); - } - - it('user with MyERC20 token can update message for free', async function () { - const initialMintAmount = ethers.parseEther('3'); - const success = await token.mint(userWallet.address, initialMintAmount); - await success.wait(); - - const userInitialTokenBalance = await token.balanceOf(userWallet.address); - const userInitialETHBalance = await userWallet.getBalance(); - const initialPaymasterBalance = await provider.getBalance(paymasterAddress); - - await executeGreetingTransaction(userWallet); - - const finalETHBalance = await userWallet.getBalance(); - const finalUserTokenBalance = await token.balanceOf(userWallet.address); - const finalPaymasterBalance = await provider.getBalance(paymasterAddress); - - expect(await greeter.greet()).to.equal('Hola, mundo!'); - expect(initialPaymasterBalance).to.be.gt(finalPaymasterBalance); - expect(userInitialETHBalance).to.eql(finalETHBalance); - expect(userInitialTokenBalance.gt(finalUserTokenBalance)).to.be.true; - }); - - it('should allow owner to withdraw all funds', async function () { - try { - await paymaster.connect(wallet); - const tx = await paymaster.withdraw(userWallet.address); - await tx.wait(); - } catch (e) { - console.error('Error executing withdrawal:', e); - } - - const finalContractBalance = await provider.getBalance(paymasterAddress); - - expect(finalContractBalance).to.eql(BigInt(0)); - }); - - it('should prevent non-owners from withdrawing funds', async function () { - try { - await paymaster.connect(userWallet); - await paymaster.withdraw(userWallet.address); - } catch (e) { - expect(e.message).to.include('Ownable: caller is not the owner'); - } - }); - - async function deployContract(deployer: Deployer, contract: string, params: any[]): Promise<Contract> { - const artifact = await deployer.loadArtifact(contract); - return await deployer.deploy(artifact, params); - } - - async function fundAccount(wallet: Wallet, address: string, amount: string) { - await (await wallet.sendTransaction({ to: address, value: ethers.parseEther(amount) })).wait(); - } - - function setupDeployer(url: string, privateKey: string): [Provider, Wallet, Deployer] { - const provider = new Provider(url); - const wallet = new Wallet(privateKey, provider); - const deployer = new Deployer(hre, wallet); - return [provider, wallet, deployer]; - } -}); -``` - -This particular script assesses the paymaster's ability to cover gas expenses for accounts, provided they hold a balance -in the designated ERC20 token. - -To execute test: - -```bash -yarn hardhat test --network hardhat -``` - -### Conclusion - -The `ERC20FixedPaymaster` contract introduces an efficient mechanism, allowing developers to cover gas fees for users -holding a specific ERC20 token with that ERC20 token. This improves UX for dApps, making it easier for users to interact -without worrying about gas fees. Further customizations or protocol-specific validations can be added as necessary. diff --git a/content/20.build/tutorials/smart-contract-development/paymasters/gasless.md b/content/20.build/tutorials/smart-contract-development/paymasters/gasless.md deleted file mode 100644 index 5270ea56..00000000 --- a/content/20.build/tutorials/smart-contract-development/paymasters/gasless.md +++ /dev/null @@ -1,254 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Gasless | zkSync Docs ---- - -# Gasless - -### Introduction - -zkSync's native account abstraction allows contracts to cover transaction fees on behalf of users, significantly -improving user experience. The **`GaslessPaymaster`** contract offers a method to deploy a universal paymaster which -ensures transactions are gasless for users.; - -This guide describes the process of setting up and deploying the **`GaslessPaymaster`** contract. - -:::info For detailed explanations of the IPaymaster interface please refer to the documentation -[here](../../../developer-reference/account-abstraction.md#ipaymaster-interface). ::: - -### Prerequisites - -- **Knowledge Base**: You should be familiar with Solidity and Hardhat. -- **Wallet Setup**: Have MetaMask installed and set up, ensuring there's a balance on the zkSync testnet. -- **Tooling**: This guide utilizes [`zksync-cli`](../../../tooling/zksync-cli/getting-started.md). Ensure you have it - accessible or installed in your environment. - -### Step 1 — Understanding the GaslessPaymaster Contract - -The `GaslessPaymaster` contract ensures that transaction fees are handled automatically without user intervention. - -Key components: - -- **validateAndPayForPaymasterTransaction**: This function validates the transaction, calculates the required ETH based - on gas limits, and transfers the fees to the bootloader. - -Each paymaster should implement the -[IPaymaster](https://github.com/matter-labs/era-contracts/blob/main/l2-contracts/contracts/interfaces/IPaymaster.sol) -interface. We will be using `zksync-cli` to bootstrap the boilerplate code for this paymaster. - -### Step 2 — Environment Setup - -Using `zksync-cli` create a new project with the required dependencies and boilerplate paymaster implementations. - -```sh -npx zksync-cli create gaslessPaymaster -``` - -Choose the following options: - -```sh -? What type of project do you want to create? Contracts -? Ethereum framework Ethers v6 -? Template Hardhat + Solidity -? Private key of the wallet responsible for deploying contracts (optional) -? Package manager yarn -``` - -The contract for this guide exists under `/contracts/GeneralPaymaster.sol`. - -**Update the Environment File**: - -If you didn't enter your wallet private key in the CLI prompt, enter it in the `.env` file. - -Ensure your account has a sufficient balance. - -### Step 3 — Updating the Contract - -No modifications are needed for gasless transactions since the provided `GeneralPaymaster` contract is already -configured for this purpose. With no restrictions on its usage. - -Reviewing the `validateAndPayForPaymasterTransaction` function reveals its simplicity: it only verifies that the -paymaster holds sufficient ETH. - -### Step 4 — Deploy the Contract - -Create a new file under `/deploy`, for example `deploy-gaslessPaymaster.ts`. Insert the provided script: - -Deployment script - -```typescript -import { Provider, Wallet } from 'zksync-ethers'; -import * as ethers from 'ethers'; -import { HardhatRuntimeEnvironment } from 'hardhat/types'; -import { Deployer } from '@matterlabs/hardhat-zksync-deploy'; - -// load env file -import dotenv from 'dotenv'; -dotenv.config(); - -// load wallet private key from env file -const PRIVATE_KEY = process.env.WALLET_PRIVATE_KEY || ''; - -if (!PRIVATE_KEY) throw '⛔️ Private key not detected! Add it to the .env file!'; - -export default async function (hre: HardhatRuntimeEnvironment) { - console.log(`Running deploy script for the GaslessPaymaster contract...`); - const provider = new Provider('https://sepolia.era.zksync.dev'); - - // The wallet that will deploy the token and the paymaster - // It is assumed that this wallet already has sufficient funds on zkSync - const wallet = new Wallet(PRIVATE_KEY); - const deployer = new Deployer(hre, wallet); - - // Deploying the paymaster - const paymasterArtifact = await deployer.loadArtifact('GeneralPaymaster'); - const deploymentFee = await deployer.estimateDeployFee(paymasterArtifact, []); - const parsedFee = ethers.formatEther(deploymentFee.toString()); - console.log(`The deployment is estimated to cost ${parsedFee} ETH`); - // Deploy the contract - const paymaster = await deployer.deploy(paymasterArtifact, []); - const paymasterAddress = await paymaster.getAddress(); - console.log(`Paymaster address: ${paymasterAddress}`); - - console.log('Funding paymaster with ETH'); - // Supplying paymaster with ETH - await ( - await deployer.zkWallet.sendTransaction({ - to: paymasterAddress, - value: ethers.parseEther('0.005'), - }) - ).wait(); - - let paymasterBalance = await provider.getBalance(paymasterAddress); - console.log(`Paymaster ETH balance is now ${paymasterBalance.toString()}`); - console.log(`Done!`); -} -``` - -:::info Be sure to add your private key to the `.env` file.; ::: - -The provided script takes care of loading environment variables, setting up a deployment wallet with the private key -specified in an `.env` file, contract deployment and funding the paymaster. You can adjust the amount of ETH to fund the -paymaster to your needs.; - -Compile the contract: - -```bash -yarn hardhat compile -``` - -Once compiled, deploy using: - -```bash -yarn hardhat deploy-zksync --script deploy-gaslessPaymaster.ts -``` - -### Step 5 — Testing the Contract - -To verify the functionality of the GaslessPaymaster contract, let's draft a quick test. - -Set it up by creating `gaslessTest.test.ts` in the `/test` directory and populating it with the provided script: - -#### gasless.test.ts - -```typescript -import { expect } from 'chai'; -import { Wallet, Provider, Contract, utils } from 'zksync-ethers'; -import hardhatConfig from '../hardhat.config'; -import { Deployer } from '@matterlabs/hardhat-zksync-deploy'; -import * as hre from 'hardhat'; -import * as ethers from 'ethers'; -import dotenv from 'dotenv'; - -dotenv.config(); - -// test pk rich wallet from in-memory node -const PRIVATE_KEY = '0x7726827caac94a7f9e1b160f7ea819f172f7b6f9d2a97f992c38edeab82d4110'; - -describe.only('GaslessPaymaster', function () { - let provider: Provider; - let wallet: Wallet; - let deployer: Deployer; - let emptyWallet: Wallet; - let userWallet: Wallet; - let ownerInitialBalance: BigInt; - let paymaster: Contract; - let greeter: Contract; - let paymasterAddress: string; - - before(async function () { - // @ts-ignore - [provider, wallet, deployer] = setupDeployer(hardhatConfig.networks.inMemoryNode.url, PRIVATE_KEY); - emptyWallet = Wallet.createRandom(); - userWallet = new Wallet(emptyWallet.privateKey, provider); - paymaster = await deployContract(deployer, 'GeneralPaymaster', []); - paymasterAddress = await paymaster.getAddress(); - greeter = await deployContract(deployer, 'Greeter', ['Hi']); - await fundAccount(wallet, paymasterAddress, '3'); - ownerInitialBalance = await wallet.getBalance(); - }); - - async function executeGreetingTransaction(user: Wallet) { - const gasPrice = await provider.getGasPrice(); - const paymasterParams = utils.getPaymasterParams(paymasterAddress, { - type: 'General', - innerInput: new Uint8Array(), - }); - - await greeter.connect(user); - - const setGreetingTx = await greeter.setGreeting('Hola, mundo!', { - maxPriorityFeePerGas: BigInt(0), - maxFeePerGas: gasPrice, - gasLimit: 6000000, - customData: { - gasPerPubdata: utils.DEFAULT_GAS_PER_PUBDATA_LIMIT, - paymasterParams, - }, - }); - - await setGreetingTx.wait(); - return wallet.getBalance(); - } - - it('Owner can update message for free', async function () { - const newBalance = await executeGreetingTransaction(userWallet); - expect(await greeter.greet()).to.equal('Hola, mundo!'); - expect(newBalance).to.eql(ownerInitialBalance); - }); - - async function deployContract(deployer: Deployer, contract: string, params: any[]): Promise<Contract> { - const artifact = await deployer.loadArtifact(contract); - return await deployer.deploy(artifact, params); - } - - async function fundAccount(wallet: Wallet, address: string, amount: string) { - await (await wallet.sendTransaction({ to: address, value: ethers.parseEther(amount) })).wait(); - } - - function setupDeployer(url: string, privateKey: string): [Provider, Wallet, Deployer] { - const provider = new Provider(url); - const wallet = new Wallet(privateKey, provider); - const deployer = new Deployer(hre, wallet); - return [provider, wallet, deployer]; - } -}); -``` - -This script tests whether the GaslessPaymaster contract permits a user to modify a message in the "Greeter" contract -without incurring any gas charges. The necessary paymaster parameters are provided when invoking the `setGreeting` -method, showcasing our gasless paymaster in action. - -To execute test: - -```bash -yarn hardhat test --network hardhat -``` - -### Conclusion - -The `GaslessPaymaster` contract provides an effortless way to cover gas fees, ensuring a seamless experience for users. -It represents a breakthrough for dApps and businesses aiming to increase adoption by making user transactions gasless. -You can add protocol specific validations for more control, an adaptation of which can be reviewed in the next section. diff --git a/content/20.build/tutorials/smart-contract-development/paymasters/timebased.md b/content/20.build/tutorials/smart-contract-development/paymasters/timebased.md deleted file mode 100644 index a9cfedf4..00000000 --- a/content/20.build/tutorials/smart-contract-development/paymasters/timebased.md +++ /dev/null @@ -1,302 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: TimeBased | zkSync Docs ---- - -# TimeBased - -### Introduction - -zkSync brings forth the possibility to cover transaction fees on behalf of users through native account abstraction, -promoting user experience. The `TimeBasedPaymaster` contract presented in this guide ensures transactions are validated -based on the time they occur. By utilizing this guide, developers can set up, deploy, and test the `TimeBasedPaymaster` -contract. - -:::info For a more in-depth understanding of the IPaymaster interface, please refer to the official zkSync documentation -[here](../../../developer-reference/account-abstraction.md#ipaymaster-interface). ::: - -### Prerequisites - -- **Knowledge Base**: Familiarity with Solidity and Hardhat. -- **Wallet Setup**: MetaMask installation with balance on zkSync testnet. -- **Tooling**: Ensure you have `zksync-cli` either accessible or installed. - -### Step 1 — Understanding the TimeBasedPaymaster contract - -The `TimeBasedPaymaster` contract allows transactions within a specific timeframe to have the gas covered. - -Key components: - -- **validateAndPayForPaymasterTransaction**: Validates the transaction time, checks if the transaction is within the - defined time window, calculates the required ETH, and pays the bootloader. - -Each paymaster should implement the -[IPaymaster](https://github.com/matter-labs/era-contracts/blob/main/l2-contracts/contracts/interfaces/IPaymaster.sol) -interface. We will be using `zksync-cli` to bootstrap the boilerplate code for this paymaster. - -### Step 2 — Environment Setup - -Using `zksync-cli` create a new project with the required dependencies and boilerplate paymaster implementations: - -```bash -npx zksync-cli create timeBasedPaymaster -``` - -Choose the following options: - -```sh -? What type of project do you want to create? Contracts -? Ethereum framework Ethers v6 -? Template Hardhat + Solidity -? Private key of the wallet responsible for deploying contracts (optional) -? Package manager yarn -``` - -The contract for this guide exists under `/contracts/GeneralPaymaster.sol`. - -**Update the Environment File**: - -If you didn't enter your wallet private key in the CLI prompt, enter it in the `.env` file. - -Ensure your account has a sufficient balance. - -### Step 3 — Updating the Contract - -For convenience, rename the `GeneralPaymaster.sol` contract to `TimeBasedPaymaster.sol` also changing the name of the -contract in the source file. - -The intended objective of the `TimeBasedPaymaster` contract is to permit transactions only between a stipulated -timeframe to cover the gas costs. - -Include the validation logic in the `validateAndPayForPaymasterTransaction` function in the contract. Insert the -following code under the `if(paymasterInputSelector == IPaymasterFlow.general.selector){` condition check: - -```solidity -uint256 startTime = (block.timestamp / 86400) * 86400 + 15 hours; - uint256 endTime = startTime + 20 minutes; - - require( - block.timestamp >= startTime && block.timestamp <= endTime, - "Transactions can only be processed between 14:35 - 14:55" - ); -``` - -During the validation step, the contract will check if the transaction is taking place between the specified time frame, -if not the account will be required to pay their own gas costs. Specifically, this contract checks if the transaction -takes place between 14:35 - 14:55 UTC. - -### Step 4 — Deploy the Contract - -Create a new file under `/deploy`, for example `deploy-timeBasedPaymaster.ts`. Insert the provided script: - -```typescript -import { Provider, Wallet } from 'zksync-ethers'; -import * as ethers from 'ethers'; -import { HardhatRuntimeEnvironment } from 'hardhat/types'; -import { Deployer } from '@matterlabs/hardhat-zksync-deploy'; - -// load env file -import dotenv from 'dotenv'; -dotenv.config(); - -// load wallet private key from env file -const PRIVATE_KEY = process.env.WALLET_PRIVATE_KEY || ''; - -if (!PRIVATE_KEY) throw '⛔️ Private key not detected! Add it to the .env file!'; - -export default async function (hre: HardhatRuntimeEnvironment) { - console.log(`Running deploy script for the TimeBasedPaymaster contract...`); - const provider = new Provider('https://sepolia.era.zksync.dev'); - - const wallet = new Wallet(PRIVATE_KEY); - const deployer = new Deployer(hre, wallet); - - const paymasterArtifact = await deployer.loadArtifact('TimeBasedPaymaster'); - const deploymentFee = await deployer.estimateDeployFee(paymasterArtifact, []); - const parsedFee = ethers.formatEther(deploymentFee.toString()); - console.log(`The deployment is estimated to cost ${parsedFee} ETH`); - // Deploy the contract - const paymaster = await deployer.deploy(paymasterArtifact, []); - const paymasterAddress = await paymaster.getAddress(); - console.log(`Paymaster address: ${paymasterAddress}`); - console.log('constructor args:' + paymaster.interface.encodeDeploy([])); - - console.log('Funding paymaster with ETH'); - // Supplying paymaster with ETH - await ( - await deployer.zkWallet.sendTransaction({ - to: paymasterAddress, - value: ethers.parseEther('0.005'), - }) - ).wait(); - - let paymasterBalance = await provider.getBalance(paymasterAddress); - console.log(`Paymaster ETH balance is now ${paymasterBalance.toString()}`); - - // Verify contract programmatically - // - // Contract MUST be fully qualified name (e.g. path/sourceName:contractName) - const contractFullyQualifedName = 'contracts/paymasters/TimeBasedPaymaster.sol:TimeBasedPaymaster'; - const verificationId = await hre.run('verify:verify', { - address: paymasterAddress, - contract: contractFullyQualifedName, - constructorArguments: [], - bytecode: paymasterArtifact.bytecode, - }); - console.log(`${contractFullyQualifedName} verified! VerificationId: ${verificationId}`); - console.log(`Done!`); -} -``` - -:::info Be sure to add your private key to the `.env` file. ::: - -The provided script takes care of loading environment variables, setting up a deployment wallet with the private key -specified in an `.env` file, contract deployment and funding the paymaster. You can adjust the amount of ETH to fund the -paymaster to your needs. - -Compile the contract: - -```bash -yarn hardhat compile -``` - -Deploy the contract: - -```bash -yarn hardhat deploy-zksync --script deploy-timeBasedPaymaster.ts -``` - -### Step 5 — Testing the Contract - -To verify the functionality of the TimeBased Paymaster contract, let's draft a quick test. Set it up by creating -`timeBasedPaymaster.test.ts` in the `/test` directory and populating it with the provided script: - -#### timeBasedPaymaster.test.ts - -```typescript -import { expect } from 'chai'; -import { Wallet, Provider, Contract, utils } from 'zksync-ethers'; -import hardhatConfig from '../hardhat.config'; -import { Deployer } from '@matterlabs/hardhat-zksync-deploy'; -import * as ethers from 'ethers'; -import * as hre from 'hardhat'; -import dotenv from 'dotenv'; - -dotenv.config(); - -// test pk rich wallet from in-memory node -const PRIVATE_KEY = '0x7726827caac94a7f9e1b160f7ea819f172f7b6f9d2a97f992c38edeab82d4110'; - -describe.only('TimeBasedPaymaster', function () { - let provider: Provider; - let wallet: Wallet; - let deployer: Deployer; - let userWallet: Wallet; - let paymaster: Contract; - let greeter: Contract; - let paymasterAddress: string; - - before(async function () { - const deployUrl = hardhatConfig.networks.inMemoryNode.url; - [provider, wallet, deployer] = setupDeployer(deployUrl, PRIVATE_KEY); - userWallet = Wallet.createRandom(); - console.log(`User wallet's address: ${userWallet.address}`); - userWallet = new Wallet(userWallet.privateKey, provider); - paymaster = await deployContract(deployer, 'TimeBasedPaymaster', []); - paymasterAddress = await paymaster.getAddress(); - greeter = await deployContract(deployer, 'Greeter', ['Hi']); - await fundAccount(wallet, paymasterAddress, '3'); - }); - - async function executeGreetingTransaction(user: Wallet) { - const gasPrice = await provider.getGasPrice(); - - const paymasterParams = utils.getPaymasterParams(paymasterAddress, { - type: 'General', - innerInput: new Uint8Array(), - }); - - await greeter.connect(user); - - const setGreetingTx = await greeter.setGreeting('Hola, mundo!', { - maxPriorityFeePerGas: BigInt(0), - maxFeePerGas: gasPrice, - gasLimit: 6000000, - customData: { - gasPerPubdata: utils.DEFAULT_GAS_PER_PUBDATA_LIMIT, - paymasterParams, - }, - }); - - await setGreetingTx.wait(); - } - - it('should cost the user no gas during the time window', async function () { - // Arrange - const currentDate = new Date(); - currentDate.setUTCHours(14); - currentDate.setUTCMinutes(1); - currentDate.setUTCSeconds(0); - currentDate.setUTCMilliseconds(0); - const targetTime = Math.floor(currentDate.getTime() / 1000); - await provider.send('evm_setNextBlockTimestamp', [targetTime]); - - // Act - const initialBalance = await userWallet.getBalance(); - await executeGreetingTransaction(userWallet); - await provider.send('evm_mine', []); - const newBalance = await userWallet.getBalance(); - - // Assert - expect(newBalance.toString()).to.equal(initialBalance.toString()); - expect(await greeter.greet()).to.equal('Hola, mundo!'); - }); - - it('should fail due to Paymaster validation error outside the time window', async function () { - // Arrange - let errorOccurred = false; - - // Act - try { - await executeGreetingTransaction(wallet); - } catch (error) { - errorOccurred = true; - expect(error.message).to.include('Paymaster validation error'); - } - - // Assert - expect(errorOccurred).to.be.true; - }); - async function deployContract(deployer: Deployer, contract: string, params: any[]): Promise<Contract> { - const artifact = await deployer.loadArtifact(contract); - return await deployer.deploy(artifact, params); - } - - async function fundAccount(wallet: Wallet, address: string, amount: string) { - await (await wallet.sendTransaction({ to: address, value: ethers.parseEther(amount) })).wait(); - } - - function setupDeployer(url: string, privateKey: string): [Provider, Wallet, Deployer] { - const provider = new Provider(url); - const wallet = new Wallet(privateKey, provider); - const deployer = new Deployer(hre, wallet); - return [provider, wallet, deployer]; - } -}); -``` - -This script tests whether the TimeBasedPaymaster contract permits a user to modify a message in the "Greeter" contract -without incurring any gas charges at different times. The necessary paymaster parameters are provided when invoking the -`setGreeting` method, showcasing our time based paymaster in action. - -```bash -yarn hardhat test --network hardhat -``` - -#### Conclusion - -The `TimeBasedPaymaster` contract bestows a novel capability on zkSync, allowing developers to limit transactions gas -coverage to a specific timeframe. This proves beneficial for scenarios demanding temporal restrictions. Further -adaptability or protocol-specific validations can be incorporated as needed. diff --git a/content/20.build/tutorials/tooling-guides/api3.md b/content/20.build/tutorials/tooling-guides/api3.md deleted file mode 100644 index 40266ad6..00000000 --- a/content/20.build/tutorials/tooling-guides/api3.md +++ /dev/null @@ -1,600 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: API3 | zkSync Docs ---- - -# API3 - -In this guide, we'll create a paymaster on zkSync Era, enabling transactions to be paid using the `mockUSDC` ERC20 -token, all while harnessing API3's dAPIs for accurate, decentralized price feeds. - -[API3➚](https://api3.org/) offers decentralized API services to blockchain platforms. API3 empowers smart contracts with -its data feeds, termed [dAPIs➚](https://docs.api3.org/guides/dapis/subscribing-self-funded-dapis/). These dAPIs, sourced -from first-party oracles, constantly relay signed, updated on-chain data. - -For our paymaster, we'll integrate dAPIs to fetch live -[ETH/USD](https://market.api3.org/dapis/zksync-goerli-testnet/ETH-USD) and -[USDC/USD](https://market.api3.org/dapis/zksync-goerli-testnet/USDC-USD) rates, facilitating users to settle their gas -costs in USDC equivalent. - -**Data Feed Addresses:** - -<table><thead><tr><th width="156">Price Pair</th><th width="353.3333333333333">Address</th><th>Network</th></tr></thead><tbody><tr><td>ETH / USD</td><td><code>0x28ce555ee7a3daCdC305951974FcbA59F5BdF09b</code></td><td>zkSync Testnet</td></tr><tr><td>USDC / USD</td><td><code>0x946E3232Cc18E812895A8e83CaE3d0caA241C2AB</code></td><td>zkSync Testnet</td></tr></tbody></table> - -### Prerequisites - -- **Knowledge Base**: Familiarity with deploying smart contracts. -- **Wallet Setup**: Have MetaMask installed and set up, ensuring there's a balance on the zkSync Testnet. -- **Tooling**: This guide utilizes [`zksync-cli`](../../tooling/zksync-cli/getting-started.md). Ensure you have it - accessible or installed in your environment. - -### Step 1 — Understanding the **mockUSDCPaymaster contract** - -The `mockUSDCPaymaster` contract offers a refined experience for users by allowing them to pay gas fees using `mockUSDC` -instead of `ETH`. This not only provides flexibility in transaction costs but also integrates real-time data feeds to -determine the exact value of `USDC` and `ETH` using API3 dAPIs. - -**Key components:** - -- **setDapiProxy**: A function to set the dAPI proxies for allowed tokens. The function stores the proxy addresses for - USDC and ETH, which are then used to fetch real-time price data. -- **readDapi**: A function that, given a dAPI proxy address, returns the real-time value. In the contract, it's used to - fetch the current values of `USDC` and `ETH`. -- **validateAndPayForPaymasterTransaction**: This function validates the transaction, ensures the received token makes - the allowed token, fetches real-time ETH and USRC prices using dAPIs, and calculate the required ERC20 tokens - equivalent to the value of required ETH. - -Each paymaster should implement the -[IPaymaster](https://github.com/matter-labs/era-contracts/blob/main/l2-contracts/contracts/interfaces/IPaymaster.sol) -interface. We will be using `zksync-cli` to bootstrap the boilerplate code for this paymaster. - -### Step 2 — Environment setup - -Using `zksync-cli` create a new project with the required dependencies and boilerplate paymaster implementations: - -<pre class="language-bash"><code class="lang-bash"><strong>npx zksync-cli create mockUSDCPaymaster -</strong></code></pre> - -Choose `Hardhat + Solidity` to setup the project repository. The contract for this guide exists under -`/contracts/ApprovalPaymaster.sol`. - -**Update the Environment File**: - -- Modify the `.env-example` file with your private key. -- Ensure your account has a sufficient balance. - -**Add the required dependencies to the project:** - -::: code-tabs - -@tab:active yarn - -```bash -yarn add -D @openzeppelin/contracts-upgradeable @api3/contracts -``` - -@tab npm - -```bash -npm install @openzeppelin/contracts-upgradeable @api3/contracts -``` - -::: - -### Step 3 - Implementing contracts - -Create a `mockUSDC.sol` contract to emulate a USDC equivalent in the `/contracts` directory. Populate the file with the -provided code: - -<details> - -<summary>mockUSDC.sol</summary> - -```solidity - -// SPDX-License-Identifier: UNLICENSED - -pragma solidity ^0.8.8; - -import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; - -contract MyERC20 is ERC20 { - uint8 private _decimals; - - constructor( - string memory name_, - string memory symbol_, - uint8 decimals_ - ) ERC20(name_, symbol_) { - _decimals = decimals_; - } - - function mint(address _to, uint256 _amount) public returns (bool) { - _mint(_to, _amount); - return true; - } - - function decimals() public view override returns (uint8) { - return _decimals; - } -} -``` - -</details> - -Using the `ApprovalPaymaster.sol` contract, add the following imports: - -```solidity -import "@openzeppelin/contracts/access/Ownable.sol"; -import "@api3/contracts/v0.8/interfaces/IProxy.sol"; -``` - -Inherit `Ownable` and declare the following public variables: - -```solidity -contract ApprovalPaymaster is IPaymaster, Ownable { - address public allowedToken; - address public USDCdAPIProxy; - address public ETHdAPIProxy; - uint256 public requiredETH; -} -``` - -Make a `public` `onlyOwner` function to set dAPI proxies: - -```solidity -// Set dapi proxies for the allowed token/s -function setDapiProxy(address _USDCproxy, address _ETHproxy) - public onlyOwner { - USDCdAPIProxy = _USDCproxy; - ETHdAPIProxy = _ETHproxy; -} -``` - -Make a `public` `view` function to read the dAPI values. This will read the price of **ETH/USD** and **USDC/USD** data -feeds: - -```solidity -// read the price of ETH/USD and USDC/USD data feeds -function readDapi(address _dapiProxy) public view returns (uint256) { - (int224 value, ) = IProxy(_dapiProxy).read(); - uint256 price = uint224(value); - return price; -} -``` - -Inside `validateAndPayForPaymasterTransaction()`, invoke the `readDapi()` function and add the logic to calculate the -required USDC to be sent by the user: - -```solidity -// Read values from the dAPIs -uint256 ETHUSDCPrice = readDapi(ETHdAPIProxy); -uint256 USDCUSDPrice = readDapi(USDCdAPIProxy); - -requiredETH = _transaction.gasLimit * - _transaction.maxFeePerGas; - -// Calculate the required ERC20 tokens to be sent to the paymaster -// (Equal to the value of requiredETH) -uint256 requiredERC20 = (requiredETH * ETHUSDCPrice)/USDCUSDPrice; -require( - providedAllowance >= requiredERC20, - "Min paying allowance too low" -); -``` - -Update the try-catch block to transfer the exact `requiredERC20` amount: - -```solidity - try - IERC20(token).transferFrom(userAddress, thisAddress, requiredERC20) -{} catch (bytes memory revertReason) { - // If the revert reason is empty or represented by just a function selector, - // we replace the error with a more user-friendly message - if (requiredERC20 > amount) { - revert("Not the required amount of tokens sent"); - } - if (revertReason.length <= 4) { - revert("Failed to transferFrom from users' account"); - } else { - assembly { - revert(add(0x20, revertReason), mload(revertReason)) - } - } -} -``` - -The full paymaster implementation can be viewed here: - -<details> - -<summary>mockUSDCPaymaster.sol</summary> - -```solidity -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.8; - -import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; - -import {IPaymaster, ExecutionResult, PAYMASTER_VALIDATION_SUCCESS_MAGIC} -from "@matterlabs/zksync-contracts/l2/system-contracts/interfaces/IPaymaster.sol"; -import {IPaymasterFlow} from "@matterlabs/zksync-contracts/l2/system-contracts/interfaces/IPaymasterFlow.sol"; -import {TransactionHelper, Transaction} from "@matterlabs/zksync-contracts/l2/system-contracts/libraries/TransactionHelper.sol"; -import "@openzeppelin/contracts/access/Ownable.sol"; -import "@api3/contracts/v0.8/interfaces/IProxy.sol"; - -import "@matterlabs/zksync-contracts/l2/system-contracts/Constants.sol"; - -contract ApprovalPaymaster is IPaymaster, Ownable { - - address public allowedToken; - address public USDCdAPIProxy; - address public ETHdAPIProxy; - uint256 public requiredETH; - - modifier onlyBootloader() { - require( - msg.sender == BOOTLOADER_FORMAL_ADDRESS, - "Only bootloader can call this method" - ); - // Continue execution if called from the bootloader. - _; - } - - constructor(address _erc20) { - allowedToken = _erc20; - } - - // Set dapi proxies for the allowed token/s - function setDapiProxy(address _USDCproxy, address _ETHproxy) - public onlyOwner { - USDCdAPIProxy = _USDCproxy; - ETHdAPIProxy = _ETHproxy; - } - - function readDapi(address _dapiProxy) public view returns (uint256) { - (int224 value, ) = IProxy(_dapiProxy).read(); - uint256 price = uint224(value); - return price; - } - - function validateAndPayForPaymasterTransaction ( - bytes32, - bytes32, - Transaction calldata _transaction - ) onlyBootloader external payable returns (bytes4 magic, bytes memory context) { - // By default we consider the transaction as accepted. - magic = PAYMASTER_VALIDATION_SUCCESS_MAGIC; - require( - _transaction.paymasterInput.length >= 4, - "The standard paymaster input must be at least 4 bytes long" - ); - - bytes4 paymasterInputSelector = bytes4( - _transaction.paymasterInput[0:4] - ); - if (paymasterInputSelector == IPaymasterFlow.approvalBased.selector) { - // While the transaction data consists of address, uint256 and bytes data, - // the data is not needed for this paymaster - (address token, uint256 amount, bytes memory data) = abi.decode( - _transaction.paymasterInput[4:], - (address, uint256, bytes) - ); - - // Verify if token is the correct one - require(token == allowedToken, "Invalid token"); - - // We verify that the user has provided enough allowance - address userAddress = address(uint160(_transaction.from)); - - address thisAddress = address(this); - - uint256 providedAllowance = IERC20(token).allowance( - userAddress, - thisAddress - ); - // Read values from the dAPIs - - uint256 ETHUSDCPrice = readDapi(ETHdAPIProxy); - uint256 USDCUSDPrice = readDapi(USDCdAPIProxy); - - requiredETH = _transaction.gasLimit * - _transaction.maxFeePerGas; - - // Calculate the required ERC20 tokens to be sent to the paymaster - // (Equal to the value of requiredETH) - - uint256 requiredERC20 = (requiredETH * ETHUSDCPrice)/USDCUSDPrice; - require( - providedAllowance >= requiredERC20, - "Min paying allowance too low" - ); - - // Note, that while the minimal amount of ETH needed is tx.gasPrice * tx.gasLimit, - // neither paymaster nor account are allowed to access this context variable. - try - IERC20(token).transferFrom(userAddress, thisAddress, requiredERC20) - {} catch (bytes memory revertReason) { - // If the revert reason is empty or represented by just a function selector, - // we replace the error with a more user-friendly message - if (requiredERC20 > amount) { - revert("Not the required amount of tokens sent"); - } - if (revertReason.length <= 4) { - revert("Failed to transferFrom from users' account"); - } else { - assembly { - revert(add(0x20, revertReason), mload(revertReason)) - } - } - } - - // The bootloader never returns any data, so it can safely be ignored here. - (bool success, ) = payable(BOOTLOADER_FORMAL_ADDRESS).call{ - value: requiredETH - }(""); - require(success, "Failed to transfer funds to the bootloader"); - } else { - revert("Unsupported paymaster flow"); - } - } - - function postTransaction ( - bytes calldata _context, - Transaction calldata _transaction, - bytes32, - bytes32, - ExecutionResult _txResult, - uint256 _maxRefundedGas - ) onlyBootloader external payable override { - } - - receive() external payable {} -} -``` - -</details> - -### Step 4 — Deploy the contract - -Create a new file under `/deploy`, for example `deploy-mockUSDCPaymaster.ts`. Insert the provided script: - -<details> - -<summary>Deployment script</summary> - -```typescript -import { Wallet } from 'zksync-ethers'; -import * as ethers from 'ethers'; -import { HardhatRuntimeEnvironment } from 'hardhat/types'; -import { Deployer } from '@matterlabs/hardhat-zksync-deploy'; - -require('dotenv').config(); -// load wallet private key from env file -const PRIVATE_KEY = process.env.PRIVATE_KEY || ''; - -export default async function (hre: HardhatRuntimeEnvironment) { - // The wallet that will deploy the token and the paymaster - // It is assumed that this wallet already has sufficient funds on zkSync - // ⚠️ Never commit private keys to file tracking history, or your account could be compromised. - const wallet = new Wallet(PRIVATE_KEY); - // The wallet that will receive ERC20 tokens - const emptyWallet = Wallet.createRandom(); - console.log(`Empty wallet's address: ${emptyWallet.address}`); - console.log(`Empty wallet's private key: ${emptyWallet.privateKey}`); - - const deployer = new Deployer(hre, wallet); - - // Deploying the ERC20 token - const erc20Artifact = await deployer.loadArtifact('MyERC20'); - const erc20 = await deployer.deploy(erc20Artifact, ['USDC', 'USDC', 18]); - console.log(`ERC20 address: ${erc20.address}`); - - // Deploying the paymaster - const paymasterArtifact = await deployer.loadArtifact('MyPaymaster'); - const paymaster = await deployer.deploy(paymasterArtifact, [erc20.address]); - console.log(`Paymaster address: ${paymaster.address}`); - - // Supplying paymaster with ETH. - await ( - await deployer.zkWallet.sendTransaction({ - to: paymaster.address, - value: ethers.utils.parseEther('0.05'), - }) - ).wait(); - - // Setting the dAPIs in Paymaster. Head over to the API3 Market (https://market.api3.org) to verify dAPI proxy contract addresses and whether they're funded or not. - const ETHUSDdAPI = '0x28ce555ee7a3daCdC305951974FcbA59F5BdF09b'; - const USDCUSDdAPI = '0x946E3232Cc18E812895A8e83CaE3d0caA241C2AB'; - const setProxy = paymaster.setDapiProxy(USDCUSDdAPI, ETHUSDdAPI); - await (await setProxy).wait(); - console.log('dAPI Proxies Set!'); - - // Deploying the Greeter contract - const greeterContractArtifact = await deployer.loadArtifact('Greeter'); - const oldGreeting = 'old greeting'; - const deployGreeter = await deployer.deploy(greeterContractArtifact, [oldGreeting]); - console.log(`Greeter contract address: ${deployGreeter.address}`); - - // Supplying the ERC20 tokens to the empty wallet: - await // We will give the empty wallet 5k mUSDC: - (await erc20.mint(emptyWallet.address, '5000000000000000000000')).wait(); - - console.log('Minted 5k mUSDC for the empty wallet'); - - console.log(`Done!`); -} -``` - -</details> - -The provided script deploys the `mockUSDC`, the `Greeter`, and the `Paymaster` contracts. After this, an empty wallet is -created, and 5,000 `mockUSDC` tokens are minted for the paymaster's use. The `Paymaster` contract also receives 0.05 ETH -to cover transaction fees. Additionally, the script calls the `setDapiProxy` method, assigning the necessary proxy -addresses for on-chain dAPIs, and sets the initial `greeting` value. - -Compile the contract: - -```bash -yarn hardhat compile -``` - -Once compiled, deploy using: - -```bash -yarn hardhat deploy-zksync --script deploy-mockUSDCPaymaster.ts -``` - -### Step 5 — Interact with contract - -To interact with contract update the `.env` file with the following items derived from the deployment script that ran -previously: - -``` -PRIVATE_KEY= -PAYMASTER_ADDRESS= -TOKEN_ADDRESS= -EMPTY_WALLET_PRIVATE_KEY= -GREETER_CONTRACT= -``` - -Create a new file under `/deploy`, for example `use-mockUSDCPaymaster.ts`. Insert the provided script: - -<details> - -<summary>use-mockUSDCPaymaster.ts</summary> - -```typescript -import { ContractFactory, Provider, utils, Wallet } from 'zksync-ethers'; -import * as ethers from 'ethers'; -import { HardhatRuntimeEnvironment } from 'hardhat/types'; -import { Deployer } from '@matterlabs/hardhat-zksync-deploy'; - -require('dotenv').config(); - -// Put the address of the deployed paymaster and the Greeter Contract in the .env file -const PAYMASTER_ADDRESS = process.env.PAYMASTER_ADDRESS || ''; -const GREETER_CONTRACT_ADDRESS = process.env.GREETER_CONTRACT || ''; - -// Put the address of the ERC20 token in the .env file: -const TOKEN_ADDRESS = process.env.TOKEN_ADDRESS || ''; - -function getToken(hre: HardhatRuntimeEnvironment, wallet: Wallet) { - const artifact = hre.artifacts.readArtifactSync('MyERC20'); - return new ethers.Contract(TOKEN_ADDRESS, artifact.abi, wallet); -} - -// Greeter contract -function getGreeter(hre: HardhatRuntimeEnvironment, wallet: Wallet) { - const artifact = hre.artifacts.readArtifactSync('Greeter'); - return new ethers.Contract(GREETER_CONTRACT_ADDRESS, artifact.abi, wallet); -} - -// Wallet private key -// ⚠️ Never commit private keys to file tracking history, or your account could be compromised. -const EMPTY_WALLET_PRIVATE_KEY = process.env.EMPTY_WALLET_PRIVATE_KEY || ''; -export default async function (hre: HardhatRuntimeEnvironment) { - const provider = new Provider('https://testnet.era.zksync.dev'); - const emptyWallet = new Wallet(EMPTY_WALLET_PRIVATE_KEY, provider); - - // Obviously this step is not required, but it is here purely to demonstrate that indeed the wallet has no ether. - const ethBalance = await emptyWallet.getBalance(); - if (!ethBalance.eq(0)) { - throw new Error('The wallet is not empty'); - } - - const erc20Balance = await emptyWallet.getBalance(TOKEN_ADDRESS); - console.log(`ERC20 balance of the user before tx: ${erc20Balance}`); - - const greeter = getGreeter(hre, emptyWallet); - const erc20 = getToken(hre, emptyWallet); - - const gasPrice = await provider.getGasPrice(); - - // Loading the Paymaster Contract - const deployer = new Deployer(hre, emptyWallet); - const paymasterArtifact = await deployer.loadArtifact('MyPaymaster'); - - const PaymasterFactory = new ContractFactory(paymasterArtifact.abi, paymasterArtifact.bytecode, deployer.zkWallet); - const PaymasterContract = PaymasterFactory.attach(PAYMASTER_ADDRESS); - - // Estimate gas fee for the transaction - const gasLimit = await greeter.estimateGas.setGreeting('new updated greeting', { - customData: { - gasPerPubdata: utils.DEFAULT_GAS_PER_PUBDATA_LIMIT, - paymasterParams: utils.getPaymasterParams(PAYMASTER_ADDRESS, { - type: 'ApprovalBased', - token: TOKEN_ADDRESS, - // Set a large allowance just for estimation - minimalAllowance: ethers.BigNumber.from(`100000000000000000000`), - // Empty bytes as testnet paymaster does not use innerInput - innerInput: new Uint8Array(), - }), - }, - }); - - // Gas estimation: - const fee = gasPrice.mul(gasLimit.toString()); - console.log(`Estimated ETH FEE (gasPrice * gasLimit): ${fee}`); - - // Calling the dAPI to get the ETH price: - const ETHUSD = await PaymasterContract.readDapi('0x28ce555ee7a3daCdC305951974FcbA59F5BdF09b'); - const USDCUSD = await PaymasterContract.readDapi('0x946E3232Cc18E812895A8e83CaE3d0caA241C2AB'); - - // Checks old allowance (for testing purposes): - const checkSetAllowance = await erc20.allowance(emptyWallet.address, PAYMASTER_ADDRESS); - console.log(`ERC20 allowance for paymaster : ${checkSetAllowance}`); - - console.log(`ETH/USD dAPI Value: ${ETHUSD}`); - console.log(`USDC/USD dAPI Value: ${USDCUSD}`); - - // Calculating the USD fee: - const usdFee = fee.mul(ETHUSD).div(USDCUSD); - console.log(`Estimated USD FEE: ${usdFee}`); - - console.log(`Current message is: ${await greeter.greet()}`); - - // Encoding the "ApprovalBased" paymaster flow's input - const paymasterParams = utils.getPaymasterParams(PAYMASTER_ADDRESS, { - type: 'ApprovalBased', - token: TOKEN_ADDRESS, - // set minimalAllowance to the estimated fee in erc20 - minimalAllowance: ethers.BigNumber.from(usdFee), - // empty bytes as testnet paymaster does not use innerInput - innerInput: new Uint8Array(), - }); - - await ( - await greeter.connect(emptyWallet).setGreeting(`new greeting updated at ${new Date().toUTCString()}`, { - // specify gas values - maxFeePerGas: gasPrice, - maxPriorityFeePerGas: 0, - gasLimit: gasLimit, - // paymaster info - customData: { - paymasterParams: paymasterParams, - gasPerPubdata: utils.DEFAULT_GAS_PER_PUBDATA_LIMIT, - }, - }) - ).wait(); - - const newErc20Balance = await emptyWallet.getBalance(TOKEN_ADDRESS); - - console.log(`ERC20 Balance of the user after tx: ${newErc20Balance}`); - console.log(`Transaction fee paid in ERC20 was ${erc20Balance.sub(newErc20Balance)}`); - console.log(`Message in contract now is: ${await greeter.greet()}`); -} -``` - -</details> - -Run the script: - -```bash -yarn hardhat deploy-zksync --script use-mockUSDCPaymaster.ts -``` - -The wallet had 5000 mUSDC after running the deployment script. After sending the transaction to update the `Greeting` -contract, we are now left with 4998.92 mUSDC. The script used mUSDC to cover the gas costs for the update transaction! diff --git a/content/20.build/tutorials/tooling-guides/dia.md b/content/20.build/tutorials/tooling-guides/dia.md deleted file mode 100644 index a1461230..00000000 --- a/content/20.build/tutorials/tooling-guides/dia.md +++ /dev/null @@ -1,249 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: DIA | zkSync Docs ---- - -# DIA - -In this guide, we'll create a simple contract that interacts with a DIA Oracle for decentralized price feeds on zkSync -Testnet. - -DIA’s data and oracle infrastructure provides dApps on zkSync Era’s ecosystem with access to price feeds of over -[3,000+ digital assets](https://app.diadata.org/price) and -[18,000+ NFT collections](https://app.diadata.org/floor-price). Additionally, DIA offers access to distributed and -verifiable [Random Number Generation — RNG](https://docs.diadata.org/products/randomness-oracle), Liquid Staked Tokens — -LSTs price feeds, as well as a range of lending rates, foreign exchange rates, and other data feeds. With this wide -range of data feeds, zkSync Era protocols can support a wider range of applications beyond just DeFi and NFTfi. - -For our purposes, we'll make use of their token price feeds to fetch live -[ETH/USD](https://market.api3.org/dapis/zksync-goerli-testnet/ETH-USD) rates. - -**Data Feed Addresses:** - -<table><thead><tr><th width="272">Contract</th><th width="212.33333333333331">Update Frequency</th><th>Network</th></tr></thead><tbody><tr><td><a href="https://explorer.zksync.io/address/0x8569B6695B25F9Ce9A0beDA29231eE6f2fDd3997">Price Feed</a> </td><td>2 hr</td><td>zkSync Era </td></tr><tr><td><a href="https://goerli.explorer.zksync.io/address/0x294838c2399950Ab91a74F9E35213aD417761FB5">Price Feed</a></td><td>1 hr</td><td>zkSync Testnet</td></tr></tbody></table> - -:::warning DIA demo oracles are not intended for use in production environments. Developers can request a dedicated, -production-ready oracle with custom price feeds and configuration settings. Start the request process: -[Request a Custom Oracle | DIA Documentation](https://docs.diadata.org/introduction/intro-to-dia-oracles/request-an-oracle). -::: - -### Prerequisites - -- **Knowledge Base**: Familiarity with deploying smart contracts. -- **Wallet Setup**: Have MetaMask installed and set up, ensuring there's a balance on the zkSync Testnet. -- **Tooling**: This guide utilizes [`zksync-cli`](../../tooling/zksync-cli/getting-started.md). Ensure you have it - accessible or installed in your environment. - -### Step 1 — Understanding the **DIAOracle contract** - -The DIAOracle contract is designed to retrieve and store the latest price information of a specified asset (e.g., -ETH/USD) using an external oracle. The contract has functions to fetch the price and its timestamp and to verify how -recent the fetched price is. - -**Key components:** - -- **ORACLE**: A constant (immutable) address pointing to the oracle service that the contract uses to get the price - information. This is set to - [`0x294838c2399950Ab91a74F9E35213aD417761FB5`](https://goerli.explorer.zksync.io/address/0x294838c2399950Ab91a74F9E35213aD417761FB5). -- **latestPrice**: A public state variable storing the latest fetched price of the asset. -- **timestampOflatestPrice**: A public state variable storing the timestamp when the latest price was updated. -- **getPriceInfo**: A function that fetches the latest price and the timestamp of the specified asset from the DIA - oracle. The fetched values are stored in the contract's state variables. - - **key**: A string specifying the asset (like "ETH/USD"). This parameter directs the oracle to fetch the price of the - specified asset. -- **checkPriceAge**: This is a view function, meaning it doesn't modify the contract's state. It checks whether the - saved price's timestamp is within an acceptable range. If the latest price was updated too long ago (based on a - specified threshold), the function returns `false`. - - **maxTimePassed**: This parameter defines the maximum acceptable duration since the last price update. If the latest - price was updated more recently than this duration, the function returns `true`; otherwise, it returns `false`. - -### Step 2 — Environment setup - -Using `zksync-cli` create a new project with the required dependencies and boilerplate paymaster implementations: - -`npx zksync-cli create DIAOracle` - -Choose `Hardhat + Solidity` to setup the project repository. - -**Update the Environment File**: - -- Modify the `.env-example` file with your private key. -- Ensure your account has a sufficient balance. - -### Step 3 - Implementing contracts - -Create a `DIAOracle.sol` contract in the `/contracts` directory. Populate the file with the provided code: - -```solidity -// SPDX-License-Identifier: UNLICENSED - -pragma solidity ^0.8.13; - -interface IDIAOracleV2{ - function getValue(string memory) external returns (uint128, uint128); -} - -/** -* @title A sample contract showing how DIA oracles can be used in contracts. -*/ -contract DIAOracle{ - address immutable ORACLE = 0x294838c2399950Ab91a74F9E35213aD417761FB5; - uint128 public latestPrice; - uint128 public timestampOflatestPrice; - - /** - * @dev A function that retrieves the price and the corresponding timestamp - * from the DIA oracle and saves them in storage variables. - * @param key - A string specifying the asset. - */ - function getPriceInfo(string memory key) external { - (latestPrice, timestampOflatestPrice) = IDIAOracleV2(ORACLE).getValue(key); - } - - /** - * @dev A function that checks if the timestamp of the saved price - * is older than maxTimePassed. - * @param maxTimePassed - The max acceptable amount of time passed since the - * oracle price was last updated. - * @return inTime - A bool hat will be true if the price was updated - * at most maxTimePassed seconds ago, otherwise false. - */ - function checkPriceAge(uint128 maxTimePassed) external view returns (bool inTime){ - if((block.timestamp - timestampOflatestPrice) < maxTimePassed){ - inTime = true; - } else { - inTime = false; - } - } -} -``` - -### Step 4 — Deploy the contract - -Create a new file under `/deploy`, for example `deploy-oracle.ts`. Insert the provided script: - -The deployment script - -```typescript -import { Wallet, utils } from 'zksync-ethers'; -import * as ethers from 'ethers'; -import { HardhatRuntimeEnvironment } from 'hardhat/types'; -import { Deployer } from '@matterlabs/hardhat-zksync-deploy'; - -// load env file -import dotenv from 'dotenv'; -dotenv.config(); - -// load wallet private key from env file -const PRIVATE_KEY = process.env.WALLET_PRIVATE_KEY || ''; - -if (!PRIVATE_KEY) throw '⛔️ Private key not detected! Add it to the .env file!'; - -// Deploy script for the DIAOracle contract -export default async function (hre: HardhatRuntimeEnvironment) { - console.log(`Running deploy script for the DIAOracle contract`); - - // Initialize the wallet. - const wallet = new Wallet(PRIVATE_KEY); - - // Create deployer object and load the artifact of the contract you want to deploy. - const deployer = new Deployer(hre, wallet); - const artifact = await deployer.loadArtifact('DIAOracle'); - - // Estimate contract deployment fee - const deploymentFee = await deployer.estimateDeployFee(artifact, []); - - // Deploy this contract. - const parsedFee = ethers.utils.formatEther(deploymentFee.toString()); - console.log(`The deployment is estimated to cost ${parsedFee} ETH`); - - const diaOracleContract = await deployer.deploy(artifact, []); - - // Show the contract info. - const contractAddress = diaOracleContract.address; - console.log(`${artifact.contractName} was deployed to ${contractAddress}`); -} -``` - -The provided script will deploy the `DIAOracle.sol` contract to zkSync Testnet. Ensure you have sufficient funds in the -deployer wallet. - -Compile the contract: - -```bash -yarn hardhat compile -``` - -Once compiled, deploy using: - -```bash -yarn hardhat deploy-zksync --script deploy-oracle.ts -``` - -### Step 5 — Interact with contract - -To interact with contract, create a new file under `/deploy`, for example `use-oracle.ts`. Insert the provided script: - -```typescript -import { Provider } from 'zksync-ethers'; -import * as ethers from 'ethers'; -import { HardhatRuntimeEnvironment } from 'hardhat/types'; - -// load env file -import dotenv from 'dotenv'; -dotenv.config(); - -import * as ContractArtifact from '../artifacts-zk/contracts/DIAOracle.sol/DIAOracle.json'; - -const PRIVATE_KEY = process.env.WALLET_PRIVATE_KEY || ''; - -if (!PRIVATE_KEY) throw '⛔️ Private key not detected! Add it to the .env file!'; - -const CONTRACT_ADDRESS = 'DEPLOYED-CONTRACT-ADDRESS '; - -if (!CONTRACT_ADDRESS) throw '⛔️ Contract address not provided'; - -export default async function (hre: HardhatRuntimeEnvironment) { - console.log(`Running script to interact with contract ${CONTRACT_ADDRESS}`); - - // Initialize the provider. - // @ts-ignore - const provider = new Provider(hre.userConfig.networks?.zkSyncTestnet?.url); - const signer = new ethers.Wallet(PRIVATE_KEY, provider); - - const contract = new ethers.Contract(CONTRACT_ADDRESS, ContractArtifact.abi, signer); - console.log(`The contract is ${contract.address}`); - // Fetch the price of ETH/USD - const tx = await contract.getPriceInfo('ETH/USD'); - await tx.wait(); - - // Fetch and log the latest price of ETH/USD - const rawPrice = await contract.latestPrice(); - console.log(`The price of ETH/USD is ${rawPrice}`); - - // Fetch and log the timestamp of the latest price - const timestamp = await contract.timestampOflatestPrice(); - const date = new Date(timestamp * 1000); - console.log(`The price of ETH/USD was last updated on ${date.toLocaleString()}`); -} -``` - -Update the script to provide the deployed contract address from the previous step: - -```typescript -const CONTRACT_ADDRESS = 'DEPLOYED-CONTRACT-ADDRESS '; -``` - -Run the script: - -```bash -yarn hardhat deploy-zksync --script use-oracle.ts -``` - -### Conclusion - -In this guide, we've effectively demonstrated how to make use of the DIA Oracle on zkSync Testnet. Using DIA’s extensive -data infrastructure, we set up a contract to access real-time decentralized price feeds that can be used in a variety of -use cases! diff --git a/content/20.build/tutorials/tooling-guides/layerzero.md b/content/20.build/tutorials/tooling-guides/layerzero.md deleted file mode 100644 index d650a9a1..00000000 --- a/content/20.build/tutorials/tooling-guides/layerzero.md +++ /dev/null @@ -1,129 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: LayerZero | zkSync Docs ---- - -# LayerZero - -### Introduction - -This guide aims to provide an insight into the LayerZero messaging service, which is an omnichain interoperability -protocol designed for lightweight message passing across chains, and how to Setup and utilize the OmniCounter contract -to demonstrate cross-chain message passing. Below is a table showcasing the zkSync Era and zkSync (Testnet) endpoint -details for LayerZero: - -<table><thead><tr><th width="176">Network</th><th width="91.33333333333331">ChainID</th><th>Endpoint</th></tr></thead><tbody><tr><td>zkSync Era</td><td>165</td><td>0x9b896c0e23220469C7AE69cb4BbAE391eAa4C8da</td></tr><tr><td>zkSync Testnet</td><td>10165</td><td>0x093D2CF57f764f09C3c2Ac58a42A2601B8C79281</td></tr></tbody></table> - -### Prerequisites - -- **Knowledge Base**: Familiarity with blockchain concepts and smart contract development. -- **Node.js**: If not installed, [download it here](https://nodejs.org/). - -### Step 1 — Understanding LayerZero messaging service - -LayerZero enables authentic and guaranteed message delivery between different blockchain networks with configurable -trustlessness. Messages in LayerZero are managed by LayerZero Endpoints, which comprise versioned messaging libraries -and a proxy to route messages to the appropriate library version. Message states are maintained across versions, -allowing for seamless library upgrades. - -Messages are sent from the User Application (UA) at source `srcUA` to the UA at the destination `dstUA`. Once the -message is received by `dstUA`, the message is considered delivered (transitioning from `INFLIGHT` to either `SUCCESS` -or `STORED`) - -More details can be found [here](https://layerzero.gitbook.io/docs/faq/messaging-properties). - -### Step 2 — Environment setup - -Clone the GitHub repository containing the OmniCounter contract, and navigate to the repository directory: - -```bash -git clone git@github.com:dutterbutter/zksync-layer0-example.git -``` - -Install dependencies: - -```bash -yarn install -``` - -**Update the Environment File**: - -- Modify the `.env-example` file with your private key. -- Ensure your account has a sufficient balance for both chains being interacted with. For this guide, that is zkSync - Testnet, and Optimism Testnet. - -### Step 3 — Understanding OmniCounter - -OmniCounter is a smart contract that increments a counter on another chain via LayerZero messaging service. - -It utilizes `_lzSend()` within `incrementCounter()` to send messages, and `_nonblockingLzReceive()` to receive messages -on the destination chain. - -### Step 4 — Deploy OmniCounter - -Deploy OmniCounter contract on at least two different chains. In this example, we'll use zkSync Testnet and Optimism -Testnet. - -We will start with deploying on zkSync Testnet: - -```bash -npx hardhat --network zksync-testnet deploy --tags OmniCounter -``` - -We should see the expected output: - -``` -[zksync-testnet] Endpoint address: 0x093D2CF57f764f09C3c2Ac58a42A2601B8C79281 -OmniCounter was deployed to 0x07C89fc22B959DbaE2bF3Bb5d0F1Ac94986588fd -``` - -**Note:** Copy the contract address somewhere safe, we will need it in the next step! - -Deploy on Optimism: - -```bash -npx hardhat --network optimism-goerli deploy --tags OmniCounter -``` - -### Step 5 — Configure and Send Cross-Chain Message - -Open `setTrustedRemote.js` located in the `/tasks` directory. Replace `"YOUR-ZKSYNC-DEPLOYED-OMNICOUNTER-ADDRESS"` with -the zkSync contract address. - -```javascript -const ZKSYNC_OMNICOUNTER = 'YOUR-ZKSYNC-DEPLOYED-OMNICOUNTER-ADDRESS'; -``` - -Set the remote addresses to allow each contract to receive messages: - -```bash -npx hardhat --network zksync-testnet setTrustedRemote --target-network optimism-goerli --contract OmniCounter -``` - -Execute: - -```bash -npx hardhat --network optimism-goerli setTrustedRemote --target-network zksync-testnet --contract OmniCounter -``` - -Time to send a cross-chain message from `optimism-goerli` to `zksync-testnet`: - -```bash -npx hardhat --network optimism-goerli incrementCounter --target-network zksync-testnet -``` - -Expected output: - -``` -fees[0] (wei): 1289224800000000 / (eth): 0.0012892248 -✅ Message Sent [optimism-goerli] incrementCounter on destination OmniCounter @ [10165] -tx: 0x6efca38d68bd11aae030c2b02d0dd8ae93eb32cba04152bb541309a909a0c894 -``` - -### Conclusion - -You have now set up and demonstrated cross-chain messaging using LayerZero with the OmniCounter contract. This -simplistic example serves as a gateway to understand and explore the potential of LayerZero messaging service in -building interoperable blockchain applications. diff --git a/content/20.build/tutorials/tooling-guides/redstone.md b/content/20.build/tutorials/tooling-guides/redstone.md deleted file mode 100644 index b7bb0703..00000000 --- a/content/20.build/tutorials/tooling-guides/redstone.md +++ /dev/null @@ -1,205 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Redstone | zkSync Docs ---- - -# Redstone - -### Introduction - -In this tutorial, we'll construct a stable price NFT marketplace on the zkSync network. Utilizing Hardhat for smart -contract compilation and testing, ethers.js for contract interaction, and React for the frontend, we'll create a -seamless NFT trading platform. A crucial component of our marketplace is the integration of RedStone Oracles to obtain -reliable price data. - -[RedStone](https://docs.redstone.finance/docs/introduction) is a data ecosystem that delivers frequently updated, -reliable and diverse data for your dApps and smart contracts. - -- Data providers can avoid the requirement of continuous on-chain data delivery -- Allow end users to self-deliver signed Oracle data on-chain -- Use the decentralized Streamr network to deliver signed oracle data to the end users -- Use token incentives to motivate data providers to maintain data integrity and uninterrupted service - -### Prerequisites - -- **Knowledge Base**: Familiarity with smart contracts, Hardhat, `ethers.js`, and React. -- **Environment Setup**: Have [Node.js](https://nodejs.org/) installed. -- **Tooling**: This guide utilizes [`hardhat`](https://hardhat.org/) and [`ethers.js`](https://docs.ethers.io/v5/). - -### Step 1 — Setting Up the Development Environment - -1\. Clone the Repository: - -```bash -git clone https://github.com/zkSync-Community-Hub/tutorials -``` - -2\. Navigate to the Project Directory: - -```bash -cd tutorials/tutorials/zkSync-RedStone-stable-price-marketplace-tutorial/code -``` - -3\. Install Dependencies: - -```bash -yarn install -``` - -4\. Setup Local zkSync Node: - -Set up a local zkSync node in a Dockerized setup following the instructions -[here](../../test-and-debug/dockerized-l1-l2-nodes.md). - -### Step 2 — Understanding the Contract Structure - -**ExampleNFT.sol** - -[`ExampleNFT`](https://github.com/zkSync-Community-Hub/tutorials/blob/d01c44af89bff8d8c322ae9d6ebc823a3111b447/tutorials/zkSync-RedStone-stable-price-marketplace-tutorial/code/contracts/ExampleNFT.sol#L2) -is a simplistic ERC721 contract with sequential token ID assignment, extending `ERC721Enumerable` from OpenZeppelin for -enhanced enumeration capability. - -```solidity -function mint() external { - _mint(msg.sender, nextTokenId); - nextTokenId++; -} -``` - -**Marketplace.sol** - -[`Marketplace`](https://github.com/zkSync-Community-Hub/tutorials/blob/d01c44af89bff8d8c322ae9d6ebc823a3111b447/tutorials/zkSync-RedStone-stable-price-marketplace-tutorial/code/contracts/Marketplace.sol#L6) -facilitates NFT trading with basic order placement, cancellation, and buying functionality, adhering to the -[EIP-721 standard](https://eips.ethereum.org/EIPS/eip-721). - -```solidity -function postSellOrder(address nftContractAddress, uint256 tokenId, uint256 price) external {} -function cancelOrder(uint256 orderId) external {} -function getAllOrders() public view returns (SellOrder[] memory) {} -function getPrice(uint256 orderId) public view returns (uint256) {} -function buy(uint256 orderId) external payable {} -``` - -**StableMarketplace.sol** - -[`StableMarketplace`](https://github.com/zkSync-Community-Hub/tutorials/blob/d01c44af89bff8d8c322ae9d6ebc823a3111b447/tutorials/zkSync-RedStone-stable-price-marketplace-tutorial/code/contracts/StableMarketplace.sol#L11) -enhances `Marketplace` with stable pricing, integrating RedStone Oracles for precise price data. - -### Step 3 — Modifying the StableMarketplace Contract - -The `StableMarketplace.sol` requires extension from `MainDemoConsumerBase` to interact with RedStone Oracles. Modify -`_getPriceFromOrder` to utilize `getOracleNumericValueFromTxMsg` for price data retrieval. - -```solidity -contract StableMarketplace is Marketplace, MainDemoConsumerBase { - function _getPriceFromOrder(SellOrder memory order) internal view override returns (uint256) { - uint256 ethPrice = getOracleNumericValueFromTxMsg(bytes32("ETH")); - return (order.price / ethPrice) * (10 ** 8); - } -} -``` - -### Step 4 — Adjusting dApp TypeScript Code - -In -[`blockchain.ts`](https://github.com/zkSync-Community-Hub/tutorials/blob/d01c44af89bff8d8c322ae9d6ebc823a3111b447/tutorials/zkSync-RedStone-stable-price-marketplace-tutorial/code/src/core/blockchain.ts#L121), -implement the `buy` function, wrapping the marketplace contract with RedStone's framework to facilitate `buy` operations -with precise pricing. - -```javascript -import { WrapperBuilder } from "@redstone-finance/evm-connector"; - -async function buy(orderId: string) { - const marketplace = await getContractInstance("marketplace"); - - // Wrapping marketplace contract instance. - // It enables fetching data from redstone data pool - // for each contract function call - try { - const wrappedMarketplaceContract = WrapperBuilder.wrap(marketplace).usingDataService({ - dataServiceId: "redstone-main-demo", - uniqueSignersCount: 1, - dataFeeds: ["ETH"], - }); - - // Checking expected amount - const expectedEthAmount = await wrappedMarketplaceContract.getPrice(orderId); - - // Sending buy tx - const buyTx = await wrappedMarketplaceContract.buy(orderId, { - value: expectedEthAmount.mul(101).div(100), // a buffer for price movements - }); - await buyTx.wait(); - - return buyTx; - } catch { - const errText = "Error happened while buying the NFT"; - alert(errText); - } -} -``` - -### Step 5 — Testing and Launching Locally - -Ensure the RedStone Oracle integration is correct by running tests, compiling contracts, deploying them locally, and -launching the React app. - -```bash -yarn test -yarn compile -# Rename and update .env file -mv .env.example .env -# Update WALLET_PRIVATE_KEY in .env -echo "WALLET_PRIVATE_KEY=0x7726827caac94a7f9e1b160f7ea819f172f7b6f9d2a97f992c38edeab82d4110" >> .env -yarn deploy:local -yarn app:start -``` - -Visit [http://localhost:3000](http://localhost:3000) to interact with your local NFT stable price marketplace. - -#### Step 5.1 — Local Marketplace Interaction - -**Import Local Wallets to MetaMask** - -1. In MetaMask, select the account dropdown, then `Import account`. -2. Input the private keys for `User 1` and `User 2` respectively: - - `User 1`: `0xac1e735be8536c6534bb4f17f06f6afc73b2b5ba84ac2cfb12f7461b20c0bbe3` - - `User 2`: `0xd293c684d884d56f8d6abd64fc76757d3664904e309a0645baf8522ab6366d9e` -3. Click `Import`. - -**Explore App** - -Navigate to the app at [http://localhost:3000](http://localhost:3000). Initially, you'll see a near-empty interface with -a `+ Mint new NFT` link. - -![Stable marketplace](../../../assets/images/redstone-stable-marketplace-app.png) - -**Mint NFTs** - -1. Click `+ Mint new NFT` to create new NFTs. -2. Post-minting, view your NFT in the left column. - -![My NFT's](../../../assets/images/redstone-my-nfts.png) - -**Post Sell Orders** - -1. Click `SELL` on any NFT, enter the USD value, and confirm the two prompted transactions for NFT transfer approval and - marketplace order creation. - -![Sell NFT's](../../../assets/images/redstone-orders.png) - -**Buy NFTs** - -1. Switch MetaMask accounts to buy an NFT. -2. Optionally, open browser's developer tools on the network tab to observe network requests, including the two requests - for ETH price data and crypto signatures before the buy transaction. - -![Buy NFT's](../../../assets/images/redstone-requests.png) - -### Conclusion - -You've successfully built and launched a stable price NFT marketplace on zkSync, integrating RedStone Oracles for -reliable price data. This marketplace provides a platform for NFT trading with stable pricing, showcasing the potential -of combining zkSync's scalability with RedStone's accurate price oracles. diff --git a/content/20.build/tutorials/tooling-guides/subquery.md b/content/20.build/tutorials/tooling-guides/subquery.md deleted file mode 100644 index aa649013..00000000 --- a/content/20.build/tutorials/tooling-guides/subquery.md +++ /dev/null @@ -1,257 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: SubQuery | zkSync Docs ---- - -# SubQuery - -### Introduction - -This guide outlines the process of indexing all transfers and approval events from the Wrapped ETH on zkSync Era -Network. - -[The SubQuery Network](https://academy.subquery.network/) indexes and services data to the global community in an -incentivized and verifiable way. After publishing your project to the SubQuery Network, anyone can index and host it — -providing data to users around the world faster and reliably. - -### Prerequisites - -- **Node.js**: If not installed, [download it here](https://nodejs.org/). -- **Docker**: If not installed, [download it here](https://www.docker.com/get-started). -- **Tooling**: This guide utilizes `@subql/cli`. Ensure you have it accessible or installed in your environment. - -### Step 1 — Understanding SubQuery - -A SubQuery extracts data from a blockchain, processing it and storing it so that it can be easily queried via GraphQL. -Make advanced, flexible, but simple queries over GraphQL from any website or app. SubQuery supports advanced features -like aggregate functions and subscriptions. dApps often need to fetch data from chain. Instead of querying the chain -directly, which can be slow and expensive, dApps can use SubQuery to quickly retrieve the data they need. - -**Key components:** - -- **project.yaml**: a YAML file containing the subgraph manifest. -- **schema.graphql**: a GraphQL schema that defines what data is stored for your subgraph, and how to query it via - GraphQL. -- **Mappings**: Translates from the event data to the entities defined in your schema. - -### Step 2 — Environment setup - -Install the SubQuery CLI using NPM (avoid using `yarn global` due to dependency issues): - -```bash -npm install -g @subql/cli -subql --help # Verify installation -``` - -Run `subql init` in the desired directory, follow the prompts to set up your project: - -```bash -subql init -# Follow the interactive prompts -``` - -After initialization, navigate to your project directory and install dependencies: - -```bash -cd PROJECT_NAME -yarn install -``` - -### Step 3 — Configure Your Project Manifest File - -The `project.yaml` file serves as the entry point to your zkSync project, defining how SubQuery will index and transform -the chain data. For zkSync Era, three types of mapping handlers are available: - -- `BlockHandlers`: Executes a mapping function on every block. -- `TransactionHandlers`: Executes a mapping function on each transaction matching optional filter criteria. -- `LogHandlers`: Executes a mapping function on each log matching optional filter criteria. - -Start by: - -Import the contract ABI definition from any standard -[ERC-20 contract](https://ethereum.org/en/developers/docs/standards/tokens/erc-20/), save it as `erc20.abi.json` in the -`/abis` directory. - -Update the `dataSources` section in `project.yaml` as shown below: - -```yaml -dataSources: - - kind: ethereum/Runtime # We use ethereum runtime since Zksync is a layer-2 that is compatible - startBlock: 10456259 # This is the block that the contract was deployed on - options: - # Must be a key of assets - abi: erc20 - address: '0x3355df6D4c9C3035724Fd0e3914dE96A5a83aaf4' # This is the contract address for wrapped ether https://explorer.zksync.io/address/0x3355df6D4c9C3035724Fd0e3914dE96A5a83aaf4 - assets: - erc20: - file: './abis/erc20.abi.json' - mapping: - file: './dist/index.js' - handlers: - - handler: handleTransaction - kind: ethereum/TransactionHandler # We use ethereum handlers since Zksync is a layer-2 that is compatible - filter: - ## The function can either be the function fragment or signature - # function: '0x095ea7b3' - # function: '0x7ff36ab500000000000000000000000000000000000000000000000000000000' - function: approve(address to, uint256 value) - - handler: handleLog - kind: ethereum/LogHandler # We use ethereum handlers since Zksync is a layer-2 that is compatible - filter: - topics: - ## Follows standard log filters https://docs.ethers.io/v5/concepts/events/ - - Transfer(address indexed from, address indexed to, uint256 amount) - # address: "0x60781C2586D68229fde47564546784ab3fACA982" -``` - -### Step 4 — Update Your GraphQL Schema File - -Remove existing entities and update `schema.graphql` file to index block information, transfers, and approvals as shown -below: - -```graphql -type Transfer @entity { - id: ID! - blockHeight: BigInt - to: String! - from: String! - value: BigInt! - contractAddress: String! -} - -type Approval @entity { - id: ID! - blockHeight: BigInt - owner: String! - spender: String! - value: BigInt! - contractAddress: String! -} -``` - -Generate entity classes and ABI types: - -::: code-tabs - -@tab:active yarn - -```bash -yarn codegen -``` - -@tab npm - -```bash -npm run-script codegen -``` - -::: - -Import the generated types in your project: - -```javascript -import { Approval, Transfer } from '../types'; -import { ApproveTransaction, TransferLog } from '../types/abi-interfaces/Erc20Abi'; -``` - -### Step 5 — Add Mapping Functions - -Navigate to `src/mappings` directory, you'll find `handleLog` and `handleTransaction` functions. - -Update the functions to process and store the desired data as shown below: - -```typescript -export async function handleLog(log: TransferLog): Promise<void> { - logger.info(`New transfer transaction log at block ${log.blockNumber}`); - assert(log.args, 'No log.args'); - - const transaction = Transfer.create({ - id: log.transactionHash, - blockHeight: BigInt(log.blockNumber), - to: log.args.to, - from: log.args.from, - value: log.args.value.toBigInt(), - contractAddress: log.address, - }); - - await transaction.save(); -} - -export async function handleTransaction(tx: ApproveTransaction): Promise<void> { - logger.info(`New Approval transaction at block ${tx.blockNumber}`); - assert(tx.args, 'No tx.args'); - - const approval = Approval.create({ - id: tx.hash, - owner: tx.from, - spender: await tx.args[0], - value: BigInt(await tx.args[1].toString()), - contractAddress: tx.to, - }); - - await approval.save(); -} -``` - -These functions process transaction and log data, extracting necessary information to save in the database. Ensure to -check the Mappings documentation for more insights. - -### Step 6 — Build, Run, and Query Your Project - -Build your project: - -```bash -yarn build -``` - -Run your project locally with Docker: - -```bash -yarn start:docker -``` - -Open your browser and head to `http://localhost:3000`. Explore the GraphQL playground and use the Docs tab to understand -the available queries. - -Try the following query to understand how it works for your new SubQuery starter project: - -```graphql -{ - query { - transfers(first: 5, orderBy: VALUE_DESC) { - totalCount - nodes { - id - blockHeight - from - to - value - contractAddress - } - } - } - approvals(first: 5, orderBy: BLOCK_HEIGHT_DESC) { - nodes { - id - blockHeight - owner - spender - value - contractAddress - } - } -} -``` - -You should now see the results displayed below in the GraphQL playground, and you're ready to continue developing your -SubQuery project. - -### Conclusion - -Congratulations! You have successfully set up a SubQuery project running locally, ready to handle GraphQL API requests -pertaining to data transfers. - -To ensure your SubQuery project operates efficiently and to sidestep common pitfalls, delve into the -[Project Optimization](https://academy.subquery.network/build/optimisation.html) section. Happy querying! diff --git a/content/20.build/tutorials/tooling-guides/the-graph.md b/content/20.build/tutorials/tooling-guides/the-graph.md deleted file mode 100644 index 3a3cc223..00000000 --- a/content/20.build/tutorials/tooling-guides/the-graph.md +++ /dev/null @@ -1,648 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: The Graph | zkSync Docs ---- - -# The Graph - -### Introduction - -In this guide, you will learn how to deploy a subgraph that tracks a specific address on zkSync Era mainnet. Deploying -graphs is a great way to query data from network historically and in real-time. - -[The Graph](https://thegraph.com/) is a decentralized protocol for indexing and querying data from blockchains. The -Graph serves queries over data that is easily stored, decentralized, and secured by the blockchain. You will learn how -to deploy a subgraph that tracks a specific address on zkSync Era mainnet. - -### Prerequisites - -- **Knowledge Base**: Familiarity with Typescript. -- **Wallet Setup**: Have MetaMask installed and Setup, ensuring there's a balance on the zkSync Testnet. -- **Tooling**: This guide utilizes `@graphprotocol/graph-cli`. Ensure you have it accessible or installed in your - environment. - -### Step 1 — Understanding subgraphs - -A subgraph extracts data from a blockchain, processing it and storing it so that it can be easily queried via GraphQL. -DApps often need to fetch data from chain. Instead of querying the chain directly, which can be slow and expensive, -DApps can use subgraphs to quickly retrieve the data they need. - -**Key components:** - -- **subgraph.yaml**: a YAML file containing the subgraph manifest. -- **schema.graphql**: a GraphQL schema that defines what data is stored for your subgraph, and how to query it via - GraphQL. -- **AssemblyScript Mappings**: [AssemblyScript](https://github.com/AssemblyScript/assemblyscript) code that translates - from the event data to the entities defined in your schema. - -### Step 2 — Environment setup - -Visit [https://thegraph.com/studio/](https://thegraph.com/studio/), connect your wallet. Next, click the button to -create a new subgraph: - -![create-new-subgraph-zksync](../../../assets/images/Screenshot-2023-09-25-4.34.png) - -- [Create subgraph](https://thegraph.com/studio) - -Enter the name of the subgraph, and select the zkSync Era as the network: - -![Install graphcli](../../../assets/images/Screenshot-2023-09-25-4.35.png) - -Install the [@graphprotocol/graph-cli](https://www.npmjs.com/package/@graphprotocol/graph-cli): - -::: code-tabs - -@tab:active yarn - -```bash -yarn add @graphprotocol/graph-cli -``` - -@tab npm - -```bash -npm install @graphprotocol/graph-cli -``` - -::: - -### Step 3 — Generate subgraph - -To generate a subgraph using the `graph-cli` , we first need to be able to provide an ABI file for the CLI to reference. -This will be addressed in future explorer updates. Create a `pepe_abi.json` file and insert the provided json: - -```json -[ - { - "inputs": [], - "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": "_account", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "_amount", - "type": "uint256" - } - ], - "name": "BridgeBurn", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "l1Token", - "type": "address" - }, - { - "indexed": false, - "internalType": "string", - "name": "name", - "type": "string" - }, - { - "indexed": false, - "internalType": "string", - "name": "symbol", - "type": "string" - }, - { - "indexed": false, - "internalType": "uint8", - "name": "decimals", - "type": "uint8" - } - ], - "name": "BridgeInitialization", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "_account", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "_amount", - "type": "uint256" - } - ], - "name": "BridgeMint", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint8", - "name": "version", - "type": "uint8" - } - ], - "name": "Initialized", - "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": [ - { - "internalType": "address", - "name": "_from", - "type": "address" - }, - { - "internalType": "uint256", - "name": "_amount", - "type": "uint256" - } - ], - "name": "bridgeBurn", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_l1Address", - "type": "address" - }, - { - "internalType": "bytes", - "name": "_data", - "type": "bytes" - } - ], - "name": "bridgeInitialize", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "_amount", - "type": "uint256" - } - ], - "name": "bridgeMint", - "outputs": [], - "stateMutability": "nonpayable", - "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": [], - "name": "l1Address", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "l2Bridge", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "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" - } -] -``` - -We will refer to this file path during setup. Execute the command: - -::: code-tabs - -@tab:active yarn - -```bash -yarn graph init --studio zksync-subgraph-example -``` - -@tab npm - -```bash -npm graph init --studio zksync-subgraph-example -``` - -::: - -Begin initializing the project with the following item options: - -- Select `Ethereum` as the protocol -- Select `zksync-era` as the Ethereum network -- Provide the contract address you wish to track, for this tutorial, the PEPE token: - `0xFD282F16a64c6D304aC05d1A58Da15bed0467c71` -- Provide an ABI file path, in this case the `pepe_abi.json` file created previously. -- Provide a block number to start indexing from (e.g. 13761747) -- Provide a contract name (e.g. PEPE) -- Indicate `true` to indexing events as entities -- Approve the next steps and skip adding another contract - -![Example output from The Graph cli](../../../assets/images/Screenshot-2023-09-25-4.57.45.png) - -### Step 4 — Authenticate and Deploy the Subgraph - -In order to authenticate and deploy the generated subgraph, copy the deploy key studio account: - -![Copy deploy key from The Graph studio](../../../assets/images/deploy.png) Copy deploy key from The Graph studio - -Run auth command: - -::: code-tabs - -@tab:active yarn - -```bash -yarn graph auth --studio <DEPLOY-KEY> -``` - -@tab npm - -```bash -npm graph auth --studio <DEPLOY-KEY> -``` - -::: - -Change directory to the subgraph: - -```bash -cd zksync-subgraph-example -``` - -Deploy the subgraph: - -::: code-tabs - -@tab:active yarn - -```bash -yarn graph deploy zksync-subgraph-example -``` - -@tab npm - -```bash -npm graph deploy --studio zksync-subgraph-example -``` - -::: - -:::warning Please, make sure that local folder name matches name of the subgraph studio ::: - -### Step 5 — Query the Subgraph - -Visit the [studio](https://thegraph.com/studio/), select the **Playground** tab, and run the pre-loaded query: - -Running a query on our subgraph ![Running a query on our subgraph](../../../assets/images/query.png) - -To write a custom query, for example, to query the `approvals` table for a specific `owner` address: - -```graphql -{ - approvals(where: { owner: "0x7c5a0ce9267ed19b22f8cae653f198e3e8daf098" }) { - id - owner - spender - value - } -} -``` - -Query the `bridgeBurns` table for a specific `account` address: - -```graphql -{ - bridgeBurns(where: { _account: "0x7c5a0ce9267ed19b22f8cae653f198e3e8daf098" }) { - id - _account - _amount - blockNumber - } -} -``` - -Query the `bridgeMints` table for a specific `account` address: - -```graphql -{ - bridgeMints(where: { _account: "0x7c5a0ce9267ed19b22f8cae653f198e3e8daf098" }) { - id - _account - _amount - blockNumber - } -} -``` - -### Conclusion - -In this tutorial, you learned how to deploy a subgraph that tracks a specific address on zkSync Era. Build a frontend -application that interacts with the subgraph and is reliant on data from zkSync Era! diff --git a/content/20.build/tutorials/tooling-guides/viem.md b/content/20.build/tutorials/tooling-guides/viem.md deleted file mode 100644 index 984aae64..00000000 --- a/content/20.build/tutorials/tooling-guides/viem.md +++ /dev/null @@ -1,200 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Viem | zkSync Docs ---- - -# viem - -[viem](https://viem.sh/) is a TypeScript interface for Ethereum that now includes support for zkSync, offering low-level -stateless primitives for interacting with both Ethereum and zkSync. You can use viem to interact seamlessly with smart -contracts deployed on zkSync. For more information on zkSync specific support please refer to viem documentation -[here](https://viem.sh/docs/chains/zksync). - -You can use viem to interact with smart contracts deployed on zkSync. - -## Installation - -Start by adding Viem to your project. Open your terminal and execute the following command: - -```bash -npm install --save viem -``` - -This command installs the latest version of Viem and adds it to your project's dependencies. - -## Initial Setup - -### Client Configuration - -Before using viem, you need to setup a [Client](https://viem.sh/docs/clients/intro.html) with a chosen -[Transport](https://viem.sh/docs/clients/intro.html) and [Chain](https://viem.sh/docs/clients/chains.html). - -#### Example - -```javascript -import { createPublicClient, http } from 'viem'; -import { zkSyncSepoliaTestnet } from 'viem/chains'; - -// Initialize the Viem client -const client = createPublicClient({ - chain: zkSyncSepoliaTestnet, // Specify the zkSync network - transport: http(), // Define the transport method -}); -``` - -:::info - -- To use the zkSync Sepolia testnet, specify `zkSyncSepoliaTestnet` as the chain. -- For zkSync mainnet, replace `zkSyncSepoliaTestnet` with `zkSync`. - -::: - -### Reading Data - -Access zkSync data by invoking Public Actions that mirror Ethereum RPC methods. - -#### Fetch the Latest Block Number - -```javascript -const blockNumber = await client.getBlockNumber(); -console.log(`Current block number: ${blockNumber}`); -``` - -### Writing Data - -To write data, such as sending transactions, you need to set up a Wallet client. - -#### Sending Transactions - -```javascript -import { createWalletClient, custom } from 'viem'; -import { zkSyncSepoliaTestnet } from 'viem/chains'; - -// Request account access from the Ethereum provider -const [account] = await window.ethereum.request({ method: 'eth_requestAccounts' }); - -// Configure the wallet client -const client = createWalletClient({ - account, - chain: zkSyncSepoliaTestnet, - transport: custom(window.ethereum), -}); - -// Example transaction -client.sendTransaction({ - /* transaction details */ -}); -``` - -## Advanced Usage - -### Utilizing Paymasters - -[Paymasters](https://docs.zksync.io/build/developer-reference/account-abstraction.html#paymasters) cover transaction -fees, facilitating a smoother user experience. To utilize zkSync's native account abstraction and Paymasters, extend the -Wallet client with `eip712WalletActions`: - -#### Setup - -```javascript -import 'viem/window'; -import { createWalletClient, custom } from 'viem'; -import { zkSync } from 'viem/chains'; -import { eip712WalletActions } from 'viem/zksync'; - -// Initialize and extend the wallet client -const walletClient = createWalletClient({ - chain: zkSync, - transport: custom(window.ethereum!), -}).extend(eip712WalletActions()); -``` - -#### Sending a Transaction with a Paymaster - -```javascript -import { utils } from 'zksync-ethers'; - -const paymasterAddress = '<DEPLOYED_PAYMASTER_ADDRESS>'; // Replace with your paymaster address -const params = utils.getPaymasterParams(paymasterAddress, { - type: 'General', - innerInput: new Uint8Array(), -}); - -// Send the transaction example -const hash = await walletClient.sendTransaction({ - account: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e', - to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8', - value: 1000000000000000000n, - paymaster: paymasterAddress, - paymasterInput: params.paymasterInput, -}); -``` - -:::info - -**Note:** Ensure your paymaster contract is set up and funded appropriately. - -::: - -For a live example, check out this [StackBlitz demo](https://stackblitz.com/edit/github-zfdhx8-ju8urb?file=index.tsx). -Remember to replace `PAYMASTER_CONTRACT_ADDRESS` with your own! - -### Contract Interactions with Paymasters - -#### Contract Function Call - -```javascript -import { utils } from 'zksync-ethers'; - -const paymasterAddress = '<DEPLOYED_PAYMASTER_ADDRESS>'; // Replace with actual address - -// Set up paymaster parameters -const params = utils.getPaymasterParams(paymasterAddress, { - type: 'General', - innerInput: new Uint8Array(), -}); - -// Call the contract function -const hash = await walletClient.writeContract({ - address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2', - abi: parseAbi(['function setGreeting(string _greeting) nonpayable']), - functionName: 'setGreeting', - args: ['zkSync!'], - paymaster: paymasterAddress, - paymasterInput: params.paymasterInput, -}); -``` - -:::info - -**Note:** Ensure your paymaster contract is set up and funded appropriately. - -::: - -For a live example, check out this [StackBlitz demo](https://stackblitz.com/edit/github-aa4rfx?file=index.tsx). Remember -to replace `PAYMASTER_CONTRACT_ADDRESS` with your own! - -### Smart Contract Interactions - -Interact with smart contracts by creating a Contract instance, providing ABI, address, and the client. - -#### Example - -```javascript -import { getContract } from 'viem'; -import { yourContractAbi } from './abi'; // Your contract's ABI -import { client } from './client'; // Your initialized Viem client - -// Initialize the contract instance -const contract = getContract({ - address: 'YOUR_CONTRACT_ADDRESS', // Replace with your contract's address - abi: yourContractAbi, - client, -}); - -// Interact with your contract -const result = await contract.read.totalSupply(); -console.log(`Total Supply: ${result}`); -``` diff --git a/content/20.build/tutorials/tooling-guides/wagmi.md b/content/20.build/tutorials/tooling-guides/wagmi.md deleted file mode 100644 index 435e62f3..00000000 --- a/content/20.build/tutorials/tooling-guides/wagmi.md +++ /dev/null @@ -1,519 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Wagmi | zkSync Docs ---- - -# Wagmi - -The `@wagmi/core` library provides a comprehensive VanillaJS toolkit for interacting with zkSync Era. It simplifies -wallet connections, balance retrieval, message signing, and contract interactions. For setup instructions, consult the -official documentation [here](https://wagmi.sh/core/getting-started). - -:::info Wagmi hooks do not yet support Paymasters and native Account Abstraction; development is in progress. ::: - -Here are some common actions: - -### Connect Wallet - -```typescript -import { w3mConnectors, w3mProvider } from '@web3modal/ethereum'; -import { configureChains, createConfig } from 'wagmi'; -import { zkSync, zkSyncTestnet } from 'wagmi/chains'; - -export const walletConnectProjectId = 'd4a7167a6eed6a53c8364631aaeca861'; - -const { chains, publicClient, webSocketPublicClient } = configureChains( - [zkSync, ...(import.meta.env?.MODE === 'development' ? [zkSyncTestnet] : [])], - [w3mProvider({ projectId: walletConnectProjectId })] -); - -export const config = createConfig({ - autoConnect: true, - connectors: w3mConnectors({ - chains, - projectId: walletConnectProjectId, - version: 2, - }), - publicClient, - webSocketPublicClient, -}); - -export { chains }; -``` - -### Display Wallet Options - -```typescript -import { useConnect } from "wagmi"; - -export function WalletOptions() { - const { connect, connectors, error, isLoading, pendingConnector } = useConnect(); - console.log(connectors); - - return ( - <div> - {connectors.map((connector) => ( - <button disabled={!connector.ready} key={connector.id} onClick={() => connect({ connector })}> - {connector.name} - {!connector.ready && " (unsupported)"} - {isLoading && connector.id === pendingConnector?.id && " (connecting)"} - </button> - ))} - - {error && <div>{error.message}</div>} - </div> - ); -} -``` - -### Fetch Account - -```typescript -import { useAccount } from "wagmi"; - -export function Account() { - const { address } = useAccount(); - - return <div>{address}</div>; -} -``` - -### Fetch Balance - -```typescript -import { useState } from "react"; -import type { Address } from "wagmi"; -import { useAccount, useBalance } from "wagmi"; - -export function Balance() { - return ( - <> - <div> - <AccountBalance /> - </div> - <br /> - <div> - <FindBalance /> - </div> - </> - ); -} - -export function AccountBalance() { - const { address } = useAccount(); - const { data, refetch } = useBalance({ - address, - watch: true, - }); - - return ( - <div> - {data?.formatted} - <button onClick={() => refetch()}>refetch</button> - </div> - ); -} - -export function FindBalance() { - const [address, setAddress] = useState(""); - const { data, isLoading, refetch } = useBalance({ - address: address as Address, - }); - - const [value, setValue] = useState(""); - - return ( - <div> - Find balance: <input onChange={(e) => setValue(e.target.value)} placeholder="wallet address" value={value} /> - <button onClick={() => (value === address ? refetch() : setAddress(value))}>{isLoading ? "fetching..." : "fetch"}</button> - <div>{data?.formatted}</div> - </div> - ); -} -``` - -### Fetch Block Number - -```typescript -import { useBlockNumber } from "wagmi"; - -export function BlockNumber() { - const { data } = useBlockNumber({ watch: true }); - return <div>{data?.toString()}</div>; -} -``` - -### Send Transaction - -```typescript -import { parseEther } from "viem"; -import { useSendTransaction, useWaitForTransaction } from "wagmi"; - -import { stringify } from "../utils/stringify"; - -export function SendTransaction() { - const { data, error, isLoading, isError, sendTransaction } = useSendTransaction(); - const { data: receipt, isLoading: isPending, isSuccess } = useWaitForTransaction({ hash: data?.hash }); - - return ( - <> - <form - onSubmit={(e) => { - e.preventDefault(); - const formData = new FormData(e.target as HTMLFormElement); - const address = formData.get("address") as string; - const value = formData.get("value") as `${number}`; - sendTransaction({ - to: address, - value: parseEther(value), - }); - }} - > - <input name="address" placeholder="address" /> - <input name="value" placeholder="value (ether)" /> - <button type="submit">Send</button> - </form> - - {isLoading && <div>Check wallet...</div>} - {isPending && <div>Transaction pending...</div>} - {isSuccess && ( - <> - <div>Transaction Hash: {data?.hash}</div> - <div> - Transaction Receipt: <pre>{stringify(receipt, null, 2)}</pre> - </div> - </> - )} - {isError && <div>Error: {error?.message}</div>} - </> - ); -} -``` - -### Send Transaction (Prepared) - -```typescript -import { useState } from "react"; -import { parseEther, stringify } from "viem"; -import { usePrepareSendTransaction, useSendTransaction, useWaitForTransaction } from "wagmi"; - -import { useDebounce } from "../hooks/useDebounce"; - -export function SendTransactionPrepared() { - const [to, setTo] = useState(""); - const debouncedTo = useDebounce(to); - - const [value, setValue] = useState(""); - const debouncedValue = useDebounce(value); - - const { config } = usePrepareSendTransaction({ - to: debouncedTo, - value: debouncedValue ? parseEther(value as `${number}`) : undefined, - enabled: Boolean(debouncedTo && debouncedValue), - }); - const { data, error, isLoading, isError, sendTransaction } = useSendTransaction(config); - const { data: receipt, isLoading: isPending, isSuccess } = useWaitForTransaction({ hash: data?.hash }); - - return ( - <> - <form - onSubmit={(e) => { - e.preventDefault(); - sendTransaction?.(); - }} - > - <input placeholder="address" onChange={(e) => setTo(e.target.value)} value={to} /> - <input id="value" placeholder="value (ether)" onChange={(e) => setValue(e.target.value)} value={value} /> - <button disabled={!sendTransaction} type="submit"> - Send - </button> - </form> - - {isLoading && <div>Check wallet...</div>} - {isPending && <div>Transaction pending...</div>} - {isSuccess && ( - <> - <div>Transaction Hash: {data?.hash}</div> - <div> - Transaction Receipt: <pre>{stringify(receipt, null, 2)}</pre> - </div> - </> - )} - {isError && <div>Error: {error?.message}</div>} - </> - ); -} -``` - -### Sign Message - -```typescript -import { useEffect, useState } from "react"; -import { recoverMessageAddress } from "viem"; -import { type Address, useSignMessage } from "wagmi"; - -export function SignMessage() { - const [recoveredAddress, setRecoveredAddress] = useState<Address>(); - const { data: signature, variables, error, isLoading, signMessage } = useSignMessage(); - - useEffect(() => { - (async () => { - if (variables?.message && signature) { - const recoveredAddress = await recoverMessageAddress({ - message: variables?.message, - signature, - }); - setRecoveredAddress(recoveredAddress); - } - })(); - }, [signature, variables?.message]); - - return ( - <> - <form - onSubmit={(event) => { - event.preventDefault(); - const element = event.target as HTMLFormElement; - const formData = new FormData(element); - const message = formData.get("message") as string; - signMessage({ message }); - }} - > - <input name="message" type="text" required /> - <button disabled={isLoading} type="submit"> - {isLoading ? "Check Wallet" : "Sign Message"} - </button> - </form> - - {signature && ( - <div> - <div>Signature: {signature}</div> - <div>Recovered address: {recoveredAddress}</div> - </div> - )} - {error && <div>Error: {error?.message}</div>} - </> - ); -} -``` - -### Sign Typed Data - -```typescript -import { useEffect, useState } from "react"; -import { recoverTypedDataAddress } from "viem"; -import { type Address, useSignTypedData } from "wagmi"; - -const domain = { - name: "Ether Mail", - version: "1", - chainId: 280 || 324, - verifyingContract: "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC", -} as const; - -const types = { - Person: [ - { name: "name", type: "string" }, - { name: "wallet", type: "address" }, - ], - Mail: [ - { name: "from", type: "Person" }, - { name: "to", type: "Person" }, - { name: "contents", type: "string" }, - ], -} as const; - -const message = { - from: { - name: "Cow", - wallet: "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826", - }, - to: { - name: "Bob", - wallet: "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB", - }, - contents: "Hello, Bob!", -} as const; - -export function SignTypedData() { - const { data, error, isLoading, signTypedData } = useSignTypedData({ - domain, - types, - message, - primaryType: "Mail", - }); - - const [recoveredAddress, setRecoveredAddress] = useState<Address>(); - useEffect(() => { - if (!data) return; - (async () => { - setRecoveredAddress( - await recoverTypedDataAddress({ - domain, - types, - message, - primaryType: "Mail", - signature: data, - }) - ); - })(); - }, [data]); - - return ( - <> - <button disabled={isLoading} onClick={() => signTypedData()}> - {isLoading ? "Check Wallet" : "Sign Message"} - </button> - - {data && ( - <div> - <div>Signature: {data}</div> - <div>Recovered address {recoveredAddress}</div> - </div> - )} - {error && <div>Error: {error?.message}</div>} - </> - ); -} -``` - -### Read Contract - -```typescript -import { useState } from "react"; -import { BaseError } from "viem"; -import { type Address, useContractRead } from "wagmi"; - -import { erc20TokenABI } from "./contracts"; - -export function ReadContract() { - return ( - <div> - <div> - <BalanceOf /> - <br /> - <TotalSupply /> - </div> - </div> - ); -} - -function TotalSupply() { - const { data, isRefetching, refetch } = useContractRead({ - ...erc20TokenABI, - functionName: "totalSupply", - }); - - return ( - <div> - Total Supply: {data?.toString()} - <button disabled={isRefetching} onClick={() => refetch()} style={{ marginLeft: 4 }}> - {isRefetching ? "loading..." : "refetch"} - </button> - </div> - ); -} - -function BalanceOf() { - const [address, setAddress] = useState<Address>("0x3e7676937A7E96CFB7616f255b9AD9FF47363D4b"); - const { data, error, isLoading, isSuccess } = useContractRead({ - ...erc20TokenABI, - functionName: "balanceOf", - args: [address], - enabled: Boolean(address), - }); - - const [value, setValue] = useState<string>(address); - - return ( - <div> - Token balance: {isSuccess && data?.toString()} - <input onChange={(e) => setValue(e.target.value)} placeholder="wallet address" style={{ marginLeft: 4 }} value={value} /> - <button onClick={() => setAddress(value as Address)}>{isLoading ? "fetching..." : "fetch"}</button> - {error && <div>{(error as BaseError).shortMessage}</div>} - </div> - ); -} -``` - -### Token - -```typescript -import { useState } from "react"; -import { type Address, useToken } from "wagmi"; - -export function Token() { - const [address, setAddress] = useState<Address>("0x3e7676937A7E96CFB7616f255b9AD9FF47363D4b"); - const { data, error, isError, isLoading, refetch } = useToken({ address }); - - return ( - <> - <div> - <input onChange={(e) => setAddress(e.target.value as Address)} placeholder="token address" value={address} /> - <button onClick={() => refetch()}>fetch</button> - </div> - - {data && ( - <div> - {data.totalSupply?.formatted} {data.symbol} - </div> - )} - {isLoading && <div>Fetching token...</div>} - {isError && <div>Error: {error?.message}</div>} - </> - ); -} -``` - -### Write Contract - -```typescript -import { BaseError } from "viem"; -import { useContractWrite, useWaitForTransaction } from "wagmi"; - -import { erc721Contract } from "./contracts"; -import { stringify } from "../utils/stringify"; - -export function WriteContract() { - const { write, data, error, isLoading, isError } = useContractWrite({ - ...erc721Contract, - functionName: "mint", - }); - const { data: receipt, isLoading: isPending, isSuccess } = useWaitForTransaction({ hash: data?.hash }); - - return ( - <> - <h3>Mint an NFT</h3> - <form - onSubmit={(e) => { - e.preventDefault(); - const formData = new FormData(e.target as HTMLFormElement); - const tokenId = formData.get("tokenId") as string; - write({ - args: [BigInt(tokenId)], - }); - }} - > - <input name="tokenId" placeholder="token id" /> - <button disabled={isLoading} type="submit"> - Mint - </button> - </form> - - {isLoading && <div>Check wallet...</div>} - {isPending && <div>Transaction pending...</div>} - {isSuccess && ( - <> - <div>Transaction Hash: {data?.hash}</div> - <div> - Transaction Receipt: <pre>{stringify(receipt, null, 2)}</pre> - </div> - </> - )} - {isError && <div>{(error as BaseError)?.shortMessage}</div>} - </> - ); -} -``` diff --git a/content/20.build/tutorials/tooling-guides/wallet-connect.md b/content/20.build/tutorials/tooling-guides/wallet-connect.md deleted file mode 100644 index fc6174c0..00000000 --- a/content/20.build/tutorials/tooling-guides/wallet-connect.md +++ /dev/null @@ -1,107 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: WalletConnect | zkSync Docs ---- - -# WalletConnect - -Using WalletConnect with zkSync Era is fast and easy. Below is a quick example to get you started. - -WalletConnect's [Web3Modal React](https://docs.walletconnect.com/web3modal/react/about#introduction) integrates with the -Wagmi library, offering a suite of React Hooks to streamline your dapp development. This enables effortless message -signing, smart contract interactions, and additional functionalities. - -::: info Don't have a project ID? - -Head over to [WalletConnect Cloud](https://cloud.walletconnect.com/sign-in) and create a new project now! This is a -requirement for using WalletConnect. - -::: - -## Installation - -::: code-tabs @tab yarn - -```bash -yarn add @web3modal/wagmi wagmi viem -``` - -@tab npm - -```bash -npm install @web3modal/wagmi wagmi viem -``` - -::: - -You can find more details about the installation in the -[WalletConnect documentation](https://docs.walletconnect.com/web3modal/react/about#installation). - -## Implementation - -You can start Web3Modal configuration using either **default** or **custom** mode. - -Default mode will implement WalletConnect, Browser Wallets (injected) and -[Wagmi's public provider](https://wagmi.sh/react/providers/public) and -[WalletConnect's provider](https://docs.walletconnect.com/cloud/blockchain-api). - -Start by importing `createWeb3Modal`, `defaultWagmiConfig` and wagmi packages, then create `wagmiConfig` using -`defaultWagmiConfig` function as shown below. Finally, pass `wagmiConfig` to `createWeb3Modal`. - -Find an example below: - -```ts -import React from "react"; -import ReactDOM from "react-dom/client"; -import { createWeb3Modal, defaultWagmiConfig } from "@web3modal/wagmi/react"; -import { WagmiConfig, useAccount } from "wagmi"; -import { zkSync } from "wagmi/chains"; -import "./index.css"; - -// 1. Get projectId -const projectId = <PROJECT_ID>; - -// 2. Create wagmiConfig -const chains = [zkSync]; -const wagmiConfig = defaultWagmiConfig({ - chains, - projectId, - metadata: { name: "Web3Modal v3" }, -}); - -// 3. Create modal -createWeb3Modal({ wagmiConfig, projectId, chains, defaultChain: zkSync }); - -// 4. Create modal -const App = () => { - const { address } = useAccount(); - return ( - <> - <div className="container"> - <w3m-button /> - <w3m-network-button /> - </div> - <p> - {address && ( - <> - <b>Address:</b> {address} - </> - )} - </p> - </> - ); -}; - -ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render( - <React.StrictMode> - <WagmiConfig config={wagmiConfig}> - <App /> - </WagmiConfig> - </React.StrictMode>, -); -``` - -You can find more information about how to integrate Web3Modal in the -[WalletConnect documentation](https://docs.walletconnect.com/web3modal/react/about#implementation). diff --git a/content/20.build/tutorials/tooling-guides/web3js.md b/content/20.build/tutorials/tooling-guides/web3js.md deleted file mode 100644 index 1ddf647f..00000000 --- a/content/20.build/tutorials/tooling-guides/web3js.md +++ /dev/null @@ -1,84 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Web3.js | zkSync Docs ---- - -# Web3.js - -[Web3.js](https://web3js.org/) is a robust and flexible collection of libraries for TypeScript and JavaScript -developers. It serves as an essential tool for connecting and crafting applications within the Ethereum ecosystem and -can be extended to support other networks through its -[plugin system](https://docs.web3js.org/guides/web3_plugin_guide/). - -You can use the [zkSync plugin](https://github.com/web3/web3-plugin-zksync) for Web3.js to interact with the -[zkSync JSON-RPC API](https://docs.zksync.io/build/api.html) smart contracts deployed on zkSync. - -## Installation - -Start by adding Web3.js and the zkSync plugin for Web3.js to your project. Open your terminal and execute the following -command: - -```bash -npm install --save web3 web3-plugin-zksync -``` - -This command installs the latest version of Web3.js and the zkSync plugin for Web3.js and adds them to your project's -dependencies. - -## Initial Setup - -### Initialization - -Before using the zkSync plugin for Web3.js, you need to -[initialize Web3 with a provider](https://docs.web3js.org/#initialize-web3-with-a-provider) and -[register the plugin](https://docs.web3js.org/guides/web3_plugin_guide/plugin_users#registering-the-plugin). - -#### Example - -```javascript -import { Web3 } from "web3"; -import { ZkSyncPlugin } from "web3-plugin-zksync"; - -const zkSyncRpcUrl: string = "https://sepolia.era.zksync.dev"; - -console.log(`📞 Connecting to zkSync Era [${zkSyncRpcUrl}]`); -const web3: Web3 = new Web3(zkSyncRpcUrl); -web3.registerPlugin(new ZkSyncPlugin()); -``` - -:::info - -- This examples uses the zkSync Sepolia testnet. - -::: - -### Ethereum JSON-RPC API - -Use the Web3.js `eth` package to fetch data from the zkSync -[Ethereum JSON-RPC API](https://ethereum.org/en/developers/docs/apis/json-rpc). - -#### Fetch the Latest Block Number - -```javascript -const blockNumber = await web3.eth.getBlockNumber(); -console.log(`Current block number: ${blockNumber}`); -``` - -### zkSync L2-Specific JSON-RPC API - -The zkSync plugin for Web3.js implements the zkSync-specific methods from the `zks_` namespace of the -[JSON-RPC API](https://docs.zksync.io/build/api.html#zksync-era-json-rpc-methods). - -#### Fetch the Main Contract Address - -```javascript -const mainContract = await web3.zkSync.rpc.getMainContract(); -console.log(`Main contract: ${mainContract}`); -``` - -### Wallet Configuration - -Refer to the Web3.js documentation for -[details regarding wallet configuration](https://docs.web3js.org/#setting-up-a-wallet). diff --git a/content/30.infra/README.md b/content/30.infra/README.md deleted file mode 100644 index d2d42339..00000000 --- a/content/30.infra/README.md +++ /dev/null @@ -1,52 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Run a Node | zkSync Docs ---- - -# Run a Node - -<section> - <div class="card-container"> - <RouterLink - to="/infra/introduction" - class="card" - > - <img - src="/images/landing/lets-get-started.png" - alt="Running an external node" - > - <div class="content"> - <h3>Introduction</h3> - <p>Learn more about our external node.</p> - </div> - </RouterLink> - <RouterLink - to="/infra/running-node" - class="card" - > - <img - src="/images/landing/run-a-node.png" - alt="zkSync ERA documentation" - /> - <div class="content"> - <h3>Running</h3> - <p>Run your own node at home.</p> - </div> - </RouterLink> - <RouterLink - to="/infra/component-breakdown" - class="card" - > - <img - src="/images/landing/diverse-toolkit.png" - alt="Diverse Toolkit" - > - <div class="content"> - <h3>External Node Components</h3> - <p>Overview of the EN's main components.</p> - </div> - </RouterLink> - </div> -</section> diff --git a/content/30.infra/api-overview.md b/content/30.infra/api-overview.md deleted file mode 100644 index e01cb98c..00000000 --- a/content/30.infra/api-overview.md +++ /dev/null @@ -1,120 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: API Overview | zkSync Docs ---- - -# API Overview - -:::info The API exposed by the EN is designed to be Web3-compliant. Any deviation from the Ethereum behavior is likely -unintended, and we encourage users to report such discrepancies. ::: - -### `eth_` Namespace - -Data getters in this namespace operate in the L2 domain. They deal with L2 block numbers, check balances in L2, and -more. - -| Method | Notes | -| ----------------------------------------- | ------------------------------------------------------------------------- | -| `eth_blockNumber` | | -| `eth_chainId` | | -| `eth_call` | | -| `eth_estimateGas` | | -| `eth_gasPrice` | | -| `eth_newFilter` | Maximum amount of installed filters is configurable | -| `eth_newBlockFilter` | Same as above | -| `eth_newPendingTransactionsFilter` | Same as above | -| `eth_uninstallFilter` | | -| `eth_getLogs` | Maximum amount of returned entities can be configured | -| `eth_getFilterLogs` | Same as above | -| `eth_getFilterChanges` | Same as above | -| `eth_getBalance` | | -| `eth_getBlockByNumber` | | -| `eth_getBlockByHash` | | -| `eth_getBlockTransactionCountByNumber` | | -| `eth_getBlockTransactionCountByHash` | | -| `eth_getCode` | | -| `eth_getStorageAt` | | -| `eth_getTransactionCount` | | -| `eth_getTransactionByHash` | | -| `eth_getTransactionByBlockHashAndIndex` | | -| `eth_getTransactionByBlockNumberAndIndex` | | -| `eth_getTransactionReceipt` | | -| `eth_protocolVersion` | | -| `eth_sendRawTransaction` | | -| `eth_syncing` | EN is considered synced if it's less than 11 blocks behind the main node. | -| `eth_coinbase` | Always returns a zero address | -| `eth_accounts` | Always returns an empty list | -| `eth_getCompilers` | Always returns an empty list | -| `eth_hashrate` | Always returns zero | -| `eth_getUncleCountByBlockHash` | Always returns zero | -| `eth_getUncleCountByBlockNumber` | Always returns zero | -| `eth_mining` | Always returns false | - -### **PubSub** - -This is exclusively available on the WebSocket servers. - -| Method | Notes | -| ------------------ | ----------------------------------------------- | -| `eth_subscribe` | Maximum amount of subscriptions is configurable | -| `eth_subscription` | | - -### `net_` Namespace - -| Method | Notes | -| ---------------- | -------------------- | -| `net_version` | | -| `net_peer_count` | Always returns 0 | -| `net_listening` | Always returns false | - -### `web3_` Namespace - -| Method | Notes | -| -------------------- | ----- | -| `web3_clientVersion` | | - -### `debug_` Namespace\*\* - -This namespace provides a set of non-standard RPC methods for developers to inspect and debug calls and transactions. By -default, this namespace is disabled but can be activated using the `EN_API_NAMESPACES` setting. Please refer to the -configuration section for more details.; - -| Method | Notes | -| -------------------------- | ----- | -| `debug_traceBlockByNumber` | | -| `debug_traceBlockByHash` | | -| `debug_traceCall` | | -| `debug_traceTransaction` | | - -### `zks` Namespace - -This namespace holds rollup-specific extensions to the Web3 API. Only the methods documented are deemed public. Other -methods in this namespace, though exposed, are not stable and may change without notice. - -| Method | Notes | -| ----------------------------- | ----- | -| `zks_estimateFee` | | -| `zks_estimateGasL1ToL2` | | -| `zks_getAllAccountBalances` | | -| `zks_getBlockDetails` | | -| `zks_getBridgeContracts` | | -| `zks_getBytecodeByHash` | | -| `zks_getConfirmedTokens` | | -| `zks_getL1BatchBlockRange` | | -| `zks_getL1BatchDetails` | | -| `zks_getL2ToL1LogProof` | | -| `zks_getL2ToL1MsgProof` | | -| `zks_getMainContract` | | -| `zks_getRawBlockTransactions` | | -| `zks_getTestnetPaymaster` | | -| `zks_getTokenPrice` | | -| `zks_getTransactionDetails` | | -| `zks_L1BatchNumber` | | -| `zks_L1ChainId` | | - -### `en` Namespace - -This namespace includes methods that external nodes call on the main node during syncing. If this namespace is active, -other ENs can sync using this node. diff --git a/content/30.infra/component-breakdown.md b/content/30.infra/component-breakdown.md deleted file mode 100644 index 9c837c58..00000000 --- a/content/30.infra/component-breakdown.md +++ /dev/null @@ -1,84 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Component Breakdown | zkSync Docs ---- - -# EN components - -This section contains an overview of the EN's main components. - -## API - -The EN can serve both the HTTP and the WS Web3 API, as well as PubSub. Whenever possible, it provides data based on the -local state, with a few exceptions: - -- Submitting transactions: Since it is a read replica, submitted transactions are proxied to the main node, and the - response is returned from the main node. -- Querying transactions: The EN is not aware of the main node's mempool, and it does not sync rejected transactions. - Therefore, if a local lookup for a transaction or its receipt fails, the EN will attempt the same query on the main - node. - -Apart from these cases, the API does not depend on the main node. Even if the main node is temporarily unavailable, the -EN can continue to serve the state it has locally. - -## Fetcher - -The Fetcher component is responsible for maintaining synchronization between the EN and the main node. Its primary task -is to fetch new blocks in order to update the local chain state. However, its responsibilities extend beyond that. For -instance, the Fetcher is also responsible for keeping track of L1 batch statuses. This involves monitoring whether -locally applied batches have been committed, proven, or executed on L1. - -It is worth noting that in addition to fetching the _state_, the EN also retrieves the L1 gas price from the main node -for the purpose of estimating fees for L2 transactions (since this also happens based on the local state). This -information is necessary to ensure that gas estimations are performed in the exact same manner as the main node, thereby -reducing the chances of a transaction not being included in a block. - -## State Keeper / VM - -The State Keeper component serves as the "sequencer" part of the node. It shares most of its functionality with the main -node, with one key distinction. The main node retrieves transactions from the mempool and has the authority to decide -when a specific L2 block or L1 batch should be sealed. On the other hand, the EN retrieves transactions from the queue -populated by the Fetcher and seals the corresponding blocks/batches based on the data obtained from the Fetcher queue. - -The actual execution of batches takes place within the VM, which is identical in both the Main and External nodes. - -## Reorg Detector - -In zkSync Era, it is theoretically possible for L1 batches to be reverted before the corresponding "execute" operation -is applied on L1, that is before the block is [final][finality]. Such situations are highly uncommon and typically occur -due to significant issues: e.g. a bug in the sequencer implementation preventing L1 batch commitment. Prior to batch -finality, the zkSync operator can perform a rollback, reverting one or more batches and restoring the blockchain state -to a previous point. Finalized batches cannot be reverted at all. - -However, even though such situations are rare, the EN must handle them correctly. - -To address this, the EN incorporates a Reorg Detector component. This module keeps track of all L1 batches that have not -yet been finalized. It compares the locally obtained state root hashes with those provided by the main node's API. If -the root hashes for the latest available L1 batch do not match, the Reorg Detector searches for the specific L1 batch -responsible for the divergence. Subsequently, it rolls back the local state and restarts the node. Upon restart, the EN -resumes normal operation. - -[finality]: https://docs.zksync.io/zk-stack/concepts/finality.html - -## Consistency Checker - -The main node API serves as the primary source of information for the EN. However, relying solely on the API may not -provide sufficient security since the API data could potentially be incorrect due to various reasons. The primary source -of truth for the rollup system is the L1 smart contract. Therefore, to enhance the security of the EN, each L1 batch -undergoes cross-checking against the L1 smart contract by a component called the Consistency Checker. - -When the Consistency Checker detects that a particular batch has been sent to L1, it recalculates a portion of the input -known as the "block commitment" for the L1 transaction. The block commitment contains crucial data such as the state -root and batch number, and is the same commitment that is used for generating a proof for the batch. The Consistency -Checker then compares the locally obtained commitment with the actual commitment sent to L1. If the data does not match, -it indicates a potential bug in either the main node or external node implementation or that the main node API has -provided incorrect data. In either case, the state of the EN cannot be trusted, and the EN enters a crash loop until the -issue is resolved. - -## Health check server - -The EN also exposes an additional server that returns HTTP 200 response when the EN is operating normally, and HTTP 503 -response when some of the health checks don't pass (e.g. when the EN is not fully initialized yet). This server can be -used, for example, to implement the readiness probe in an orchestration solution you use. diff --git a/content/30.infra/configuration.md b/content/30.infra/configuration.md deleted file mode 100644 index 769790c9..00000000 --- a/content/30.infra/configuration.md +++ /dev/null @@ -1,76 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Configuration | zkSync Docs ---- - -# External Node Configuration - -This document outlines various configuration options for the EN. Currently, the EN requires the definition of numerous -environment variables. To streamline this process, we provide prepared configs for the zkSync Era - for both mainnet and -testnet. You can use these files as a starting point and modify only the necessary sections. - -## Database - -The EN uses two databases: PostgreSQL and RocksDB. - -PostgreSQL serves as the main source of truth in the EN, so all the API requests fetch the state from there. The -PostgreSQL connection is configured by the `DATABASE_URL`. Additionally, the `DATABASE_POOL_SIZE` variable defines the -size of the connection pool. - -RocksDB is used in components where IO is a bottleneck, such as the State Keeper and the Merkle tree. If possible, it is -recommended to use an NVME SSD for RocksDB. RocksDB requires two variables to be set: `EN_STATE_CACHE_PATH` and -`EN_MERKLE_TREE_PATH`, which must point to different directories. - -## L1 Web3 client - -EN requires a connection to an Ethereum node. The corresponding env variable is `EN_ETH_CLIENT_URL`. Make sure to set -the URL corresponding to the correct L1 network (L1 mainnet for L2 mainnet and L1 sepolia for L2 testnet). - -Note: Currently, the EN makes 2 requests to the L1 per L1 batch, so the Web3 client usage for a synced node should not -be high. However, during the synchronization phase the new batches would be persisted on the EN quickly, so make sure -that the L1 client won't exceed any limits (e.g. in case you use Infura). - -## Exposed ports - -The dockerized version of the server exposes the following ports: - -- HTTP JSON-RPC: `3060` -- WebSocket JSON-RPC: `3061` -- Prometheus listener: `3322` -- Healthcheck server: `3081` - -While the configuration variables for them exist, you are not expected to change them unless you want to use the EN -outside of provided docker environment (not supported at the time of writing). - -:::info **NOTE**: if the Prometheus port is configured, it must be -[scraped](https://prometheus.io/docs/introduction/overview/) periodically to avoid a memory leak due to a -[bug in an external metrics library](https://github.com/metrics-rs/metrics/issues/245). If you are not intending to use -the metrics, leave this port not configured, and the metrics won't be collected. ::: - -## API limits - -There are variables that allow you to fine-tune the limits of the RPC servers, such as limits on the number of returned -entries or the limit for the accepted transaction size. Provided files contain sane defaults that are recommended for -use, but these can be edited, e.g. to make the EN more/less restrictive. - -## JSON-RPC API namespaces - -There are 7 total supported API namespaces: `eth`, `net`, `web3`, `debug` - standard ones; `zks` - rollup-specific one; -`pubsub` - a.k.a. `eth_subscribe`; `en` - used by external nodes while syncing. You can configure what namespaces you -want to enable using `EN_API_NAMESPACES` and specifying namespace names in a comma-separated list. By default, all but -the `debug` namespace are enabled. - -## Logging and observability - -`MISC_LOG_FORMAT` defines the format in which logs are shown: `plain` corresponds to the human-readable format, while -the other option is `json` (recommended for deployments). - -`RUST_LOG` variable allows you to set up the logs granularity (e.g. make the EN emit fewer logs). You can read about the -format [here](https://docs.rs/env_logger/0.10.0/env_logger/#enabling-logging). - -`MISC_SENTRY_URL` and `MISC_OTLP_URL` variables can be configured to set up Sentry and OpenTelemetry exporters. - -If Sentry is configured, you also have to set `EN_SENTRY_ENVIRONMENT` variable to configure the environment in events -reported to sentry. diff --git a/content/30.infra/introduction.md b/content/30.infra/introduction.md deleted file mode 100644 index ef31a891..00000000 --- a/content/30.infra/introduction.md +++ /dev/null @@ -1,165 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: External Node | zkSync Docs ---- - -:::info For local testing, we recommend setting up an in-memory node and forking mainnet. ::: - -# External Node Documentation - -This documentation explains the basics of the zkSync Era External Node. - -## Disclaimers - -- The external node is in the alpha phase, and should be used with caution. -- While in alpha, the EN is dependent on a DB snapshot in order to run that is not yet publicly available. -- The EN is a read-only replica of the main node. We are currently working on decentralizing our infrastructure by - creating a consensus node. The EN is not going to be the consensus node. - -## What is the External Node? - -The external node (herein EN) is a read-replica of the main (centralized) node that can be run by external parties. It -functions by fetching data from the zkSync API and re-applying transactions locally, starting from the genesis block. -The EN shares most of its codebase with the main node. Consequently, when it re-applies transactions, it does so exactly -as the main node did in the past. - -In Ethereum terms, the current state of the EN represents an archive node, providing access to the entire history of the -blockchain. - -## High-level Overview - -At a high level, the EN can be seen as an application that has the following modules: - -- API server that provides the publicly available Web3 interface. -- Synchronization layer that interacts with the main node and retrieves transactions and blocks to re-execute. -- Sequencer component that actually executes and persists transactions received from the synchronization layer. -- Several checker modules that ensure the consistency of the EN state. - -With the EN, you are able to: - -- Locally recreate and verify the zkSync Era mainnet/testnet state. -- Interact with the recreated state in a trustless way (in a sense that the validity is locally verified, and you should - not rely on a third-party API zkSync Era provides). -- Use the Web3 API without having to query the main node. -- Send L2 transactions (that will be proxied to the main node). - -With the EN, you _can not_: - -- Create L2 blocks or L1 batches on your own. -- Generate proofs. -- Submit data to L1. - -A more detailed overview of the EN's components is provided in the components section. - -## API Overview - -API exposed by the EN strives to be Web3-compliant. If some method is exposed but behaves differently compared to -Ethereum, it should be considered a bug. Please [report][contact_us] such cases. - -[contact_us]: https://zksync.io/contact - -### `eth_` Namespace - -Data getters in this namespace operate in the L2 space: require/return L2 block numbers, check balances in L2, etc. - -Available methods: - -| Method | Notes | -| ----------------------------------------- | ------------------------------------------------------------------------- | -| `eth_blockNumber` | | -| `eth_chainId` | | -| `eth_call` | | -| `eth_estimateGas` | | -| `eth_gasPrice` | | -| `eth_newFilter` | Maximum amount of installed filters is configurable | -| `eth_newBlockFilter` | Same as above | -| `eth_newPendingTransactionsFilter` | Same as above | -| `eth_uninstallFilter` | | -| `eth_getLogs` | Maximum amount of returned entities can be configured | -| `eth_getFilterLogs` | Same as above | -| `eth_getFilterChanges` | Same as above | -| `eth_getBalance` | | -| `eth_getBlockByNumber` | | -| `eth_getBlockByHash` | | -| `eth_getBlockTransactionCountByNumber` | | -| `eth_getBlockTransactionCountByHash` | | -| `eth_getCode` | | -| `eth_getStorageAt` | | -| `eth_getTransactionCount` | | -| `eth_getTransactionByHash` | | -| `eth_getTransactionByBlockHashAndIndex` | | -| `eth_getTransactionByBlockNumberAndIndex` | | -| `eth_getTransactionReceipt` | | -| `eth_protocolVersion` | | -| `eth_sendRawTransaction` | | -| `eth_syncing` | EN is considered synced if it's less than 11 blocks behind the main node. | -| `eth_coinbase` | Always returns a zero address | -| `eth_accounts` | Always returns an empty list | -| `eth_getCompilers` | Always returns an empty list | -| `eth_hashrate` | Always returns zero | -| `eth_getUncleCountByBlockHash` | Always returns zero | -| `eth_getUncleCountByBlockNumber` | Always returns zero | -| `eth_mining` | Always returns false | - -### PubSub - -Only available on the WebSocket servers. - -Available methods: - -| Method | Notes | -| ------------------ | ----------------------------------------------- | -| `eth_subscribe` | Maximum amount of subscriptions is configurable | -| `eth_subscription` | | - -### `net_` Namespace - -Available methods: - -| Method | Notes | -| ---------------- | -------------------- | -| `net_version` | | -| `net_peer_count` | Always returns 0 | -| `net_listening` | Always returns false | - -### `web3_` Namespace - -Available methods: - -| Method | Notes | -| -------------------- | ----- | -| `web3_clientVersion` | | - -### `debug` namespace - -The `debug` namespace gives access to several non-standard RPC methods, which will allow developers to inspect and debug -calls and transactions. - -This namespace is disabled by default and can be configured via setting `EN_API_NAMESPACES` as described in the example -config. - -Available methods: - -| Method | Notes | -| -------------------------- | ----- | -| `debug_traceBlockByNumber` | | -| `debug_traceBlockByHash` | | -| `debug_traceCall` | | -| `debug_traceTransaction` | | - -### `zks` namespace - -This namespace contains rollup-specific extensions to the Web3 API. Note that _only methods_ specified in the -documentation are considered public. There may be other methods exposed in this namespace, but undocumented methods come -without any kind of stability guarantees and can be changed or removed without notice. - -Always refer to the documentation linked above to see the list of stabilized methods in this namespace. - -[zks_docs](../build/api.md#zksync-era-json-rpc-methods) - -### `en` namespace - -This namespace contains methods that external nodes call on the main node while syncing. If this namespace is enabled -other ENs can sync from this node. diff --git a/content/30.infra/observability.md b/content/30.infra/observability.md deleted file mode 100644 index c1729731..00000000 --- a/content/30.infra/observability.md +++ /dev/null @@ -1,60 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Observability | zkSync Docs ---- - -# EN Observability - -The EN provides several options for setting up observability. Configuring logs and sentry is described in the -configuration section, so this section focuses on the exposed metrics. - -This section is written with the assumption that you're familiar with -[Prometheus](https://prometheus.io/docs/introduction/overview/) and [Grafana](https://grafana.com/docs/). - -## Buckets - -By default, latency histograms are distributed in the following buckets (in seconds): - -``` -[0.001, 0.005, 0.025, 0.1, 0.25, 1.0, 5.0, 30.0, 120.0] -``` - -## Metrics - -EN exposes a lot of metrics, a significant amount of which aren't interesting outside the development flow. This -section's purpose is to highlight metrics that may be worth observing in the external setup. - -If you are not planning to scrape Prometheus metrics, please unset `EN_PROMETHEUS_PORT` environment variable to prevent -memory leaking. - -| Metric name | Type | Labels | Description | -| ---------------------------------------------- | --------- | ------------------------------------- | ------------------------------------------------------------------ | -| `external_node_synced` | Gauge | - | 1 if synced, 0 otherwise. Matches `eth_call` behavior | -| `external_node_sync_lag` | Gauge | - | How many blocks behind the main node the EN is | -| `external_node_fetcher_requests` | Histogram | `stage`, `actor` | Duration of requests performed by the different fetcher components | -| `external_node_fetcher_cache_requests` | Histogram | - | Duration of requests performed by the fetcher cache layer | -| `external_node_fetcher_miniblock` | Gauge | `status` | The number of the last L2 block update fetched from the main node | -| `external_node_fetcher_l1_batch` | Gauge | `status` | The number of the last batch update fetched from the main node | -| `external_node_action_queue_action_queue_size` | Gauge | - | Amount of fetched items waiting to be processed | -| `server_miniblock_number` | Gauge | `stage`=`sealed` | Last locally applied L2 block number | -| `server_block_number` | Gauge | `stage`=`sealed` | Last locally applied L1 batch number | -| `server_block_number` | Gauge | `stage`=`tree_lightweight_mode` | Last L1 batch number processed by the tree | -| `server_processed_txs` | Counter | `stage`=`mempool_added, state_keeper` | Can be used to show incoming and processing TPS values | -| `api_web3_call` | Histogram | `method` | Duration of Web3 API calls | -| `sql_connection_acquire` | Histogram | - | Time to get an SQL connection from the connection pool | - -## Interpretation - -After applying a dump, the EN has to rebuild the Merkle tree to verify the correctness of the state in PostgreSQL. -During this stage, `server_block_number { stage='tree_lightweight_mode' }` is increasing from 0 to -`server_block_number { stage='sealed' }`, while the latter does not increase (EN needs the tree to be up-to-date to -progress). - -After that, the EN has to sync with the main node. `server_block_number { stage='sealed' }` is increasing, and -`external_node_sync_lag` is decreasing. - -Once the node is synchronized, it is indicated by the `external_node_synced`. - -Metrics can be used to detect anomalies in configuration, which is described in more detail in the next section. diff --git a/content/30.infra/running-node.md b/content/30.infra/running-node.md deleted file mode 100644 index 694d6787..00000000 --- a/content/30.infra/running-node.md +++ /dev/null @@ -1,82 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Running Node | zkSync Docs ---- - -# Running the External Node - -This section assumes that you have prepared a configuration file as described on the previous page. - -## Preferred hardware configuration - -This configuration is approximate, expect updates to these specs. - -- 32-core CPU -- 64GB RAM -- SSD storage: - - Testnet - ~800 GB (at the time of writing) and will grow over time, so should be constantly monitored - - Mainnet - ~400 GB (at the time of writing) and will grow over time, so should be constantly monitored - - NVMe recommended -- 100 Mbps network connection. - -### A note about PostgreSQL storage - -By far, the heaviest table to maintain is the `call_traces` table. This table is only required for the `debug` -namespace. If you want to clear some space and aren't using the `debug` namespace, you can - -- clear it with a simple query `DELETE FROM call_traces;` -- leave the `debug` namespace disabled via the `EN_API_NAMESPACES` env var as described in the example config. - -## Infrastructure - -You need to set up a PostgreSQL server with SSD storage: - -- Testnet - ~1TB (at the time of writing) and will grow over time, so should be constantly monitored -- Mainnet - ~2TB (at the time of writing) and will grow over time, so should be constantly monitored - -Setting up Postgres is out of the scope of these docs, but the popular choice is to run it in Docker. There are many of -guides on that, [here's one example](https://www.docker.com/blog/how-to-use-the-postgres-docker-official-image/). - -Note however that if you run Postgres as a stand-alone Docker image (e.g. not in Docker-compose with a network shared -between EN and Postgres), EN won't be able to access Postgres via `localhost` or `127.0.0.1` URLs. To make it work, -you'll have to either run it with a `--network host` (on Linux) or use `host.docker.internal` instead of `localhost` in -the EN configuration (official docs). - -Besides running Postgres, you are expected to have a DB dump from a corresponding env. You can restore it using -`pg_restore -O -C <DUMP_PATH> --dbname=<DB_URL>`. - -[host_docker_internal](https://docs.docker.com/desktop/networking/#i-want-to-connect-from-a-container-to-a-service-on-the-host) - -## Running - -Assuming you have the EN Docker image, an env file with the prepared configuration, and you have restored your DB with -the pg dump, that is all you need. - -Sample running command: - -```sh -docker run --env-file <path_to_env_file> --mount type=bind,source=<local_rocksdb_data_path>,target=<configured_rocksdb_data_path> <image> -``` - -Helm charts and other infrastructure configuration options, if required, would be available later. - -## First start - -When you start the node for the first time, the state in PostgreSQL corresponds to the dump you have used, but the state -in RocksDB (mainly the Merkle tree) is absent. Before the node can make any progress, it has to rebuild the state in -RocksDB and verify consistency. The exact time required for that depends on the hardware configuration, but it is -reasonable to expect the state rebuild on the mainnet to take more than 20 hours. - -## Redeploying the EN with a new PG dump - -If you've been running the EN for some time and are going to redeploy it using a new PG dump, you should - -- Stop the EN -- Remove SK cache (corresponding to `EN_STATE_CACHE_PATH`) -- Remove your current DB -- Restore with the new dump -- Start the EN - -Monitoring the node behavior and analyzing the state it's in is covered in the observability section. diff --git a/content/30.infra/troubleshooting.md b/content/30.infra/troubleshooting.md deleted file mode 100644 index bea424f5..00000000 --- a/content/30.infra/troubleshooting.md +++ /dev/null @@ -1,66 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Troubleshooting | zkSync Docs ---- - -# EN Troubleshooting - -The EN tries to follow the fail-fast principle: if an anomaly is discovered, instead of attempting state recovery, in -most cases it will restart. Most of the time it will manifest as crashes, and if it happens once, it shouldn't be -treated as a problem. - -However, if the node enters the crash loop or otherwise behaves unexpectedly, it may indicate either a bug in the -implementation or a problem with configuration. This section tries to cover common problems. - -## Panics - -Panics is the Rust programming language notion of irrecoverable errors, and normally if panic happens, the application -will immediately crash. - -- Panic matching `called Result::unwrap() on an Err value: Database(PgDatabaseError)`: problem communicating with the - PostgreSQL, most likely some of the connections have died. -- Panic matching `failed to init rocksdb: Error { message: "IO error: No space left on device"}`: more space on SSD is - required. -- Anything that mentions "Poison Error": a "secondary" panic that may occur if one of the components panicked first. If - you see this panic, look for a panic that happened shortly before it to find the real cause. - -Other kinds of panic aren't normally expected. While in most cases, the state will be recovered after a restart, please -[report](https://zksync.io/contact) such cases to Matter Labs regardless. - -## Genesis Issues - -The EN is supposed to start with an applied DB dump. If you see any genesis-related errors, it probably means the EN was -started without an applied dump. - -[contact_us](https://zksync.io/contact) - -## Logs - -_Note: logs with the `error` level are reported to Sentry if it's configured. If you notice unneeded alerts there that -you don't consider actionable, you may disable logs for a component by tweaking the configuration._ - -| Level | Log substring | Interpretation | -| ----- | ----------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- | -| ERROR | "One of the tokio actors unexpectedly finished" | One of the components crashed, and the node is restarting. | -| WARN | "Stop signal received, <component\> is shutting down" | Satellite log of the message above | -| ERROR | "A lot of requests to the remote API failed in a row" | The remote API used to update token lists is probably down. Logs should disappear once API is available. | -| WARN | "Server returned an error status code: 429" | The main API rate limits are too strict. [Contact](https://zksync.io/contact) Matter Labs to discuss the situation. | -| WARN | "Following transport error occurred" | There was a problem with fetching data from the main node. | -| WARN | "Unable to get the gas price" | There was a problem with fetching data from the main node. | -| WARN | "Consistency checker error" | There are problems querying L1, check the Web3 URL you specified in the config. | -| WARN | "Reorg detected" | Reorg was detected on the main node, the EN will rollback and restart | - -Same as with panics, normally it's only a problem if a WARN+ level log appears many times in a row. - -## Metrics anomalies - -The following common anomalies can be discovered by observing metrics _after the tree is rebuilt to match the DB -snapshot_: - -- `external_node_sync_lag` doesn't decrease and `external_node_action_queue_action_queue_size` is near 0. Cause: The - fetcher can't fetch new blocks quickly enough. Most likely, the network connection is too slow. -- `external_node_sync_lag` doesn't decrease and `external_node_action_queue_action_queue_size` is at some high level. - Cause: The State Keeper doesn't process fetched data quickly enough. Most likely, a more powerful CPU is needed. -- `sql_connection_acquire` skyrockets. Probably, there are not enough connections in the pool to match the demand. diff --git a/content/40.zk-stack/README.md b/content/40.zk-stack/README.md deleted file mode 100644 index 8db6fa80..00000000 --- a/content/40.zk-stack/README.md +++ /dev/null @@ -1,52 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: ZK Stack | zkSync Docs ---- - -# ZK Stack - -<section> - <div class="card-container"> - <RouterLink - to="/zk-stack/running-a-hyperchain/locally" - class="card" - > - <img - src="/images/landing/run-a-hyperchain.png" - alt="zkSync ERA documentation" - /> - <div class="content"> - <h3>Run a Hyperchain</h3> - <p>Quickly spin up a ZK Stack hyperchain on your own machine.</p> - </div> - </RouterLink> - <RouterLink - to="/zk-stack/components/sequencer-server" - class="card" - > - <img - src="/images/landing/sequencer.png" - alt="zkSync Sequencer" - > - <div class="content"> - <h3>Sequencer</h3> - <p>Know more about how the ZK Stack sequencer works.</p> - </div> - </RouterLink> - <RouterLink - to="/zk-stack/components/prover/overview" - class="card" - > - <img - src="/images/landing/prover.png" - alt="zkSync ERA documentation" - > - <div class="content"> - <h3>Prover</h3> - <p>Go deep on the cryptography of our state of the art prover, Boojum.</p> - </div> - </RouterLink> - </div> -</section> diff --git a/content/40.zk-stack/components/block-explorer.md b/content/40.zk-stack/components/block-explorer.md deleted file mode 100644 index 1bf7c72a..00000000 --- a/content/40.zk-stack/components/block-explorer.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Block Explorer | zkSync Docs ---- - -# Block Explorer - -[The Block Explorer](https://github.com/matter-labs/block-explorer) is a module to allow exposing everything that is -happening on your hyperchain to your users/developers. It comes with the following components: - -- **Block Explorer Worker:** an indexer service for hyperchain data. The purpose of the service is to read the data from - the blockchain in real-time, transform it and fill in its database to be used by the API. - -- **Block Explorer API:** a service that provides an HTTP API for retrieving structured hyperchain data. It must be - connected to the block explorer worker database. - -- **Block Explorer App:** The UI that allows user/devs to explore transactions, blocks, batches, contracts, tokens, and - much more, on your hyperchain. diff --git a/content/40.zk-stack/components/compiler/specification/code-separation.md b/content/40.zk-stack/components/compiler/specification/code-separation.md deleted file mode 100644 index 87525af1..00000000 --- a/content/40.zk-stack/components/compiler/specification/code-separation.md +++ /dev/null @@ -1,83 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Code Separation | zkSync Docs ---- - -# Code Separation - -On both EVM and EraVM the code is separated into two parts: deploy code and runtime code. The deploy code is executed -only once, when the contract is deployed. The runtime code is executed every time the contract is called. However, on -EraVM the deploy code and runtime code are deployed together, and they are not split into two separate chunks of -bytecode. - -The constructor is added to the contract as a regular public function which is called by System Contracts during -deployment. - -Just like on EVM, the deploy code on EraVM is represented by a single constructor, named differently in different -languages: - -| Language | Name | -| -------- | ----------------- | -| Solidity | `constructor` | -| Yul | `object "<name>"` | -| Vyper | `__init__` | - -The constructor is merged with the runtime code by the LLVM IR generator of our compiler, and a minimal contract on -EraVM looks like on the examples below. - -### LLVM IR - -In the example below, contract `@__entry` arguments `%0`-`%11` correspond to registers `r1`-`r12` on EraVM. - -```c++ -; Function Attrs: nofree noreturn null_pointer_is_valid -define i256 @__entry(ptr addrspace(3) nocapture readnone %0, i256 %1, i256 %2, i256 %3, i256 %4, i256 %5, i256 %6, i256 %7, i256 %8, i256 %9, i256 %10, i256 %11) local_unnamed_addr #1 personality ptr @__personality { -entry: - %is_deploy_code_call_flag_truncated = and i256 %1, 1 ; check if the call is a deploy code call - %is_deploy_code_call_flag.not = icmp eq i256 %is_deploy_code_call_flag_truncated, 0 ; invert the flag - br i1 %is_deploy_code_call_flag.not, label %runtime_code_call_block, label %deploy_code_call_block ; branch to the deploy code block if the flag is set - -deploy_code_call_block: ; preds = %entry - store i256 32, ptr addrspace(2) inttoptr (i256 256 to ptr addrspace(2)), align 256 ; store the offset of the array of immutables - store i256 0, ptr addrspace(2) inttoptr (i256 288 to ptr addrspace(2)), align 32 ; store the length of the array of immutables - tail call void @llvm.syncvm.return(i256 53919893334301279589334030174039261352344891250716429051063678533632) ; return the array of immutables using EraVM return ABI data encoding - unreachable - -runtime_code_call_block: ; preds = %entry - store i256 42, ptr addrspace(1) null, align 4294967296 ; store a value to return - tail call void @llvm.syncvm.return(i256 2535301200456458802993406410752) ; return the value using EraVM return ABI data encoding - unreachable -} -``` - -### EraVM Assembly - -```asm - .text - .file "default.yul" - .globl __entry -__entry: -.func_begin0: - and! 1, r2, r1 ; check if the call is a deploy code call - jump.ne @.BB0_1 ; branch to the deploy code block if the flag is set - add 42, r0, r1 ; move the value to return into r1 - st.1 0, r1 ; store the value to return - add @CPI0_1[0], r0, r1 ; move the return ABI data into r1 - ret.ok.to_label r1, @DEFAULT_FAR_RETURN ; return the value -.BB0_1: - add 32, r0, r1 ; move the offset of the array of immutables into r1 - st.2 256, r1 ; store the offset of the array of immutables - st.2 288, r0 ; store the length of the array of immutables - add @CPI0_0[0], r0, r1 ; move the return ABI data into r1 - ret.ok.to_label r1, @DEFAULT_FAR_RETURN ; return the array of immutables -.func_end0: - - .note.GNU-stack - .rodata -CPI0_0: - .cell 53919893334301279589334030174039261352344891250716429051063678533632 -CPI0_1: - .cell 2535301200456458802993406410752 -``` diff --git a/content/40.zk-stack/components/compiler/specification/evmla-translator.md b/content/40.zk-stack/components/compiler/specification/evmla-translator.md deleted file mode 100644 index 23217c30..00000000 --- a/content/40.zk-stack/components/compiler/specification/evmla-translator.md +++ /dev/null @@ -1,763 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: EVMLA Translator | zkSync Docs ---- - -# EVM Legacy Assembly Translator - -There are two Solidity IRs used in our pipeline: Yul and EVM legacy assembly. The former is used for older versions of -Solidity, more precisely <=0.7. - -EVM legacy assembly is very challenging to translate to LLVM IR, since it obfuscates the control flow of the program and -uses a lot of dynamic jumps. Most of the jumps can be translated to static ones by using a static analysis of EVM -assembly, but some of jumps are impossible to resolve statically. For example, internal function pointers can be written -to memory or storage, and then loaded and called. Recursion is another case we have skipped for now, as there is another -stack frame allocated on every iteration, preventing the static analyzer from resolving the jumps. - -Both issues are being worked on in our fork of the Solidity compiler, where we are changing the codegen to remove the -dynamic jumps and add the necessary metadata. - -Below you can see a minimal example of a Solidity contract and its EVM legacy assembly translated to LLVM IR which is -eventually compiled to EraVM assembly. - -## Source Code - -```solidity -contract Example { - function main() public pure returns (uint256 result) { - result = 42; - } -} -``` - -## EVM Legacy Assembly - -Produced by the upstream Solidity compiler v0.7.6. - -```text -| Line | Instruction | Value/Tag | -| ---- | ------------ | --------- | -| 000 | PUSH | 80 | -| 001 | PUSH | 40 | -| 002 | MSTORE | | -| 003 | CALLVALUE | | -| 004 | DUP1 | | -| 005 | ISZERO | | -| 006 | PUSH | [tag] 1 | -| 007 | JUMPI | | -| 008 | PUSH | 0 | -| 009 | DUP1 | | -| 010 | REVERT | | -| 011 | Tag 1 | | -| 012 | JUMPDEST | | -| 013 | POP | | -| 014 | PUSH | 4 | -| 015 | CALLDATASIZE | | -| 016 | LT | | -| 017 | PUSH | [tag] 2 | -| 018 | JUMPI | | -| 019 | PUSH | 0 | -| 020 | CALLDATALOAD | | -| 021 | PUSH | E0 | -| 022 | SHR | | -| 023 | DUP1 | | -| 024 | PUSH | 5A8AC02D | -| 025 | EQ | | -| 026 | PUSH | [tag] 3 | -| 027 | JUMPI | | -| 028 | Tag 2 | | -| 029 | JUMPDEST | | -| 030 | PUSH | 0 | -| 031 | DUP1 | | -| 032 | REVERT | | -| 033 | Tag 3 | | -| 034 | JUMPDEST | | -| 035 | PUSH | [tag] 4 | -| 036 | PUSH | [tag] 5 | -| 037 | JUMP | [in] | -| 038 | Tag 4 | | -| 039 | JUMPDEST | | -| 040 | PUSH | 40 | -| 041 | DUP1 | | -| 042 | MLOAD | | -| 043 | SWAP2 | | -| 044 | DUP3 | | -| 045 | MSTORE | | -| 046 | MLOAD | | -| 047 | SWAP1 | | -| 048 | DUP2 | | -| 049 | SWAP1 | | -| 050 | SUB | | -| 051 | PUSH | 20 | -| 052 | ADD | | -| 053 | SWAP1 | | -| 054 | RETURN | | -| 055 | Tag 5 | | -| 056 | JUMPDEST | | -| 057 | PUSH | 2A | -| 058 | SWAP1 | | -| 059 | JUMP | [out] | -``` - -## EthIR - -EthIR (Ethereal IR) is a special IR used by our translator to represent EVM legacy assembly and prepare it for the -translation to LLVM IR. The IR solves several purposes: - -1. Tracking the stack state to extract jump destinations. -2. Duplicating blocks that are reachable with different stack states. -3. Restoring the complete control-flow graph of the contract using the abovementioned data. -4. Resolving dependencies and static data chunks. - -Data format: - -1. `V_<name>` - value returned by an instruction `<name>`. -2. `T_<tag>` - tag of a block `<tag>`. -3. `40` - hexadecimal constant. -4. `tests/solidity/simple/default.sol:Test` - contract definition. - -Stack format: `[ V_CALLVALUE ]` (current values) - `[ V_CALLVALUE ]` (popped values) + `[ V_ISZERO ]` (pushed values) - -```asm -// The default entry function of the contract. -function main { -// The maximum stack size in the function. - stack_usage: 6 -block_dt_0/0: // Deploy Code Tag 0, Instance 0. -// PUSHed 0x80 onto the stack. - PUSH 80 [ ] + [ 80 ] -// PUSHed 0x40 onto the stack. - PUSH 40 [ 80 ] + [ 40 ] -// POPped 0x40 at 0x80 from the stack to store 0x80 at 0x40. - MSTORE [ ] - [ 80 | 40 ] -// PUSHed CALLVALUE onto the stack. - CALLVALUE [ ] + [ V_CALLVALUE ] - DUP1 [ V_CALLVALUE ] + [ V_CALLVALUE ] - ISZERO [ V_CALLVALUE ] - [ V_CALLVALUE ] + [ V_ISZERO ] - PUSH [tag] 1 [ V_CALLVALUE | V_ISZERO ] + [ T_1 ] -// JUMPI schedules rt_0/0 for analysis with the current stack state. - JUMPI [ V_CALLVALUE ] - [ V_ISZERO | T_1 ] - PUSH 0 [ V_CALLVALUE ] + [ 0 ] - DUP1 [ V_CALLVALUE | 0 ] + [ 0 ] - REVERT [ V_CALLVALUE ] - [ 0 | 0 ] -block_dt_1/0: (predecessors: dt_0/0) // Deploy Code Tag 1, Instance 0; the only predecessor of this block is dt_0/0. -// JUMPDESTs are ignored as we are only interested in the stack state and tag destinations. - JUMPDEST [ V_CALLVALUE ] - POP [ ] - [ V_CALLVALUE ] - PUSH #[$] tests/solidity/simple/default.sol:Test [ ] + [ tests/solidity/simple/default.sol:Test ] - DUP1 [ tests/solidity/simple/default.sol:Test ] + [ tests/solidity/simple/default.sol:Test ] - PUSH [$] tests/solidity/simple/default.sol:Test [ tests/solidity/simple/default.sol:Test | tests/solidity/simple/default.sol:Test ] + [ tests/solidity/simple/default.sol:Test ] - PUSH 0 [ tests/solidity/simple/default.sol:Test | tests/solidity/simple/default.sol:Test | tests/solidity/simple/default.sol:Test ] + [ 0 ] - CODECOPY [ tests/solidity/simple/default.sol:Test ] - [ tests/solidity/simple/default.sol:Test | tests/solidity/simple/default.sol:Test | 0 ] - PUSH 0 [ tests/solidity/simple/default.sol:Test ] + [ 0 ] - RETURN [ ] - [ tests/solidity/simple/default.sol:Test | 0 ] -// The runtime code is analyzed in the same control-flow graph as the deploy code, as it is possible to call its functions from the constructor. -block_rt_0/0: // Deploy Code Tag 0, Instance 0. - PUSH 80 [ ] + [ 80 ] - PUSH 40 [ 80 ] + [ 40 ] - MSTORE [ ] - [ 80 | 40 ] - CALLVALUE [ ] + [ V_CALLVALUE ] - DUP1 [ V_CALLVALUE ] + [ V_CALLVALUE ] - ISZERO [ V_CALLVALUE ] - [ V_CALLVALUE ] + [ V_ISZERO ] - PUSH [tag] 1 [ V_CALLVALUE | V_ISZERO ] + [ T_1 ] - JUMPI [ V_CALLVALUE ] - [ V_ISZERO | T_1 ] - PUSH 0 [ V_CALLVALUE ] + [ 0 ] - DUP1 [ V_CALLVALUE | 0 ] + [ 0 ] - REVERT [ V_CALLVALUE ] - [ 0 | 0 ] -block_rt_1/0: (predecessors: rt_0/0) // Runtime Code Tag 1, Instance 0; the only predecessor of this block is rt_0/0. - JUMPDEST [ V_CALLVALUE ] - POP [ ] - [ V_CALLVALUE ] - PUSH 4 [ ] + [ 4 ] - CALLDATASIZE [ 4 ] + [ V_CALLDATASIZE ] - LT [ ] - [ 4 | V_CALLDATASIZE ] + [ V_LT ] - PUSH [tag] 2 [ V_LT ] + [ T_2 ] - JUMPI [ ] - [ V_LT | T_2 ] - PUSH 0 [ ] + [ 0 ] - CALLDATALOAD [ ] - [ 0 ] + [ V_CALLDATALOAD ] - PUSH E0 [ V_CALLDATALOAD ] + [ E0 ] - SHR [ ] - [ V_CALLDATALOAD | E0 ] + [ V_SHR ] - DUP1 [ V_SHR ] + [ V_SHR ] - PUSH 5A8AC02D [ V_SHR | V_SHR ] + [ 5A8AC02D ] - EQ [ V_SHR ] - [ V_SHR | 5A8AC02D ] + [ V_EQ ] - PUSH [tag] 3 [ V_SHR | V_EQ ] + [ T_3 ] - JUMPI [ V_SHR ] - [ V_EQ | T_3 ] - Tag 2 [ V_SHR ] -// This instance is called with a different stack state using the JUMPI above. -block_rt_2/0: (predecessors: rt_1/0) // Runtime Code Tag 2, Instance 0. - JUMPDEST [ ] - PUSH 0 [ ] + [ 0 ] - DUP1 [ 0 ] + [ 0 ] - REVERT [ ] - [ 0 | 0 ] -// This instance is also called from rt_1/0, but using a fallthrough 'Tag 2'. -// Given different stack states, we create a new instance of the block operating on different data -// and potentially different tag destinations, although usually such blocks are merged back by LLVM. -block_rt_2/1: (predecessors: rt_1/0) // Runtime Code Tag 2, Instance 1. - JUMPDEST [ V_SHR ] - PUSH 0 [ V_SHR ] + [ 0 ] - DUP1 [ V_SHR | 0 ] + [ 0 ] - REVERT [ V_SHR ] - [ 0 | 0 ] -block_rt_3/0: (predecessors: rt_1/0) // Runtime Code Tag 3, Instance 0. - JUMPDEST [ V_SHR ] - PUSH [tag] 4 [ V_SHR ] + [ T_4 ] - PUSH [tag] 5 [ V_SHR | T_4 ] + [ T_5 ] - JUMP [in] [ V_SHR | T_4 ] - [ T_5 ] -block_rt_4/0: (predecessors: rt_5/0) // Runtime Code Tag 4, Instance 0. - JUMPDEST [ V_SHR | 2A ] - PUSH 40 [ V_SHR | 2A ] + [ 40 ] - DUP1 [ V_SHR | 2A | 40 ] + [ 40 ] - MLOAD [ V_SHR | 2A | 40 ] - [ 40 ] + [ V_MLOAD ] - SWAP2 [ V_SHR | V_MLOAD | 40 | 2A ] - DUP3 [ V_SHR | V_MLOAD | 40 | 2A ] + [ V_MLOAD ] - MSTORE [ V_SHR | V_MLOAD | 40 ] - [ 2A | V_MLOAD ] - MLOAD [ V_SHR | V_MLOAD ] - [ 40 ] + [ V_MLOAD ] - SWAP1 [ V_SHR | V_MLOAD | V_MLOAD ] - DUP2 [ V_SHR | V_MLOAD | V_MLOAD ] + [ V_MLOAD ] - SWAP1 [ V_SHR | V_MLOAD | V_MLOAD | V_MLOAD ] - SUB [ V_SHR | V_MLOAD ] - [ V_MLOAD | V_MLOAD ] + [ V_SUB ] - PUSH 20 [ V_SHR | V_MLOAD | V_SUB ] + [ 20 ] - ADD [ V_SHR | V_MLOAD ] - [ V_SUB | 20 ] + [ V_ADD ] - SWAP1 [ V_SHR | V_ADD | V_MLOAD ] - RETURN [ V_SHR ] - [ V_ADD | V_MLOAD ] -block_rt_5/0: (predecessors: rt_3/0) // Runtime Code Tag 5, Instance 0. - JUMPDEST [ V_SHR | T_4 ] - PUSH 2A [ V_SHR | T_4 ] + [ 2A ] - SWAP1 [ V_SHR | 2A | T_4 ] -// JUMP [out] is usually a return statement - JUMP [out] [ V_SHR | 2A ] - [ T_4 ] -``` - -### Unoptimized LLVM IR - -In LLVM IR, the necessary stack space is allocated at the beginning of the function. - -Every stack operation interacts with a statically known stack pointer with an offset from EthIR. - -```c++ -; Function Attrs: nofree null_pointer_is_valid -define i256 @__entry(ptr addrspace(3) %0, i256 %1, i256 %2, i256 %3, i256 %4, i256 %5, i256 %6, i256 %7, i256 %8, i256 %9, i256 %10, i256 %11) #8 personality ptr @__personality { -entry: - store i256 0, ptr @memory_pointer, align 32 - store i256 0, ptr @calldatasize, align 32 - store i256 0, ptr @returndatasize, align 32 - store i256 0, ptr @call_flags, align 32 - store [10 x i256] zeroinitializer, ptr @extra_abi_data, align 32 - store ptr addrspace(3) %0, ptr @ptr_calldata, align 32 - %abi_pointer_value = ptrtoint ptr addrspace(3) %0 to i256 - %abi_pointer_value_shifted = lshr i256 %abi_pointer_value, 96 - %abi_length_value = and i256 %abi_pointer_value_shifted, 4294967295 - store i256 %abi_length_value, ptr @calldatasize, align 32 - %calldatasize = load i256, ptr @calldatasize, align 32 - %return_data_abi_initializer = getelementptr i8, ptr addrspace(3) %0, i256 %calldatasize - store ptr addrspace(3) %return_data_abi_initializer, ptr @ptr_return_data, align 32 - store ptr addrspace(3) %return_data_abi_initializer, ptr @ptr_active, align 32 - store i256 %1, ptr @call_flags, align 32 - store i256 %2, ptr @extra_abi_data, align 32 - store i256 %3, ptr getelementptr inbounds ([10 x i256], ptr @extra_abi_data, i256 0, i32 1), align 32 - store i256 %4, ptr getelementptr inbounds ([10 x i256], ptr @extra_abi_data, i256 0, i32 2), align 32 - store i256 %5, ptr getelementptr inbounds ([10 x i256], ptr @extra_abi_data, i256 0, i32 3), align 32 - store i256 %6, ptr getelementptr inbounds ([10 x i256], ptr @extra_abi_data, i256 0, i32 4), align 32 - store i256 %7, ptr getelementptr inbounds ([10 x i256], ptr @extra_abi_data, i256 0, i32 5), align 32 - store i256 %8, ptr getelementptr inbounds ([10 x i256], ptr @extra_abi_data, i256 0, i32 6), align 32 - store i256 %9, ptr getelementptr inbounds ([10 x i256], ptr @extra_abi_data, i256 0, i32 7), align 32 - store i256 %10, ptr getelementptr inbounds ([10 x i256], ptr @extra_abi_data, i256 0, i32 8), align 32 - store i256 %11, ptr getelementptr inbounds ([10 x i256], ptr @extra_abi_data, i256 0, i32 9), align 32 - %is_deploy_code_call_flag_truncated = and i256 %1, 1 - %is_deploy_code_call_flag = icmp eq i256 %is_deploy_code_call_flag_truncated, 1 - br i1 %is_deploy_code_call_flag, label %deploy_code_call_block, label %runtime_code_call_block - -return: ; preds = %runtime_code_call_block, %deploy_code_call_block - ret i256 0 - -deploy_code_call_block: ; preds = %entry - call void @__deploy() - br label %return - -runtime_code_call_block: ; preds = %entry - call void @__runtime() - br label %return -} - -; Function Attrs: nofree null_pointer_is_valid -define private void @__deploy() #8 personality ptr @__personality { -entry: - call void @main(i1 true) - br label %return - -return: ; preds = %entry - ret void -} - -; Function Attrs: nofree null_pointer_is_valid -define private void @__runtime() #8 personality ptr @__personality { -entry: - call void @main(i1 false) - br label %return - -return: ; preds = %entry - ret void -} - -; Function Attrs: nofree null_pointer_is_valid -define private void @main(i1 %0) #8 personality ptr @__personality { ; 6 cells are allocated at the beginning of the function. -entry: - %stack_var_000 = alloca i256, align 32 - store i256 0, ptr %stack_var_000, align 32 - %stack_var_001 = alloca i256, align 32 - store i256 0, ptr %stack_var_001, align 32 - %stack_var_002 = alloca i256, align 32 - store i256 0, ptr %stack_var_002, align 32 - %stack_var_003 = alloca i256, align 32 - store i256 0, ptr %stack_var_003, align 32 - %stack_var_004 = alloca i256, align 32 - store i256 0, ptr %stack_var_004, align 32 - %stack_var_005 = alloca i256, align 32 - store i256 0, ptr %stack_var_005, align 32 - br i1 %0, label %"block_dt_0/0", label %"block_rt_0/0" - -return: ; No predecessors! - ret void - -"block_dt_0/0": ; preds = %entry - store i256 128, ptr %stack_var_000, align 32 - store i256 64, ptr %stack_var_001, align 32 - %argument_0 = load i256, ptr %stack_var_001, align 32 - %argument_1 = load i256, ptr %stack_var_000, align 32 - %memory_store_pointer = inttoptr i256 %argument_0 to ptr addrspace(1) - store i256 %argument_1, ptr addrspace(1) %memory_store_pointer, align 1 - %get_u128_value = call i256 @llvm.syncvm.getu128() - store i256 %get_u128_value, ptr %stack_var_000, align 32 - %dup1 = load i256, ptr %stack_var_000, align 32 - store i256 %dup1, ptr %stack_var_001, align 32 - %argument_01 = load i256, ptr %stack_var_001, align 32 - %comparison_result = icmp eq i256 %argument_01, 0 - %comparison_result_extended = zext i1 %comparison_result to i256 - store i256 %comparison_result_extended, ptr %stack_var_001, align 32 - store i256 1, ptr %stack_var_002, align 32 - %conditional_dt_1_condition = load i256, ptr %stack_var_001, align 32 - %conditional_dt_1_condition_compared = icmp ne i256 %conditional_dt_1_condition, 0 - br i1 %conditional_dt_1_condition_compared, label %"block_dt_1/0", label %conditional_dt_1_join_block - -"block_dt_1/0": ; preds = %"block_dt_0/0" - store i256 0, ptr %stack_var_000, align 32 - %dup15 = load i256, ptr %stack_var_000, align 32 - store i256 %dup15, ptr %stack_var_001, align 32 - store i256 0, ptr %stack_var_002, align 32 - store i256 0, ptr %stack_var_003, align 32 - %argument_06 = load i256, ptr %stack_var_003, align 32 - %argument_17 = load i256, ptr %stack_var_002, align 32 - %argument_2 = load i256, ptr %stack_var_001, align 32 - %calldata_copy_destination_pointer = inttoptr i256 %argument_06 to ptr addrspace(1) - %calldata_pointer = load ptr addrspace(3), ptr @ptr_calldata, align 32 - %calldata_source_pointer = getelementptr i8, ptr addrspace(3) %calldata_pointer, i256 %argument_17 - call void @llvm.memcpy.p1.p3.i256(ptr addrspace(1) align 1 %calldata_copy_destination_pointer, ptr addrspace(3) align 1 %calldata_source_pointer, i256 %argument_2, i1 false) - store i256 0, ptr %stack_var_001, align 32 - %argument_08 = load i256, ptr %stack_var_001, align 32 - %argument_19 = load i256, ptr %stack_var_000, align 32 - store i256 32, ptr addrspace(2) inttoptr (i256 256 to ptr addrspace(2)), align 1 - store i256 0, ptr addrspace(2) inttoptr (i256 288 to ptr addrspace(2)), align 1 - call void @__return(i256 256, i256 64, i256 2) - unreachable - -"block_rt_0/0": ; preds = %entry - store i256 128, ptr %stack_var_000, align 32 - store i256 64, ptr %stack_var_001, align 32 - %argument_010 = load i256, ptr %stack_var_001, align 32 - %argument_111 = load i256, ptr %stack_var_000, align 32 - %memory_store_pointer12 = inttoptr i256 %argument_010 to ptr addrspace(1) - store i256 %argument_111, ptr addrspace(1) %memory_store_pointer12, align 1 - %get_u128_value13 = call i256 @llvm.syncvm.getu128() - store i256 %get_u128_value13, ptr %stack_var_000, align 32 - %dup114 = load i256, ptr %stack_var_000, align 32 - store i256 %dup114, ptr %stack_var_001, align 32 - %argument_015 = load i256, ptr %stack_var_001, align 32 - %comparison_result16 = icmp eq i256 %argument_015, 0 - %comparison_result_extended17 = zext i1 %comparison_result16 to i256 - store i256 %comparison_result_extended17, ptr %stack_var_001, align 32 - store i256 1, ptr %stack_var_002, align 32 - %conditional_rt_1_condition = load i256, ptr %stack_var_001, align 32 - %conditional_rt_1_condition_compared = icmp ne i256 %conditional_rt_1_condition, 0 - br i1 %conditional_rt_1_condition_compared, label %"block_rt_1/0", label %conditional_rt_1_join_block - -"block_rt_1/0": ; preds = %"block_rt_0/0" - store i256 4, ptr %stack_var_000, align 32 - %calldatasize = load i256, ptr @calldatasize, align 32 - store i256 %calldatasize, ptr %stack_var_001, align 32 - %argument_021 = load i256, ptr %stack_var_001, align 32 - %argument_122 = load i256, ptr %stack_var_000, align 32 - %comparison_result23 = icmp ult i256 %argument_021, %argument_122 - %comparison_result_extended24 = zext i1 %comparison_result23 to i256 - store i256 %comparison_result_extended24, ptr %stack_var_000, align 32 - store i256 2, ptr %stack_var_001, align 32 - %conditional_rt_2_condition = load i256, ptr %stack_var_000, align 32 - %conditional_rt_2_condition_compared = icmp ne i256 %conditional_rt_2_condition, 0 - br i1 %conditional_rt_2_condition_compared, label %"block_rt_2/0", label %conditional_rt_2_join_block - -"block_rt_2/0": ; preds = %"block_rt_1/0" - store i256 0, ptr %stack_var_000, align 32 - %dup134 = load i256, ptr %stack_var_000, align 32 - store i256 %dup134, ptr %stack_var_001, align 32 - %argument_035 = load i256, ptr %stack_var_001, align 32 - %argument_136 = load i256, ptr %stack_var_000, align 32 - call void @__revert(i256 %argument_035, i256 %argument_136, i256 0) - unreachable - -"block_rt_2/1": ; preds = %conditional_rt_3_join_block - store i256 0, ptr %stack_var_001, align 32 - %dup137 = load i256, ptr %stack_var_001, align 32 - store i256 %dup137, ptr %stack_var_002, align 32 - %argument_038 = load i256, ptr %stack_var_002, align 32 - %argument_139 = load i256, ptr %stack_var_001, align 32 - call void @__revert(i256 %argument_038, i256 %argument_139, i256 0) - unreachable - -"block_rt_3/0": ; preds = %conditional_rt_2_join_block - store i256 4, ptr %stack_var_001, align 32 - store i256 5, ptr %stack_var_002, align 32 - br label %"block_rt_5/0" - -"block_rt_4/0": ; preds = %"block_rt_5/0" - store i256 64, ptr %stack_var_002, align 32 - %dup140 = load i256, ptr %stack_var_002, align 32 - store i256 %dup140, ptr %stack_var_003, align 32 - %argument_041 = load i256, ptr %stack_var_003, align 32 - %memory_load_pointer = inttoptr i256 %argument_041 to ptr addrspace(1) - %memory_load_result = load i256, ptr addrspace(1) %memory_load_pointer, align 1 - store i256 %memory_load_result, ptr %stack_var_003, align 32 - %swap2_top_value = load i256, ptr %stack_var_003, align 32 - %swap2_swap_value = load i256, ptr %stack_var_001, align 32 - store i256 %swap2_swap_value, ptr %stack_var_003, align 32 - store i256 %swap2_top_value, ptr %stack_var_001, align 32 - %dup3 = load i256, ptr %stack_var_001, align 32 - store i256 %dup3, ptr %stack_var_004, align 32 - %argument_042 = load i256, ptr %stack_var_004, align 32 - %argument_143 = load i256, ptr %stack_var_003, align 32 - %memory_store_pointer44 = inttoptr i256 %argument_042 to ptr addrspace(1) - store i256 %argument_143, ptr addrspace(1) %memory_store_pointer44, align 1 - %argument_045 = load i256, ptr %stack_var_002, align 32 - %memory_load_pointer46 = inttoptr i256 %argument_045 to ptr addrspace(1) - %memory_load_result47 = load i256, ptr addrspace(1) %memory_load_pointer46, align 1 - store i256 %memory_load_result47, ptr %stack_var_002, align 32 - %swap1_top_value = load i256, ptr %stack_var_002, align 32 - %swap1_swap_value = load i256, ptr %stack_var_001, align 32 - store i256 %swap1_swap_value, ptr %stack_var_002, align 32 - store i256 %swap1_top_value, ptr %stack_var_001, align 32 - %dup2 = load i256, ptr %stack_var_001, align 32 - store i256 %dup2, ptr %stack_var_003, align 32 - %swap1_top_value48 = load i256, ptr %stack_var_003, align 32 - %swap1_swap_value49 = load i256, ptr %stack_var_002, align 32 - store i256 %swap1_swap_value49, ptr %stack_var_003, align 32 - store i256 %swap1_top_value48, ptr %stack_var_002, align 32 - %argument_050 = load i256, ptr %stack_var_003, align 32 - %argument_151 = load i256, ptr %stack_var_002, align 32 - %subtraction_result = sub i256 %argument_050, %argument_151 - store i256 %subtraction_result, ptr %stack_var_002, align 32 - store i256 32, ptr %stack_var_003, align 32 - %argument_052 = load i256, ptr %stack_var_003, align 32 - %argument_153 = load i256, ptr %stack_var_002, align 32 - %addition_result = add i256 %argument_052, %argument_153 - store i256 %addition_result, ptr %stack_var_002, align 32 - %swap1_top_value54 = load i256, ptr %stack_var_002, align 32 - %swap1_swap_value55 = load i256, ptr %stack_var_001, align 32 - store i256 %swap1_swap_value55, ptr %stack_var_002, align 32 - store i256 %swap1_top_value54, ptr %stack_var_001, align 32 - %argument_056 = load i256, ptr %stack_var_002, align 32 - %argument_157 = load i256, ptr %stack_var_001, align 32 - call void @__return(i256 %argument_056, i256 %argument_157, i256 0) - unreachable - -"block_rt_5/0": ; preds = %"block_rt_3/0" - store i256 42, ptr %stack_var_002, align 32 - %swap1_top_value58 = load i256, ptr %stack_var_002, align 32 - %swap1_swap_value59 = load i256, ptr %stack_var_001, align 32 - store i256 %swap1_swap_value59, ptr %stack_var_002, align 32 - store i256 %swap1_top_value58, ptr %stack_var_001, align 32 - br label %"block_rt_4/0" - -conditional_dt_1_join_block: ; preds = %"block_dt_0/0" - store i256 0, ptr %stack_var_001, align 32 - %dup12 = load i256, ptr %stack_var_001, align 32 - store i256 %dup12, ptr %stack_var_002, align 32 - %argument_03 = load i256, ptr %stack_var_002, align 32 - %argument_14 = load i256, ptr %stack_var_001, align 32 - call void @__revert(i256 %argument_03, i256 %argument_14, i256 0) - unreachable - -conditional_rt_1_join_block: ; preds = %"block_rt_0/0" - store i256 0, ptr %stack_var_001, align 32 - %dup118 = load i256, ptr %stack_var_001, align 32 - store i256 %dup118, ptr %stack_var_002, align 32 - %argument_019 = load i256, ptr %stack_var_002, align 32 - %argument_120 = load i256, ptr %stack_var_001, align 32 - call void @__revert(i256 %argument_019, i256 %argument_120, i256 0) - unreachable - -conditional_rt_2_join_block: ; preds = %"block_rt_1/0" - store i256 0, ptr %stack_var_000, align 32 - %argument_025 = load i256, ptr %stack_var_000, align 32 - %calldata_pointer26 = load ptr addrspace(3), ptr @ptr_calldata, align 32 - %calldata_pointer_with_offset = getelementptr i8, ptr addrspace(3) %calldata_pointer26, i256 %argument_025 - %calldata_value = load i256, ptr addrspace(3) %calldata_pointer_with_offset, align 32 - store i256 %calldata_value, ptr %stack_var_000, align 32 - store i256 224, ptr %stack_var_001, align 32 - %argument_027 = load i256, ptr %stack_var_001, align 32 - %argument_128 = load i256, ptr %stack_var_000, align 32 - %shr_call = call i256 @__shr(i256 %argument_027, i256 %argument_128) - store i256 %shr_call, ptr %stack_var_000, align 32 - %dup129 = load i256, ptr %stack_var_000, align 32 - store i256 %dup129, ptr %stack_var_001, align 32 - store i256 1519042605, ptr %stack_var_002, align 32 - %argument_030 = load i256, ptr %stack_var_002, align 32 - %argument_131 = load i256, ptr %stack_var_001, align 32 - %comparison_result32 = icmp eq i256 %argument_030, %argument_131 - %comparison_result_extended33 = zext i1 %comparison_result32 to i256 - store i256 %comparison_result_extended33, ptr %stack_var_001, align 32 - store i256 3, ptr %stack_var_002, align 32 - %conditional_rt_3_condition = load i256, ptr %stack_var_001, align 32 - %conditional_rt_3_condition_compared = icmp ne i256 %conditional_rt_3_condition, 0 - br i1 %conditional_rt_3_condition_compared, label %"block_rt_3/0", label %conditional_rt_3_join_block - -conditional_rt_3_join_block: ; preds = %conditional_rt_2_join_block - br label %"block_rt_2/1" -} - -attributes #0 = { nounwind } -attributes #1 = { nounwind readnone } -attributes #2 = { nounwind readonly } -attributes #3 = { writeonly } -attributes #4 = { argmemonly nocallback nofree nounwind willreturn } -attributes #5 = { noprofile } -attributes #6 = { mustprogress nofree nounwind null_pointer_is_valid readnone willreturn } -attributes #7 = { mustprogress nofree nounwind null_pointer_is_valid willreturn } -attributes #8 = { nofree null_pointer_is_valid } -``` - -### Optimized LLVM IR - -The redundancy is optimized by LLVM, resulting in the optimized LLVM IR below. - -```c++ -; Function Attrs: nofree noreturn null_pointer_is_valid -define i256 @__entry(ptr addrspace(3) %0, i256 %1, i256 %2, i256 %3, i256 %4, i256 %5, i256 %6, i256 %7, i256 %8, i256 %9, i256 %10, i256 %11) local_unnamed_addr #1 personality ptr @__personality { -entry: - store ptr addrspace(3) %0, ptr @ptr_calldata, align 32 - %abi_pointer_value = ptrtoint ptr addrspace(3) %0 to i256 - %abi_pointer_value_shifted = lshr i256 %abi_pointer_value, 96 - %abi_length_value = and i256 %abi_pointer_value_shifted, 4294967295 - store i256 %abi_length_value, ptr @calldatasize, align 32 - %is_deploy_code_call_flag_truncated = and i256 %1, 1 - %is_deploy_code_call_flag.not = icmp eq i256 %is_deploy_code_call_flag_truncated, 0 - store i256 128, ptr addrspace(1) inttoptr (i256 64 to ptr addrspace(1)), align 64 - %get_u128_value.i.i1 = tail call i256 @llvm.syncvm.getu128() - br i1 %is_deploy_code_call_flag.not, label %runtime_code_call_block, label %deploy_code_call_block - -deploy_code_call_block: ; preds = %entry - %comparison_result.i.i = icmp eq i256 %get_u128_value.i.i1, 0 - br i1 %comparison_result.i.i, label %"block_dt_1/0.i.i", label %"block_rt_2/0.i.i" - -"block_dt_1/0.i.i": ; preds = %deploy_code_call_block - store i256 32, ptr addrspace(2) inttoptr (i256 256 to ptr addrspace(2)), align 256 - store i256 0, ptr addrspace(2) inttoptr (i256 288 to ptr addrspace(2)), align 32 - tail call void @llvm.syncvm.return(i256 53919893334301279589334030174039261352344891250716429051063678533632) - unreachable - -"block_rt_2/0.i.i": ; preds = %runtime_code_call_block, %conditional_rt_2_join_block.i.i, %deploy_code_call_block - tail call void @llvm.syncvm.revert(i256 0) - unreachable - -runtime_code_call_block: ; preds = %entry - %comparison_result.i.i2 = icmp ne i256 %get_u128_value.i.i1, 0 - %calldatasize.i.i = load i256, ptr @calldatasize, align 32 - %comparison_result23.i.i = icmp ult i256 %calldatasize.i.i, 4 - %or.cond.i.i = select i1 %comparison_result.i.i2, i1 true, i1 %comparison_result23.i.i - br i1 %or.cond.i.i, label %"block_rt_2/0.i.i", label %conditional_rt_2_join_block.i.i - -"block_rt_3/0.i.i": ; preds = %conditional_rt_2_join_block.i.i - %memory_load_result.i.i = load i256, ptr addrspace(1) inttoptr (i256 64 to ptr addrspace(1)), align 64 - %memory_store_pointer44.i.i = inttoptr i256 %memory_load_result.i.i to ptr addrspace(1) - store i256 42, ptr addrspace(1) %memory_store_pointer44.i.i, align 1 - %memory_load_result47.i.i = load i256, ptr addrspace(1) inttoptr (i256 64 to ptr addrspace(1)), align 64 - %subtraction_result.i.i = add i256 %memory_load_result.i.i, 32 - %addition_result.i.i = sub i256 %subtraction_result.i.i, %memory_load_result47.i.i - %12 = tail call i256 @llvm.umin.i256(i256 %memory_load_result47.i.i, i256 4294967295) - %13 = tail call i256 @llvm.umin.i256(i256 %addition_result.i.i, i256 4294967295) - %offset_shifted.i.i.i.i = shl nuw nsw i256 %12, 64 - %length_shifted.i.i.i.i = shl nuw nsw i256 %13, 96 - %tmp.i.i.i.i = or i256 %length_shifted.i.i.i.i, %offset_shifted.i.i.i.i - tail call void @llvm.syncvm.return(i256 %tmp.i.i.i.i) - unreachable - -conditional_rt_2_join_block.i.i: ; preds = %runtime_code_call_block - %calldata_pointer26.i.i = load ptr addrspace(3), ptr @ptr_calldata, align 32 - %calldata_value.i.i = load i256, ptr addrspace(3) %calldata_pointer26.i.i, align 32 - %shift_res.i.mask.i.i = and i256 %calldata_value.i.i, -26959946667150639794667015087019630673637144422540572481103610249216 - %comparison_result32.i.i = icmp eq i256 %shift_res.i.mask.i.i, 40953307615929575801107647705360601464619672688377251939886941387873771847680 - br i1 %comparison_result32.i.i, label %"block_rt_3/0.i.i", label %"block_rt_2/0.i.i" -} - -attributes #0 = { nounwind } -attributes #1 = { nofree noreturn null_pointer_is_valid } -attributes #2 = { noreturn nounwind } -attributes #3 = { nocallback nofree nosync nounwind readnone speculatable willreturn } -``` - -### EraVM Assembly - -The optimized LLVM IR is translated into EraVM assembly below, allowing the size comparable to the Yul pipeline. - -```asm - .text - .file "default.sol:Test" - .globl __entry -__entry: -.func_begin0: - ptr.add r1, r0, stack[@ptr_calldata] - shr.s 96, r1, r1 - and @CPI0_0[0], r1, stack[@calldatasize] - add 128, r0, r1 - st.1 64, r1 - context.get_context_u128 r1 - and! 1, r2, r2 - jump.ne @.BB0_1 - sub! r1, r0, r1 - jump.ne @.BB0_3 - add stack[@calldatasize], r0, r1 - sub.s! 4, r1, r1 - jump.lt @.BB0_3 - ptr.add stack[@ptr_calldata], r0, r1 - ld r1, r1 - and @CPI0_2[0], r1, r1 - sub.s! @CPI0_3[0], r1, r1 - jump.ne @.BB0_3 - ld.1 64, r1 - add 42, r0, r2 - st.1 r1, r2 - ld.1 64, r2 - sub r1, r2, r1 - add 32, r1, r1 - add @CPI0_0[0], r0, r3 - sub.s! @CPI0_0[0], r1, r4 - add.ge r3, r0, r1 - sub.s! @CPI0_0[0], r2, r4 - add.ge r3, r0, r2 - shl.s 64, r2, r2 - shl.s 96, r1, r1 - or r1, r2, r1 - ret.ok.to_label r1, @DEFAULT_FAR_RETURN -.BB0_1: - sub! r1, r0, r1 - jump.ne @.BB0_3 - add 32, r0, r1 - st.2 256, r1 - st.2 288, r0 - add @CPI0_1[0], r0, r1 - ret.ok.to_label r1, @DEFAULT_FAR_RETURN -.BB0_3: - add r0, r0, r1 - ret.revert.to_label r1, @DEFAULT_FAR_REVERT -.func_end0: - - .data - .p2align 5 -calldatasize: - .cell 0 - - .p2align 5 -ptr_calldata: -.cell 0 - - .note.GNU-stack - .rodata -CPI0_0: - .cell 4294967295 -CPI0_1: - .cell 53919893334301279589334030174039261352344891250716429051063678533632 -CPI0_2: - .cell -26959946667150639794667015087019630673637144422540572481103610249216 -CPI0_3: - .cell 40953307615929575801107647705360601464619672688377251939886941387873771847680 -``` - -For comparison, the Yul pipeline of solc v0.8.21 produces the following EraVM assembly: - -```asm - .text - .file "default.sol:Test" - .globl __entry -__entry: -.func_begin0: - ptr.add r1, r0, stack[@ptr_calldata] - shr.s 96, r1, r1 - and @CPI0_0[0], r1, stack[@calldatasize] - add 128, r0, r1 - st.1 64, r1 - and! 1, r2, r1 - jump.ne @.BB0_1 - add stack[@calldatasize], r0, r1 - sub.s! 4, r1, r1 - jump.lt @.BB0_2 - ptr.add stack[@ptr_calldata], r0, r1 - ld r1, r1 - and @CPI0_2[0], r1, r1 - sub.s! @CPI0_3[0], r1, r1 - jump.ne @.BB0_2 - context.get_context_u128 r1 - sub! r1, r0, r1 - jump.ne @.BB0_2 - sub.s 4, r0, r1 - add stack[@calldatasize], r1, r1 - add @CPI0_4[0], r0, r2 - sub! r1, r0, r3 - add r0, r0, r3 - add.lt r2, r0, r3 - and @CPI0_4[0], r1, r1 - sub! r1, r0, r4 - add.le r0, r0, r2 - sub.s! @CPI0_4[0], r1, r1 - add r3, r0, r1 - add.eq r2, r0, r1 - sub! r1, r0, r1 - jump.ne @.BB0_2 - add 42, r0, r1 - st.1 128, r1 - add @CPI0_5[0], r0, r1 - ret.ok.to_label r1, @DEFAULT_FAR_RETURN -.BB0_1: - context.get_context_u128 r1 - sub! r1, r0, r1 - jump.ne @.BB0_2 - add 32, r0, r1 - st.2 256, r1 - st.2 288, r0 - add @CPI0_1[0], r0, r1 - ret.ok.to_label r1, @DEFAULT_FAR_RETURN -.BB0_2: - add r0, r0, r1 - ret.revert.to_label r1, @DEFAULT_FAR_REVERT -.func_end0: - - .data - .p2align 5 -calldatasize: - .cell 0 - - .p2align 5 -ptr_calldata: -.cell 0 - - .note.GNU-stack - .rodata -CPI0_0: - .cell 4294967295 -CPI0_1: - .cell 53919893334301279589334030174039261352344891250716429051063678533632 -CPI0_2: - .cell -26959946667150639794667015087019630673637144422540572481103610249216 -CPI0_3: - .cell 40953307615929575801107647705360601464619672688377251939886941387873771847680 -CPI0_4: - .cell -57896044618658097711785492504343953926634992332820282019728792003956564819968 -CPI0_5: - .cell 2535301202817642044428229017600 -``` diff --git a/content/40.zk-stack/components/compiler/specification/exception-handling.md b/content/40.zk-stack/components/compiler/specification/exception-handling.md deleted file mode 100644 index c8b7c503..00000000 --- a/content/40.zk-stack/components/compiler/specification/exception-handling.md +++ /dev/null @@ -1,137 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Exception Handling | zkSync Docs ---- - -# Exception Handling - -This document explains some peculiarities of the exception handling (EH) in zkEVM architecture. - -In a nutshell, there are two EH mechanisms in zkEVM: contract-level and function-level. The former was inherited from -the EVM architecture, and the latter is more common to general-purpose languages. - -| | Contract Level | Function Level | -| ------------ | --------------- | ----------------------------------------------------------------------------------------------------- | -| Yul Example | revert(0, 0) | verbatim("throw") | -| Native to | EVM | General-purpose languages | -| Handled by | zkEVM | Compiler | -| Catchable by | Caller contract | Caller function | -| Efficient | Yes | Huge size impact due to numerous catch blocks. Extra cycles are needed for propagating the exception. | - -## Contract Level - -This type of exceptions is inherited from the EVM architecture. On EVM, such instructions as `REVERT` and `INVALID`, -immediately terminate the contract execution and return the control to the callee. It is impossible to catch them within -the contract, and it can be only done on the callee side with checking the call status code. - -```solidity -// callee -revert(0, 0) - -// caller -let success = call(...) -if iszero(success) { - // option 1: rethrow on the contract level - returndatacopy(...) - revert(...) - - // option 2: rethrow on the function level - verbatim("throw") // only available in the Yul mode and upcoming zkEVM solc -} -``` - -zkEVM behaves exactly the same. The VM automatically unwinds the call stack up to the uppermost function frame of the -contract, leaving no possibility to catch and handle it on the way. - -These types of exceptions are more efficient, as you can revert at any point of the execution without propagating the -control flow all the way up to the uppermost function frame. - -### Implementation - -In EraVM, contracts call each other using -[`far_call` instruction](https://matter-labs.github.io/eravm-spec/spec.html#FarCalls). It -[accepts the address of the exception handler](https://matter-labs.github.io/eravm-spec/spec.html#OpFarCall) as one of -its arguments. - -## Function Level - -This type of exceptions is more common to general-purpose languages like C++. That is why it was easy to support within -the LLVM framework, even though it is not supported by the smart contract languages we work with. That is also one of -the reasons why the two EH mechanisms are handled separately and barely interact in the high-level code. - -In general-purpose languages a set of EH tools is usually available, e.g. `try` , `throw`, and `catch` keywords that -define which piece of code may throw and how the exception must be handled. However, these tools are not available in -Solidity and its EVM Yul dialect, so some extensions have been added in the zkEVM Yul dialect compiled by zksolc, but -there are limitations, some of which are dictated by the nature of smart contracts: - -1. Every function beginning with `ZKSYNC_NEAR_CALL` is implicitly wrapped with `try`. If there is an exception handler - defined, the following will happen: - - A panic will be caught by the caller of such function. - - The control will be transferred to EH function. There can be only one EH function and it must be named - `ZKSYNC_CATCH_NEAR_CALL`. It is not very efficient, because all functions must have an LLVM IR `catch` block that - will catch and propagate the exception and call the EH function. - - When the EH function has finished executing, the caller of `ZKSYNC_NEAR_CALL` receives the control back. -2. Every operation is `throw`. Since any instruction can panic due to out-of-gas, all of them can throw. It is another - thing reducing the potential for optimizations. -3. The `catch` block is represented by the `ZKSYNC_CATCH_NEAR_CALL` function in Yul. A panic in `ZKSYNC_NEAR_CALL` will - make **their caller** catch the exception and call the EH function. After the EH function is executed, the control is - returned to the caller of `ZKSYNC_NEAR_CALL`. - -```solidity -// Follow the numbers for the order of execution. The call order is: -// caller -> ZKSYNC_NEAR_CALL_callee -> callee_even_deeper -> ZKSYNC_CATCH_NEAR_CALL -> caller - -function ZKSYNC_NEAR_CALL_callee() -> value { // 03 - value := callee_even_deeper() // 04 -} - -function callee_even_deeper() -> value { // 05 - verbatim("throw") // 06 -} - -// In every function an implicit 'catch' block in LLVM IR is created. -// This block will do the following: -// 1. Keep the return value ('zero') zero-initialized if one is expected -// 2. Call the EH function ('ZKSYNC_CATCH_NEAR_CALL') -// 3. Return the control flow to the next instruction ('value := 42') -function caller() -> value { // 01 - let zero := ZKSYNC_NEAR_CALL_callee() // 02 - value := 42 // 09 -} - -// This handler could also be doing a revert. -// Reverts in EH functions work in the same way as without EH at all. -// They immediately terminate the execution and the control is given to the contract callee. -function ZKSYNC_CATCH_NEAR_CALL() { // 07 - log0(...) // 08 -} -``` - -Having all the overhead above, the `catch` blocks are only generated if there is the EH function -`ZKSYNC_CATCH_NEAR_CALL` defined in the contract. Otherwise there is no need to catch panics and they will be propagated -to the callee contract automatically by the VM execution environment. - -### Implementation - -In EraVM, there are two ways of implementing contract-local function calls: - -1. Saving the return address and using a [`jump`](https://matter-labs.github.io/eravm-spec/spec.html#JumpDefinition) - instruction to call; using [`jump`](https://matter-labs.github.io/eravm-spec/spec.html#JumpDefinition) instruction - with saved return address to return. -2. Using [`call`](https://matter-labs.github.io/eravm-spec/spec.html#NearCallDefinition) instruction to call; using one - of `ret` instructions with modifiers [`ok`](https://matter-labs.github.io/eravm-spec/spec.html#NearRetDefinition), - [`revert`](https://matter-labs.github.io/eravm-spec/spec.html#NearRevertDefinition), or - [`panic`](https://matter-labs.github.io/eravm-spec/spec.html#step_oppanic) to return. - -Using `jump` is more lightweight and cheaper, but using `call`/`ret` is more feature-rich: - -1. In case of panic or revert, the storage effects and queues of this function are rolled back. -2. It is possible to pass a portion of available gas; the unused gas will be returned to the caller, unless the function - panicked. -3. It is possible to set up a custom exception handler. - -Prefixing Yul function name with `ZKSYNC_NEAR_CALL_` allows to use this additional, platform-specific functionality, -implemented by the `call` instruction. For other functions, the choice between `call`/`ret` or `jump` is up to the -compiler. diff --git a/content/40.zk-stack/components/compiler/specification/instructions/evm/arithmetic.md b/content/40.zk-stack/components/compiler/specification/instructions/evm/arithmetic.md deleted file mode 100644 index a783c585..00000000 --- a/content/40.zk-stack/components/compiler/specification/instructions/evm/arithmetic.md +++ /dev/null @@ -1,388 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Arithmetic | zkSync Docs ---- - -# Arithmetic Instructions - -## ADD - -Original [EVM](https://www.evm.codes/#01?fork=shanghai) instruction. - -### LLVM IR - -```c++ -%addition_result = add i256 %value1, %value2 -``` - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/arithmetic.rs#L15) -is common for Yul and EVMLA representations. - -[LLVM IR instruction documentation](https://releases.llvm.org/15.0.0/docs/LangRef.html#add-instruction) - -### EraVM Assembly - -```asm -add r1, r2, r1 -``` - -For more detail, see the -[EraVM specification reference](https://matter-labs.github.io/eravm-spec/spec.html#AddDefinition) - -## MUL - -Original [EVM](https://www.evm.codes/#02?fork=shanghai) instruction. - -### Differences from EVM - -1. The carry is written to the 2nd output register - -### LLVM IR - -```c++ -%multiplication_result = mul i256 %value1, %value2 -``` - -EraVM can output the carry of the multiplication operation. In this case, the result is a tuple of two values: the -multiplication result and the carry. The carry is written to the 2nd output register. The snippet below returns the -carry value. - -```c++ -%value1_extended = zext i256 %value1 to i512 -%value2_extended = zext i256 %value2 to i512 -%result_extended = mul nuw i512 %value1_extended, %value2_extended -%result_shifted = lshr i512 %result_extended, 256 -%result = trunc i512 %result_shifted to i256 -``` - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/arithmetic.rs#L53) -is common for Yul and EVMLA representations. - -[LLVM IR instruction documentation](https://releases.llvm.org/15.0.0/docs/LangRef.html#mul-instruction) - -### EraVM Assembly - -```asm -mul r1, r2, r1, r2 -``` - -For more detail, see the -[EraVM specification reference](https://matter-labs.github.io/eravm-spec/spec.html#MulDefinition) - -## SUB - -Original [EVM](https://www.evm.codes/#03?fork=shanghai) instruction. - -### LLVM IR - -```c++ -%subtraction_result = sub i256 %value1, %value2 -``` - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/arithmetic.rs#L34) -is common for Yul and EVMLA representations. - -[LLVM IR instruction documentation](https://releases.llvm.org/15.0.0/docs/LangRef.html#sub-instruction) - -### EraVM Assembly - -```asm -sub r1, r2, r1 -``` - -For more detail, see the -[EraVM specification reference](https://matter-labs.github.io/eravm-spec/spec.html#SubDefinition) - -## DIV - -Original [EVM](https://www.evm.codes/#04?fork=shanghai) instruction. - -### Differences from EVM - -1. The remainder is written to the 2nd output register - -### LLVM IR - -```c++ -define i256 @__div(i256 %arg1, i256 %arg2) #0 { -entry: - %is_divider_zero = icmp eq i256 %arg2, 0 - br i1 %is_divider_zero, label %return, label %division - -division: - %div_res = udiv i256 %arg1, %arg2 - br label %return - -return: - %res = phi i256 [ 0, %entry ], [ %div_res, %division ] - ret i256 %res -} -``` - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/arithmetic.rs#L73) -is common for Yul and EVMLA representations. - -[LLVM IR instruction documentation](https://releases.llvm.org/15.0.0/docs/LangRef.html#udiv-instruction) - -For more detail, see the -[EraVM specification reference](https://matter-labs.github.io/eravm-spec/spec.html#DivDefinition) - -## SDIV - -Original [EVM](https://www.evm.codes/#05?fork=shanghai) instruction. - -### LLVM IR - -```c++ -define i256 @__sdiv(i256 %arg1, i256 %arg2) #0 { -entry: - %is_divider_zero = icmp eq i256 %arg2, 0 - br i1 %is_divider_zero, label %return, label %division_overflow - -division_overflow: - %is_divided_int_min = icmp eq i256 %arg1, -57896044618658097711785492504343953926634992332820282019728792003956564819968 - %is_minus_one = icmp eq i256 %arg2, -1 - %is_overflow = and i1 %is_divided_int_min, %is_minus_one - br i1 %is_overflow, label %return, label %division - -division: - %div_res = sdiv i256 %arg1, %arg2 - br label %return - -return: - %res = phi i256 [ 0, %entry ], [ %arg1, %division_overflow ], [ %div_res, %division ] - ret i256 %res -} -``` - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/arithmetic.rs#L162) -is common for Yul and EVMLA representations. - -[LLVM IR instruction documentation](https://releases.llvm.org/15.0.0/docs/LangRef.html#sdiv-instruction) - -EraVM does not have a similar instruction. - -## MOD - -Original [EVM](https://www.evm.codes/#06?fork=shanghai) instruction. - -### Differences from EVM - -1. The remainder is written to the 2nd output register - -### LLVM IR - -```c++ -define i256 @__mod(i256 %arg1, i256 %arg2) #0 { -entry: - %is_divider_zero = icmp eq i256 %arg2, 0 - br i1 %is_divider_zero, label %return, label %remainder - -remainder: - %rem_res = urem i256 %arg1, %arg2 - br label %return - -return: - %res = phi i256 [ 0, %entry ], [ %rem_res, %remainder ] - ret i256 %res -} -``` - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/arithmetic.rs#L117) -is common for Yul and EVMLA representations. - -[LLVM IR instruction documentation](https://releases.llvm.org/15.0.0/docs/LangRef.html#urem-instruction) - -For more detail, see the -[EraVM specification reference](https://matter-labs.github.io/eravm-spec/spec.html#DivDefinition) - -## SMOD - -Original [EVM](https://www.evm.codes/#07?fork=shanghai) instruction. - -### LLVM IR - -```c++ -define i256 @__smod(i256 %arg1, i256 %arg2) #0 { -entry: - %is_divider_zero = icmp eq i256 %arg2, 0 - br i1 %is_divider_zero, label %return, label %division_overflow - -division_overflow: - %is_divided_int_min = icmp eq i256 %arg1, -57896044618658097711785492504343953926634992332820282019728792003956564819968 - %is_minus_one = icmp eq i256 %arg2, -1 - %is_overflow = and i1 %is_divided_int_min, %is_minus_one - br i1 %is_overflow, label %return, label %remainder - -remainder: - %rem_res = srem i256 %arg1, %arg2 - br label %return - -return: - %res = phi i256 [ 0, %entry ], [ 0, %division_overflow ], [ %rem_res, %remainder ] - ret i256 %res -} -``` - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/arithmetic.rs#L236) -is common for Yul and EVMLA representations. - -[LLVM IR instruction documentation](https://releases.llvm.org/15.0.0/docs/LangRef.html#srem-instruction) - -EraVM does not have a similar instruction. - -## ADDMOD - -Original [EVM](https://www.evm.codes/#08?fork=shanghai) instruction. - -### LLVM IR - -```c++ -define i256 @__addmod(i256 %arg1, i256 %arg2, i256 %modulo) #0 { -entry: - %is_zero = icmp eq i256 %modulo, 0 - br i1 %is_zero, label %return, label %addmod - -addmod: - %arg1m = urem i256 %arg1, %modulo - %arg2m = urem i256 %arg2, %modulo - %res = call {i256, i1} @llvm.uadd.with.overflow.i256(i256 %arg1m, i256 %arg2m) - %sum = extractvalue {i256, i1} %res, 0 - %obit = extractvalue {i256, i1} %res, 1 - %sum.mod = urem i256 %sum, %modulo - br i1 %obit, label %overflow, label %return - -overflow: - %mod.inv = xor i256 %modulo, -1 - %sum1 = add i256 %sum, %mod.inv - %sum.ovf = add i256 %sum1, 1 - br label %return - -return: - %value = phi i256 [0, %entry], [%sum.mod, %addmod], [%sum.ovf, %overflow] - ret i256 %value -} -``` - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/math.rs#L16) -is common for Yul and EVMLA representations. - -EraVM does not have a similar instruction. - -## MULMOD - -Original [EVM](https://www.evm.codes/#09?fork=shanghai) instruction. - -### LLVM IR - -```c++ -define i256 @__mulmod(i256 %arg1, i256 %arg2, i256 %modulo) #0 { -entry: - %cccond = icmp eq i256 %modulo, 0 - br i1 %cccond, label %ccret, label %entrycont - -ccret: - ret i256 0 - -entrycont: - %arg1m = urem i256 %arg1, %modulo - %arg2m = urem i256 %arg2, %modulo - %less_then_2_128 = icmp ult i256 %modulo, 340282366920938463463374607431768211456 - br i1 %less_then_2_128, label %fast, label %slow - -fast: - %prod = mul i256 %arg1m, %arg2m - %prodm = urem i256 %prod, %modulo - ret i256 %prodm - -slow: - %arg1e = zext i256 %arg1m to i512 - %arg2e = zext i256 %arg2m to i512 - %prode = mul i512 %arg1e, %arg2e - %prodl = trunc i512 %prode to i256 - %prodeh = lshr i512 %prode, 256 - %prodh = trunc i512 %prodeh to i256 - %res = call i256 @__ulongrem(i256 %prodl, i256 %prodh, i256 %modulo) - ret i256 %res -} -``` - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/math.rs#L43) -is common for Yul and EVMLA representations. - -EraVM does not have a similar instruction. - -## EXP - -Original [EVM](https://www.evm.codes/#0a?fork=shanghai) instruction. - -### LLVM IR - -```c++ -define i256 @__exp(i256 %value, i256 %exp) "noinline-oz" #0 { -entry: - %exp_is_non_zero = icmp eq i256 %exp, 0 - br i1 %exp_is_non_zero, label %return, label %exponent_loop_body - -return: - %exp_res = phi i256 [ 1, %entry ], [ %exp_res.1, %exponent_loop_body ] - ret i256 %exp_res - -exponent_loop_body: - %exp_res.2 = phi i256 [ %exp_res.1, %exponent_loop_body ], [ 1, %entry ] - %exp_val = phi i256 [ %exp_val_halved, %exponent_loop_body ], [ %exp, %entry ] - %val_squared.1 = phi i256 [ %val_squared, %exponent_loop_body ], [ %value, %entry ] - %odd_test = and i256 %exp_val, 1 - %is_exp_odd = icmp eq i256 %odd_test, 0 - %exp_res.1.interm = select i1 %is_exp_odd, i256 1, i256 %val_squared.1 - %exp_res.1 = mul i256 %exp_res.1.interm, %exp_res.2 - %val_squared = mul i256 %val_squared.1, %val_squared.1 - %exp_val_halved = lshr i256 %exp_val, 1 - %exp_val_is_less_2 = icmp ult i256 %exp_val, 2 - br i1 %exp_val_is_less_2, label %return, label %exponent_loop_body -} -``` - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/math.rs#L70) -is common for Yul and EVMLA representations. - -EraVM does not have a similar instruction. - -## SIGNEXTEND - -Original [EVM](https://www.evm.codes/#0b?fork=shanghai) instruction. - -### LLVM IR - -```c++ -define i256 @__signextend(i256 %numbyte, i256 %value) #0 { -entry: - %is_overflow = icmp uge i256 %numbyte, 31 - br i1 %is_overflow, label %return, label %signextend - -signextend: - %numbit_byte = mul nuw nsw i256 %numbyte, 8 - %numbit = add nsw nuw i256 %numbit_byte, 7 - %numbit_inv = sub i256 256, %numbit - %signmask = shl i256 1, %numbit - %valmask = lshr i256 -1, %numbit_inv - %ext1 = shl i256 -1, %numbit - %signv = and i256 %signmask, %value - %sign = icmp ne i256 %signv, 0 - %valclean = and i256 %value, %valmask - %sext = select i1 %sign, i256 %ext1, i256 0 - %result = or i256 %sext, %valclean - br label %return - -return: - %signext_res = phi i256 [%value, %entry], [%result, %signextend] - ret i256 %signext_res -} -``` - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/math.rs#L93) -is common for Yul and EVMLA representations. - -EraVM does not have a similar instruction. diff --git a/content/40.zk-stack/components/compiler/specification/instructions/evm/bitwise.md b/content/40.zk-stack/components/compiler/specification/instructions/evm/bitwise.md deleted file mode 100644 index 650cccb8..00000000 --- a/content/40.zk-stack/components/compiler/specification/instructions/evm/bitwise.md +++ /dev/null @@ -1,229 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Bitwise | zkSync Docs ---- - -# Bitwise Instructions - -## AND - -Original [EVM](https://www.evm.codes/#16?fork=shanghai) instruction. - -### LLVM IR - -```c++ -%and_result = and i256 %value1, %value2 -``` - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/bitwise.rs#L47) -is common for Yul and EVMLA representations. - -[LLVM IR instruction documentation](https://releases.llvm.org/15.0.0/docs/LangRef.html#and-instruction) - -### EraVM Assembly - -```asm -ptr.add stack[@ptr_calldata], r0, r1 -ptr.add.s 36, r1, r2 -ld r2, r2 -ptr.add.s 4, r1, r1 -ld r1, r1 -and r1, r2, r1 -st.1 128, r1 -``` - -[EraVM instruction: `and`](https://matter-labs.github.io/eravm-spec/spec.html#AndDefinition) - -## OR - -Original [EVM](https://www.evm.codes/#17?fork=shanghai) instruction. - -### LLVM IR - -```c++ -%or_result = or i256 %value1, %value2 -``` - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/bitwise.rs#L13) -is common for Yul and EVMLA representations. - -[LLVM IR instruction documentation](https://releases.llvm.org/15.0.0/docs/LangRef.html#or-instruction) - -### EraVM Assembly - -```asm -ptr.add stack[@ptr_calldata], r0, r1 -ptr.add.s 36, r1, r2 -ld r2, r2 -ptr.add.s 4, r1, r1 -ld r1, r1 -or r1, r2, r1 -st.1 128, r1 -``` - -[EraVM instruction: `or`](https://matter-labs.github.io/eravm-spec/spec.html#AndDefinition) - -## XOR - -Original [EVM](https://www.evm.codes/#18?fork=shanghai) instruction. - -### LLVM IR - -```c++ -%xor_result = or i256 %value1, %value2 -``` - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/bitwise.rs#L30) -is common for Yul and EVMLA representations. - -[LLVM IR instruction documentation](https://releases.llvm.org/15.0.0/docs/LangRef.html#xor-instruction) - -### EraVM Assembly - -```asm -ptr.add stack[@ptr_calldata], r0, r1 -ptr.add.s 36, r1, r2 -ld r2, r2 -ptr.add.s 4, r1, r1 -ld r1, r1 -xor r1, r2, r1 -st.1 128, r1 -``` - -[EraVM instruction: `xor`](https://matter-labs.github.io/eravm-spec/spec.html#XorDefinition) - -## NOT - -Original [EVM](https://www.evm.codes/#19?fork=shanghai) instruction. - -### LLVM IR - -```c++ -%xor_result = xor i256 %value, -1 -``` - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/bitwise.rs#L30) -is common for Yul and EVMLA representations. - -### EraVM Assembly - -```asm -ptr.add stack[@ptr_calldata], r1, r1 -ld r1, r1 -sub.s 1, r0, r2 -xor r1, r2, r1 -st.1 128, r1 -``` - -[EraVM instruction: `xor`](https://matter-labs.github.io/eravm-spec/spec.html#XorDefinition) - -## BYTE - -Original [EVM](https://www.evm.codes/#1a?fork=shanghai) instruction. - -### LLVM IR - -```c++ -define i256 @__byte(i256 %index, i256 %value) #0 { -entry: - %is_overflow = icmp ugt i256 %index, 31 - br i1 %is_overflow, label %return, label %extract_byte - -extract_byte: - %bits_offset = shl i256 %index, 3 - %value_shifted_left = shl i256 %value, %bits_offset - %value_shifted_right = lshr i256 %value_shifted_left, 248 - br label %return - -return: - %res = phi i256 [ 0, %entry ], [ %value_shifted_right, %extract_byte ] - ret i256 %res -} -``` - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/bitwise.rs#L229) -is common for Yul and EVMLA representations. - -## SHL - -Original [EVM](https://www.evm.codes/#1b?fork=shanghai) instruction. - -### LLVM IR - -```c++ -define i256 @__shl(i256 %shift, i256 %value) #0 { -entry: - %is_overflow = icmp ugt i256 %shift, 255 - br i1 %is_overflow, label %return, label %shift_value - -shift_value: - %shift_res = shl i256 %value, %shift - br label %return - -return: - %res = phi i256 [ 0, %entry ], [ %shift_res, %shift_value ] - ret i256 %res -} -``` - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/bitwise.rs#L67) -is common for Yul and EVMLA representations. - -## SHR - -Original [EVM](https://www.evm.codes/#1c?fork=shanghai) instruction. - -### LLVM IR - -```c++ -define i256 @__shr(i256 %shift, i256 %value) #0 { -entry: - %is_overflow = icmp ugt i256 %shift, 255 - br i1 %is_overflow, label %return, label %shift_value - -shift_value: - %shift_res = lshr i256 %value, %shift - br label %return - -return: - %res = phi i256 [ 0, %entry ], [ %shift_res, %shift_value ] - ret i256 %res -} -``` - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/bitwise.rs#L111) -is common for Yul and EVMLA representations. - -[EraVM instruction: `xor`](https://matter-labs.github.io/eravm-spec/spec.html#XorDefinition) - -## SAR - -Original [EVM](https://www.evm.codes/#1d?fork=shanghai) instruction. - -### LLVM IR - -```c++ -define i256 @__sar(i256 %shift, i256 %value) #0 { -entry: - %is_overflow = icmp ugt i256 %shift, 255 - br i1 %is_overflow, label %arith_overflow, label %shift_value - -arith_overflow: - %is_val_positive = icmp sge i256 %value, 0 - %res_overflow = select i1 %is_val_positive, i256 0, i256 -1 - br label %return - -shift_value: - %shift_res = ashr i256 %value, %shift - br label %return - -return: - %res = phi i256 [ %res_overflow, %arith_overflow ], [ %shift_res, %shift_value ] - ret i256 %res -} -``` - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/bitwise.rs#L157) -is common for Yul and EVMLA representations. diff --git a/content/40.zk-stack/components/compiler/specification/instructions/evm/block.md b/content/40.zk-stack/components/compiler/specification/instructions/evm/block.md deleted file mode 100644 index dd2fe1ab..00000000 --- a/content/40.zk-stack/components/compiler/specification/instructions/evm/block.md +++ /dev/null @@ -1,176 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Block | zkSync Docs ---- - -# Block Instructions - -## BLOCKHASH - -Original [EVM](https://www.evm.codes/#40?fork=shanghai) instruction. - -### System Contract - -This information is requested a System Contract called -[SystemContext](https://github.com/matter-labs/era-system-contracts/blob/main/contracts/SystemContext.sol). - -On how the System Contract is called, see [this section](../../system-contracts.md#environmental-data-storage). - -### LLVM IR - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/context.rs#L47) -is common for Yul and EVMLA representations. - -The request to the System Contract is done via the -[SystemRequest](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/context/function/runtime/system_request.rs) -runtime function. - -## COINBASE - -Original [EVM](https://www.evm.codes/#41?fork=shanghai) instruction. - -### System Contract - -This information is requested a System Contract called -[SystemContext](https://github.com/matter-labs/era-system-contracts/blob/main/contracts/SystemContext.sol). - -On how the System Contract is called, see [this section](../../system-contracts.md#environmental-data-storage). - -### LLVM IR - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/context.rs#L150) -is common for Yul and EVMLA representations. - -The request to the System Contract is done via the -[SystemRequest](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/context/function/runtime/system_request.rs) -runtime function. - -## TIMESTAMP - -Original [EVM](https://www.evm.codes/#42?fork=shanghai) instruction. - -### System Contract - -This information is requested a System Contract called -[SystemContext](https://github.com/matter-labs/era-system-contracts/blob/main/contracts/SystemContext.sol). - -On how the System Contract is called, see [this section](../../system-contracts.md#environmental-data-storage). - -### LLVM IR - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/context.rs#L98) -is common for Yul and EVMLA representations. - -The request to the System Contract is done via the -[SystemRequest](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/context/function/runtime/system_request.rs) -runtime function. - -## NUMBER - -Original [EVM](https://www.evm.codes/#43?fork=shanghai) instruction. - -### System Contract - -This information is requested a System Contract called -[SystemContext](https://github.com/matter-labs/era-system-contracts/blob/main/contracts/SystemContext.sol). - -On how the System Contract is called, see [this section](../../system-contracts.md#environmental-data-storage). - -### LLVM IR - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/context.rs#L81) -is common for Yul and EVMLA representations. - -The request to the System Contract is done via the -[SystemRequest](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/context/function/runtime/system_request.rs) -runtime function. - -## PREVRANDAO - -Original [EVM](https://www.evm.codes/#44?fork=shanghai) instruction. | DIFFICULTY - -Original [EVM](https://www.evm.codes/#44?fork=grayGlacier) - -### System Contract - -This information is requested a System Contract called -[SystemContext](https://github.com/matter-labs/era-system-contracts/blob/main/contracts/SystemContext.sol). - -On how the System Contract is called, see [this section](../../system-contracts.md#environmental-data-storage). - -### LLVM IR - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/context.rs#L133) -is common for Yul and EVMLA representations. - -The request to the System Contract is done via the -[SystemRequest](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/context/function/runtime/system_request.rs) -runtime function. - -## GASLIMIT - -Original [EVM](https://www.evm.codes/#45?fork=shanghai) instruction. - -### System Contract - -This information is requested a System Contract called -[SystemContext](https://github.com/matter-labs/era-system-contracts/blob/main/contracts/SystemContext.sol). - -On how the System Contract is called, see [this section](../../system-contracts.md#environmental-data-storage). - -### LLVM IR - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/context.rs#L13) -is common for Yul and EVMLA representations. - -The request to the System Contract is done via the -[SystemRequest](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/context/function/runtime/system_request.rs) -runtime function. - -## CHAINID - -Original [EVM](https://www.evm.codes/#46?fork=shanghai) instruction. - -### System Contract - -This information is requested a System Contract called -[SystemContext](https://github.com/matter-labs/era-system-contracts/blob/main/contracts/SystemContext.sol). - -On how the System Contract is called, see [this section](../../system-contracts.md#environmental-data-storage). - -### LLVM IR - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/context.rs#L64) -is common for Yul and EVMLA representations. - -The request to the System Contract is done via the -[SystemRequest](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/context/function/runtime/system_request.rs) -runtime function. - -## SELFBALANCE - -Original [EVM](https://www.evm.codes/#47?fork=shanghai) instruction. - -Implemented as [BALANCE](./environment.md#balance) with an [ADDRESS](./environment.md#address) as its argument. - -## BASEFEE - -Original [EVM](https://www.evm.codes/#48?fork=shanghai) instruction. - -### System Contract - -This information is requested a System Contract called -[SystemContext](https://github.com/matter-labs/era-system-contracts/blob/main/contracts/SystemContext.sol). - -On how the System Contract is called, see [this section](../../system-contracts.md#environmental-data-storage). - -### LLVM IR - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/context.rs#L167) -is common for Yul and EVMLA representations. - -The request to the System Contract is done via the -[SystemRequest](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/context/function/runtime/system_request.rs) -runtime function. diff --git a/content/40.zk-stack/components/compiler/specification/instructions/evm/calls.md b/content/40.zk-stack/components/compiler/specification/instructions/evm/calls.md deleted file mode 100644 index 611822ac..00000000 --- a/content/40.zk-stack/components/compiler/specification/instructions/evm/calls.md +++ /dev/null @@ -1,47 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Calls | zkSync Docs ---- - -# Call Instructions - -All EVM call instructions are handled similarly. - -The call type is encoded on the assembly level, so we will describe the common handling workflow, mentioning -distinctions if there are any. - -For more information, see the -[zkSync Era documentation](https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#call-staticcall-delegatecall). - -## CALL - -Original [EVM](https://www.evm.codes/#f1?fork=shanghai) instruction. - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/call.rs#L530) -is common for Yul and EVMLA representations. - -The code checks if the call is non-static and the Ether value is non-zero. If so, the call is redirected to the -[MsgValueSimulator](../../system-contracts.md#ether-value-simulator). - -- [EraVM instruction: `call` (near call)](https://matter-labs.github.io/eravm-spec/spec.html#NearCallDefinition) -- [EraVM instruction: `far_call`](https://matter-labs.github.io/eravm-spec/spec.html#FarCalls) - -## DELEGATECALL - -Original [EVM](https://www.evm.codes/#f4?fork=shanghai) instruction. - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/call.rs#L530) -is common for Yul and EVMLA representations. - -[EraVM instruction: `far_call`](https://matter-labs.github.io/eravm-spec/spec.html#FarCalls) - -## STATICCALL - -Original [EVM](https://www.evm.codes/#fa?fork=shanghai) instruction. - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/call.rs#L530) -is common for Yul and EVMLA representations. - -[EraVM instruction: `far_call`](https://matter-labs.github.io/eravm-spec/spec.html#FarCalls) diff --git a/content/40.zk-stack/components/compiler/specification/instructions/evm/create.md b/content/40.zk-stack/components/compiler/specification/instructions/evm/create.md deleted file mode 100644 index 1be1044a..00000000 --- a/content/40.zk-stack/components/compiler/specification/instructions/evm/create.md +++ /dev/null @@ -1,27 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: CREATE | zkSync Docs ---- - -# CREATE Instructions - -The EVM CREATE instructions are handled similarly. - -For more information, see the -[zkSync Era documentation](https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#create-create2). - -## CREATE - -Original [EVM](https://www.evm.codes/#f0?fork=shanghai) instruction. - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/create.rs#L19) -is common for Yul and EVMLA representations. - -## CREATE2 - -Original [EVM](https://www.evm.codes/#f5?fork=shanghai) instruction. - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/create.rs#L57) -is common for Yul and EVMLA representations. diff --git a/content/40.zk-stack/components/compiler/specification/instructions/evm/environment.md b/content/40.zk-stack/components/compiler/specification/instructions/evm/environment.md deleted file mode 100644 index 39a0f6fc..00000000 --- a/content/40.zk-stack/components/compiler/specification/instructions/evm/environment.md +++ /dev/null @@ -1,350 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Environment | zkSync Docs ---- - -# Environment Instructions - -## ADDRESS - -Original [EVM](https://www.evm.codes/#30?fork=shanghai) instruction. - -This value is fetched with a native -[EraVM instruction: `context.this`](https://matter-labs.github.io/eravm-spec/spec.html#ContextDefinitions). - -### LLVM IR - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-solidity/blob/main/src/yul/parser/statement/expression/function_call/mod.rs#L973) -is common for Yul and EVMLA representations. - -## BALANCE - -Original [EVM](https://www.evm.codes/#31?fork=shanghai) instruction. - -### System Contract - -This information is requested a System Contract called -[L2EthToken](https://github.com/matter-labs/era-system-contracts/blob/main/contracts/L2EthToken.sol). - -On how the System Contract is called, see [this section](../../system-contracts.md#environmental-data-storage). - -### LLVM IR - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/ether_gas.rs#L39) -is common for Yul and EVMLA representations. - -The request to the System Contract is done via the -[SystemRequest](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/context/function/runtime/system_request.rs) -runtime function. - -## ORIGIN - -Original [EVM](https://www.evm.codes/#32?fork=shanghai) instruction. - -### System Contract - -This information is requested a System Contract called -[SystemContext](https://github.com/matter-labs/era-system-contracts/blob/main/contracts/SystemContext.sol). - -On how the System Contract is called, see [this section](../../system-contracts.md#environmental-data-storage). - -### LLVM IR - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/context.rs#L47) -is common for Yul and EVMLA representations. - -The request to the System Contract is done via the -[SystemRequest](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/context/function/runtime/system_request.rs) -runtime function. - -## CALLER - -Original [EVM](https://www.evm.codes/#33?fork=shanghai) instruction. - -This value is fetched with a native -[EraVM instruction: `context.caller`](https://matter-labs.github.io/eravm-spec/spec.html#ContextDefinitions). - -### LLVM IR - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-solidity/blob/main/src/yul/parser/statement/expression/function_call/mod.rs#L974) -is common for Yul and EVMLA representations. - -## CALLVALUE - -Original [EVM](https://www.evm.codes/#34?fork=shanghai) instruction. - -This value is fetched with a native -[EraVM instruction: `context.get_context_u128`](https://matter-labs.github.io/eravm-spec/spec.html#ContextDefinitions). - -### LLVM IR - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/ether_gas.rs#L25) -is common for Yul and EVMLA representations. - -## CALLDATALOAD - -Original [EVM](https://www.evm.codes/#35?fork=shanghai) instruction. - -Calldata is accessed with a generic memory access instruction, but the memory chunk itself is a reference to the calling -contract's heap. A fat pointer to the parent contract is passed via ABI using registers. - -Then, the pointer -[is saved to a global stack variable](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/context/function/runtime/entry.rs#L129) -accessible from anywhere in the contract. - -### LLVM IR - -```c++ -@ptr_calldata = private unnamed_addr global ptr addrspace(3) null ; global variable declaration -... -store ptr addrspace(3) %0, ptr @ptr_calldata, align 32 ; saving the pointer from `r1` to the global variable -... -%calldata_pointer = load ptr addrspace(3), ptr @ptr_calldata, align 32 ; loading the pointer from the global variable to `calldata_pointer` -%calldata_value = load i256, ptr addrspace(3) %calldata_pointer, align 32 ; loading the value from the calldata pointer -``` - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/calldata.rs#L14) -is common for Yul and EVMLA representations. - -### EraVM Assembly - -```asm -ptr.add r1, r0, stack[@ptr_calldata] ; saving the pointer from `r1` to the global variable -... -ptr.add stack[@ptr_calldata], r0, r1 ; loading the pointer from the global variable to `r1` -ld r1, r1 ; loading the value to `r1` -``` - -- [EraVM instruction: `ptr.add`](https://matter-labs.github.io/eravm-spec/spec.html#PtrAddDefinition) -- [EraVM fat pointers](https://matter-labs.github.io/eravm-spec/spec.html#PointerDefinitions) -- [EraVM memory forwarding mechanism](https://matter-labs.github.io/eravm-spec/spec.html#MemoryForwarding) - -## CALLDATASIZE - -Original [EVM](https://www.evm.codes/#36?fork=shanghai) instruction. - -Calldata size is stored in the fat pointer passed from the parent contract (see [CALLDATALOAD](#calldataload)). - -The size value can be extracted with bitwise operations as illustrated below. - -### LLVM IR - -```c++ -@calldatasize = private unnamed_addr global i256 0 ; global variable declaration -... -%abi_pointer_value = ptrtoint ptr addrspace(3) %0 to i256 ; converting the pointer to an integer -%abi_pointer_value_shifted = lshr i256 %abi_pointer_value, 96 ; shifting the integer right 96 bits -%abi_length_value = and i256 %abi_pointer_value_shifted, 4294967295 ; keeping the lowest 32 bits of the integer -store i256 %abi_length_value, ptr @calldatasize, align 32 ; saving the value to the global variable -``` - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/calldata.rs#L40) -is common for Yul and EVMLA representations. - -### EraVM Assembly - -```asm -ptr.add r1, r0, stack[@ptr_calldata] ; saving the pointer from `r1` to the global variable -shr.s 96, r1, r1 ; shifting the integer right 96 bits -and @CPI0_0[0], r1, stack[@calldatasize] ; keeping the lowest 32 bits of the integer, saving the value to the global variable -... -CPI0_0: - .cell 4294967295 -``` - -- [EraVM instruction: `ptr.add`](https://matter-labs.github.io/eravm-spec/spec.html#PtrAddDefinition) -- [EraVM fat pointers](https://matter-labs.github.io/eravm-spec/spec.html#PointerDefinitions) -- [EraVM memory forwarding mechanism](https://matter-labs.github.io/eravm-spec/spec.html#MemoryForwarding) - -## CALLDATACOPY - -Original [EVM](https://www.evm.codes/#37?fork=shanghai) instruction. - -Unlike on EVM, on EraVM it is a simple loop over [CALLDATALOAD](#calldataload)). - -### LLVM IR - -```c++ -; loading the pointer from the global variable to `calldata_pointer` -%calldata_pointer = load ptr addrspace(3), ptr @ptr_calldata, align 32 -; shifting the pointer by 122 bytes -%calldata_source_pointer = getelementptr i8, ptr addrspace(3) %calldata_pointer, i256 122 -; copying 64 bytes from calldata at offset 122 to the heap at offset 128 -call void @llvm.memcpy.p1.p3.i256(ptr addrspace(1) align 1 inttoptr (i256 128 to ptr addrspace(1)), ptr addrspace(3) align 1 %calldata_source_pointer, i256 64, i1 false) -``` - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/calldata.rs#L54) -is common for Yul and EVMLA representations. - -### EraVM Assembly - -```asm -.BB0_3: - shl.s 5, r2, r3 ; shifting the offset by 32 - ptr.add r1, r3, r4 ; adding the offset to the calldata pointer - ld r4, r4 ; reading the calldata value - add 128, r3, r3 ; adding the offset to the heap pointer - st.1 r3, r4 ; writing the calldata value to the heap - add 1, r2, r2 ; incrementing the offset - sub.s! 2, r2, r3 ; checking the bounds - jump.lt @.BB0_3 ; loop continuation branching -``` - -- [EraVM instruction: `ptr.add`](https://matter-labs.github.io/eravm-spec/spec.html#PtrAddDefinition) -- [EraVM fat pointers](https://matter-labs.github.io/eravm-spec/spec.html#PointerDefinitions) -- [EraVM memory forwarding mechanism](https://matter-labs.github.io/eravm-spec/spec.html#MemoryForwarding) - -## CODECOPY - -Original [EVM](https://www.evm.codes/#38?fork=shanghai) instruction. - -See [the EraVM docs](https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#codecopy). - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-solidity/blob/main/src/evmla/ethereal_ir/function/block/element/mod.rs#L856). - -## CODESIZE - -Original [EVM](https://www.evm.codes/#39?fork=shanghai) instruction. - -See [the EraVM docs](https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#codesize). - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-solidity/blob/main/src/evmla/ethereal_ir/function/block/element/mod.rs#L837). - -## GASPRICE - -Original [EVM](https://www.evm.codes/#3a?fork=shanghai) instruction. - -### System Contract - -This information is requested a System Contract called -[SystemContext](https://github.com/matter-labs/era-system-contracts/blob/main/contracts/SystemContext.sol). - -On how the System Contract is called, see [this section](../../system-contracts.md#environmental-data-storage). - -### LLVM IR - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/context.rs#L30) -is common for Yul and EVMLA representations. - -The request to the System Contract is done via the -[SystemRequest](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/context/function/runtime/system_request.rs) -runtime function. - -## EXTCODESIZE - -Original [EVM](https://www.evm.codes/#3b?fork=shanghai) instruction. - -### System Contract - -This information is requested a System Contract called -[AccountCodeStorage](https://github.com/matter-labs/era-system-contracts/blob/main/contracts/AccountCodeStorage.sol). - -On how the System Contract is called, see [this section](../../system-contracts.md#environmental-data-storage). - -### LLVM IR - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/ext_code.rs#L11) -is common for Yul and EVMLA representations. - -The request to the System Contract is done via the -[SystemRequest](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/context/function/runtime/system_request.rs) -runtime function. - -## EXTCODECOPY - -Original [EVM](https://www.evm.codes/#3c?fork=shanghai) instruction. - -Not supported. Triggers a compile-time error. - -## RETURNDATASIZE - -Original [EVM](https://www.evm.codes/#3d?fork=shanghai) instruction. - -Return data size is read from the fat pointer returned from the child contract. - -The size value can be extracted with bitwise operations as illustrated below. - -### LLVM IR - -```c++ -%contract_call_external = tail call { ptr addrspace(3), i1 } @__farcall(i256 0, i256 0, i256 undef, i256 undef, i256 undef, i256 undef, i256 undef, i256 undef, i256 undef, i256 undef, i256 undef, i256 undef) -%contract_call_external_result_abi_data = extractvalue { ptr addrspace(3), i1 } %contract_call_external, 0 -%contract_call_memcpy_from_child_pointer_casted = ptrtoint ptr addrspace(3) %contract_call_external_result_abi_data to i256 -%contract_call_memcpy_from_child_return_data_size_shifted = lshr i256 %contract_call_memcpy_from_child_pointer_casted, 96 -%contract_call_memcpy_from_child_return_data_size_truncated = and i256 %contract_call_memcpy_from_child_return_data_size_shifted, 4294967295 -``` - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/return_data.rs#L16) -is common for Yul and EVMLA representations. - -### EraVM Assembly - -```asm -near_call r0, @__farcall, @DEFAULT_UNWIND ; calling a child contract -shr.s 96, r1, r1 ; shifting the pointer value right 96 bits -and @CPI0_1[0], r1, r1 ; keeping the lowest 32 bits of the pointer value -... -CPI0_1: - .cell 4294967295 -``` - -[EraVM instruction: `call`](https://matter-labs.github.io/eravm-spec/spec.html#NearCallDefinition) - -## RETURNDATACOPY - -Original [EVM](https://www.evm.codes/#3e?fork=shanghai) instruction. - -Unlike on EVM, on EraVM it is a simple loop over memory operations on 256-bit values. - -### LLVM IR - -```c++ -; loading the pointer from the global variable to `return_data_pointer` -%return_data_pointer = load ptr addrspace(3), ptr @ptr_return_data, align 32 -; shifting the pointer by 122 bytes -%return_data_source_pointer = getelementptr i8, ptr addrspace(3) %return_data_pointer, i256 122 -; copying 64 bytes from return data at offset 122 to the heap at offset 128 -call void @llvm.memcpy.p1.p3.i256(ptr addrspace(1) align 1 inttoptr (i256 128 to ptr addrspace(1)), ptr addrspace(3) align 1 %return_data_source_pointer, i256 64, i1 false) -``` - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/return_data.rs#L31) -is common for Yul and EVMLA representations. - -### EraVM Assembly - -```asm -.BB0_3: - shl.s 5, r2, r3 ; shifting the offset by 32 - ptr.add r1, r3, r4 ; adding the offset to the return data pointer - ld r4, r4 ; reading the return data value - add 128, r3, r3 ; adding the offset to the heap pointer - st.1 r3, r4 ; writing the return data value to the heap - add 1, r2, r2 ; incrementing the offset - sub.s! 2, r2, r3 ; checking the bounds - jump.lt @.BB0_3 ; loop continuation branching -``` - -- [EraVM instruction: `jump`](https://matter-labs.github.io/eravm-spec/spec.html#JumpDefinition) -- [EraVM instruction predication](https://matter-labs.github.io/eravm-spec/spec.html#Predication) - -## EXTCODEHASH - -Original [EVM](https://www.evm.codes/#3f?fork=shanghai) instruction. - -### System Contract - -This information is requested a System Contract called -[AccountCodeStorage](https://github.com/matter-labs/era-system-contracts/blob/main/contracts/AccountCodeStorage.sol). - -On how the System Contract is called, see [this section](../../system-contracts.md#environmental-data-storage). - -### LLVM IR - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/ext_code.rs#L29) -is common for Yul and EVMLA representations. - -The request to the System Contract is done via the -[SystemRequest](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/context/function/runtime/system_request.rs) -runtime function. diff --git a/content/40.zk-stack/components/compiler/specification/instructions/evm/events.md b/content/40.zk-stack/components/compiler/specification/instructions/evm/events.md deleted file mode 100644 index 8f4d0e1d..00000000 --- a/content/40.zk-stack/components/compiler/specification/instructions/evm/events.md +++ /dev/null @@ -1,37 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Events | zkSync Docs ---- - -# Event Instructions - -The EraVM event instructions are more low-level. Each `LOG`-like instruction is unrolled into a loop, where each -iteration writes two 256-bit words. - -The words must contain data in the following order: - -1. The initializer cell, describing the number of indexed words (e.g. `I`) and the size of non-indexed data in bytes - (e.g. `D`) -2. `I` indexed 32-byte words -3. `D` bytes of data - -Each write operation can contain some subsequent data from its next step. If only one word remains, the second input is -zero. - -See [EraVM instruction: `log.event`](https://matter-labs.github.io/eravm-spec/spec.html#EventDefinition) - -## LOG0 - LOG4 - -Original [EVM](https://www.evm.codes/#a0?fork=shanghai) instructions. - -### System Contract - -This information is requested a System Contract called -[EventWriter](https://github.com/matter-labs/era-system-contracts/blob/main/contracts/EventWriter.yul). - -On how the System Contract is called, see [this section](../../system-contracts.md#event-handler). - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/event.rs#L20) -is common for Yul and EVMLA representations. diff --git a/content/40.zk-stack/components/compiler/specification/instructions/evm/hashes.md b/content/40.zk-stack/components/compiler/specification/instructions/evm/hashes.md deleted file mode 100644 index ea884b26..00000000 --- a/content/40.zk-stack/components/compiler/specification/instructions/evm/hashes.md +++ /dev/null @@ -1,59 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Hashes | zkSync Docs ---- - -# Hash Instructions - -## SHA3 - -Original [EVM](https://www.evm.codes/#20?fork=shanghai) instruction. - -### System Contract - -This instruction is handled by a System Contract called -[Keccak256](https://github.com/matter-labs/era-system-contracts/blob/main/contracts/precompiles/Keccak256.yul), which is -a wrapper around the EraVM precompile. - -On how the System Contract is called, see [this section](../../system-contracts.md#keccak256-hash-function). - -### LLVM IR - -```c++ -define i256 @__sha3(i8 addrspace(1)* nocapture nofree noundef %0, i256 %1, i1 %throw_at_failure) "noinline-oz" #1 personality i32()* @__personality { -entry: - %addr_int = ptrtoint i8 addrspace(1)* %0 to i256 - %2 = tail call i256 @llvm.umin.i256(i256 %addr_int, i256 4294967295) - %3 = tail call i256 @llvm.umin.i256(i256 %1, i256 4294967295) - %gas_left = tail call i256 @llvm.syncvm.gasleft() - %4 = tail call i256 @llvm.umin.i256(i256 %gas_left, i256 4294967295) - %abi_data_input_offset_shifted = shl nuw nsw i256 %2, 64 - %abi_data_input_length_shifted = shl nuw nsw i256 %3, 96 - %abi_data_gas_shifted = shl nuw nsw i256 %4, 192 - %abi_data_offset_and_length = add i256 %abi_data_input_length_shifted, %abi_data_input_offset_shifted - %abi_data_add_gas = add i256 %abi_data_gas_shifted, %abi_data_offset_and_length - %abi_data_add_system_call_marker = add i256 %abi_data_add_gas, 904625697166532776746648320380374280103671755200316906558262375061821325312 - %call_external = tail call { i8 addrspace(3)*, i1 } @__staticcall(i256 %abi_data_add_system_call_marker, i256 32784, i256 undef, i256 undef, i256 undef, i256 undef, i256 undef, i256 undef, i256 undef, i256 undef, i256 undef, i256 undef) - %status_code = extractvalue { i8 addrspace(3)*, i1 } %call_external, 1 - br i1 %status_code, label %success_block, label %failure_block - -success_block: - %abi_data_pointer = extractvalue { i8 addrspace(3)*, i1 } %call_external, 0 - %data_pointer = bitcast i8 addrspace(3)* %abi_data_pointer to i256 addrspace(3)* - %keccak256_child_data = load i256, i256 addrspace(3)* %data_pointer, align 1 - ret i256 %keccak256_child_data - -failure_block: - br i1 %throw_at_failure, label %throw_block, label %revert_block - -revert_block: - call void @__revert(i256 0, i256 0, i256 0) - unreachable - -throw_block: - call void @__cxa_throw(i8* noalias nocapture nofree align 32 null, i8* noalias nocapture nofree align 32 undef, i8* noalias nocapture nofree align 32 undef) - unreachable -} -``` diff --git a/content/40.zk-stack/components/compiler/specification/instructions/evm/logical.md b/content/40.zk-stack/components/compiler/specification/instructions/evm/logical.md deleted file mode 100644 index 99227e86..00000000 --- a/content/40.zk-stack/components/compiler/specification/instructions/evm/logical.md +++ /dev/null @@ -1,209 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Logical | zkSync Docs ---- - -# Logical Instructions - -## LT - -Original [EVM](https://www.evm.codes/#10?fork=shanghai) instruction. - -### LLVM IR - -```c++ -%comparison_result = icmp ult i256 %value1, %value2 -%comparison_result_extended = zext i1 %comparison_result to i256 -``` - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/comparison.rs#L15) -is common for Yul and EVMLA representations. - -[LLVM IR instruction documentation](https://releases.llvm.org/15.0.0/docs/LangRef.html#icmp-instruction) - -### EraVM Assembly - -```asm -ptr.add stack[@ptr_calldata], r0, r1 -ptr.add.s 36, r1, r2 -ld r2, r2 -ptr.add.s 4, r1, r1 -ld r1, r1 -sub! r1, r2, r1 -add 0, r0, r1 -add.lt 1, r0, r1 -st.1 128, r1 -``` - -## GT - -Original [EVM](https://www.evm.codes/#11?fork=shanghai) instruction. - -### LLVM IR - -```c++ -%comparison_result = icmp ugt i256 %value1, %value2 -%comparison_result_extended = zext i1 %comparison_result to i256 -``` - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/comparison.rs#L15) -is common for Yul and EVMLA representations. - -[LLVM IR instruction documentation](https://releases.llvm.org/15.0.0/docs/LangRef.html#icmp-instruction) - -### EraVM Assembly - -```asm -ptr.add stack[@ptr_calldata], r0, r1 -ptr.add.s 36, r1, r2 -ld r2, r2 -ptr.add.s 4, r1, r1 -ld r1, r1 -sub! r1, r2, r1 -add 0, r0, r1 -add.gt 1, r0, r1 -st.1 128, r1 -``` - -## SLT - -Original [EVM](https://www.evm.codes/#12?fork=shanghai) instruction. - -### LLVM IR - -```c++ -%comparison_result = icmp slt i256 %value1, %value2 -%comparison_result_extended = zext i1 %comparison_result to i256 -``` - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/comparison.rs#L15) -is common for Yul and EVMLA representations. - -[LLVM IR instruction documentation](https://releases.llvm.org/15.0.0/docs/LangRef.html#icmp-instruction) - -### EraVM Assembly - -```asm -ptr.add stack[@ptr_calldata], r0, r1 -ptr.add.s 36, r1, r2 -ld r2, r2 -ptr.add.s 4, r1, r1 -ld r1, r1 -add @CPI0_4[0], r0, r3 -sub! r1, r2, r4 -add r0, r0, r4 -add.lt r3, r0, r4 -and @CPI0_4[0], r2, r2 -and @CPI0_4[0], r1, r1 -sub! r1, r2, r5 -add.le r0, r0, r3 -xor r1, r2, r1 -sub.s! @CPI0_4[0], r1, r1 -add r4, r0, r1 -add.eq r3, r0, r1 -sub! r1, r0, r1 -add 0, r0, r1 -add.ne 1, r0, r1 -st.1 128, r1 -``` - -## SGT - -Original [EVM](https://www.evm.codes/#13?fork=shanghai) instruction. - -### LLVM IR - -```c++ -%comparison_result = icmp sgt i256 %value1, %value2 -%comparison_result_extended = zext i1 %comparison_result to i256 -``` - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/comparison.rs#L15) -is common for Yul and EVMLA representations. - -[LLVM IR instruction documentation](https://releases.llvm.org/15.0.0/docs/LangRef.html#icmp-instruction) - -### EraVM Assembly - -```asm -ptr.add stack[@ptr_calldata], r0, r1 -ptr.add.s 36, r1, r2 -ld r2, r2 -ptr.add.s 4, r1, r1 -ld r1, r1 -add @CPI0_4[0], r0, r3 -sub! r1, r2, r4 -add r0, r0, r4 -add.gt r3, r0, r4 -and @CPI0_4[0], r2, r2 -and @CPI0_4[0], r1, r1 -sub! r1, r2, r5 -add.ge r0, r0, r3 -xor r1, r2, r1 -sub.s! @CPI0_4[0], r1, r1 -add r4, r0, r1 -add.eq r3, r0, r1 -sub! r1, r0, r1 -add 0, r0, r1 -add.ne 1, r0, r1 -st.1 128, r1 -``` - -## EQ - -Original [EVM](https://www.evm.codes/#14?fork=shanghai) instruction. - -### LLVM IR - -```c++ -%comparison_result = icmp eq i256 %value1, %value2 -%comparison_result_extended = zext i1 %comparison_result to i256 -``` - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/comparison.rs#L15) -is common for Yul and EVMLA representations. - -[LLVM IR instruction documentation](https://releases.llvm.org/15.0.0/docs/LangRef.html#icmp-instruction) - -### EraVM Assembly - -```asm -ptr.add stack[@ptr_calldata], r0, r1 -ptr.add.s 36, r1, r2 -ld r2, r2 -ptr.add.s 4, r1, r1 -ld r1, r1 -sub! r1, r2, r1 -add 0, r0, r1 -add.eq 1, r0, r1 -st.1 128, r1 -``` - -## ISZERO - -Original [EVM](https://www.evm.codes/#15?fork=shanghai) instruction. - -### LLVM IR - -```c++ -%comparison_result = icmp eq i256 %value, 0 -%comparison_result_extended = zext i1 %comparison_result to i256 -``` - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/comparison.rs#L15) -is common for Yul and EVMLA representations. - -[LLVM IR instruction documentation](https://releases.llvm.org/15.0.0/docs/LangRef.html#icmp-instruction) - -### EraVM Assembly - -```asm -ptr.add stack[@ptr_calldata], r1, r1 -ld r1, r1 -sub! r1, r0, r1 -add 0, r0, r1 -add.eq 1, r0, r1 -st.1 128, r1 -``` diff --git a/content/40.zk-stack/components/compiler/specification/instructions/evm/memory.md b/content/40.zk-stack/components/compiler/specification/instructions/evm/memory.md deleted file mode 100644 index 656c2bcb..00000000 --- a/content/40.zk-stack/components/compiler/specification/instructions/evm/memory.md +++ /dev/null @@ -1,80 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Memory | zkSync Docs ---- - -# Memory Instructions - -## MLOAD - -Original [EVM](https://www.evm.codes/#51?fork=shanghai) instruction. - -Heap memory load operation is modeled with a native EraVM instruction. - -### LLVM IR - -```c++ -%value = load i256, ptr addrspace(1) %pointer, align 1 -``` - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/memory.rs#L15) -is common for Yul and EVMLA representations. - -[LLVM IR instruction documentation](https://releases.llvm.org/15.0.0/docs/LangRef.html#load-instruction) - -### EraVM Assembly - -```asm -ld.1 r1, r2 -``` - -See [EraVM instruction: `st.1`](https://matter-labs.github.io/eravm-spec/spec.html#LoadDefinition) - -## MSTORE - -Original [EVM](https://www.evm.codes/#52?fork=shanghai) instruction. - -Heap memory load operation is modeled with a native EraVM instruction. - -### LLVM IR - -```c++ -store i256 128, ptr addrspace(1) inttoptr (i256 64 to ptr addrspace(1)), align 1 -``` - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/memory.rs#L38) -is common for Yul and EVMLA representations. - -[LLVM IR instruction documentation](https://releases.llvm.org/15.0.0/docs/LangRef.html#store-instruction) - -### EraVM Assembly - -```asm -st.1 r1, r2 -``` - -See [EraVM instruction: `st.1`](https://matter-labs.github.io/eravm-spec/spec.html#StoreDefinition) - -## MSTORE8 - -Original [EVM](https://www.evm.codes/#53?fork=shanghai) instruction. - -### LLVM IR - -```c++ -define void @__mstore8(i256 addrspace(1)* nocapture nofree noundef dereferenceable(32) %addr, i256 %val) #2 { -entry: - %orig_value = load i256, i256 addrspace(1)* %addr, align 1 - %orig_value_shifted_left = shl i256 %orig_value, 8 - %orig_value_shifted_right = lshr i256 %orig_value_shifted_left, 8 - %byte_value_shifted = shl i256 %val, 248 - %store_result = or i256 %orig_value_shifted_right, %byte_value_shifted - store i256 %store_result, i256 addrspace(1)* %addr, align 1 - ret void -} -``` - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/memory.rs#L62) -is common for Yul and EVMLA representations. diff --git a/content/40.zk-stack/components/compiler/specification/instructions/evm/overview.md b/content/40.zk-stack/components/compiler/specification/instructions/evm/overview.md deleted file mode 100644 index e2d09917..00000000 --- a/content/40.zk-stack/components/compiler/specification/instructions/evm/overview.md +++ /dev/null @@ -1,34 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: EVM Instructions | zkSync Docs ---- - -# Native EVM Instructions - -Such instructions are grouped into the following categories according to -[the original reference](https://www.evm.codes/): - -- [Arithmetic](./arithmetic.md) -- [Logical](./logical.md) -- [Bitwise](./bitwise.md) -- [Hashes](./hashes.md) -- [Environment](./environment.md) -- [Block](./block.md) -- [Stack](./stack.md) -- [Memory](./memory.md) -- [Storage](./storage.md) -- [Events](./events.md) -- [Calls](./calls.md) -- [Create](./create.md) -- [Return](./return.md) - -### EraVM Assembly - -Assembly emitted for LLVM standard library functions depends on available optimizations which differ between versions. -If there is no assembly example under an instruction, compile a reproducing contract with the latest version of -`zksolc`. - -EraVM specification contains a list of -[all EraVM instructions (see the table of contents)](https://matter-labs.github.io/eravm-spec/spec.html). diff --git a/content/40.zk-stack/components/compiler/specification/instructions/evm/return.md b/content/40.zk-stack/components/compiler/specification/instructions/evm/return.md deleted file mode 100644 index ed45535b..00000000 --- a/content/40.zk-stack/components/compiler/specification/instructions/evm/return.md +++ /dev/null @@ -1,85 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Return | zkSync Docs ---- - -# Return Instructions - -## STOP - -Original [EVM](https://www.evm.codes/#00?fork=shanghai) instruction. - -This instruction is a [RETURN](#return) with an empty data payload. - -### LLVM IR - -The same as for [RETURN](#return). - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/return.rs#L103) -is common for Yul and EVMLA representations. - -## RETURN - -Original [EVM](https://www.evm.codes/#f3?fork=shanghai) instruction. - -This instruction works differently in deploy code. For more information, see -[the zkSync Era documentation](https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#return). - -### LLVM IR - -```c++ -define void @__return(i256 %0, i256 %1, i256 %2) "noinline-oz" #5 personality i32()* @__personality { -entry: - %abi = call i256@__aux_pack_abi(i256 %0, i256 %1, i256 %2) - tail call void @llvm.syncvm.return(i256 %abi) - unreachable -} -``` - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/return.rs#L16) -is common for Yul and EVMLA representations. - -## REVERT - -Original [EVM](https://www.evm.codes/#fd?fork=shanghai) instruction. - -### LLVM IR - -```c++ -define void @__revert(i256 %0, i256 %1, i256 %2) "noinline-oz" #5 personality i32()* @__personality { -entry: - %abi = call i256@__aux_pack_abi(i256 %0, i256 %1, i256 %2) - tail call void @llvm.syncvm.revert(i256 %abi) - unreachable -} -``` - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/return.rs#L86) -is common for Yul and EVMLA representations. - -### EraVM - -See also EraVM instruction `revert`: -[when returning from near calls](https://matter-labs.github.io/eravm-spec/spec.html#NearRevertDefinition) and -[when returning from far calls](https://matter-labs.github.io/eravm-spec/spec.html#FarRevertDefinition). - -## INVALID - -Original [EVM](https://www.evm.codes/#fe?fork=shanghai) instruction. - -This instruction is a [REVERT](#revert) with an empty data payload, but it also burns all the available gas. - -### LLVM IR - -The same as for [REVERT](#revert). - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/return.rs#L115) -is common for Yul and EVMLA representations. - -### EraVM - -See also EraVM instruction `revert`: -[when returning from near calls](https://matter-labs.github.io/eravm-spec/spec.html#NearRevertDefinition) and -[when returning from far calls](https://matter-labs.github.io/eravm-spec/spec.html#FarRevertDefinition). diff --git a/content/40.zk-stack/components/compiler/specification/instructions/evm/stack.md b/content/40.zk-stack/components/compiler/specification/instructions/evm/stack.md deleted file mode 100644 index edb5a0f8..00000000 --- a/content/40.zk-stack/components/compiler/specification/instructions/evm/stack.md +++ /dev/null @@ -1,60 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Stack | zkSync Docs ---- - -# Stack Instructions - -## POP - -Original [EVM](https://www.evm.codes/#50?fork=shanghai) instruction. - -In Yul, only used to mark unused values, and is not translated to LLVM IR. - -```solidity -pop(staticcall(gas(), address(), 0, 64, 0, 32)) -``` - -For EVMLA, see [EVM Legacy Assembly Translator](../../evmla-translator.md). - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-solidity/blob/main/src/evmla/assembly/instruction/stack.rs#L108). - -## JUMPDEST - -Original [EVM](https://www.evm.codes/#5b?fork=shanghai) instruction. - -Is not available in Yul. - -Ignored in EVMLA. See [EVM Legacy Assembly Translator](../../evmla-translator.md) for more information. - -## PUSH - PUSH32 - -Original [EVM](https://www.evm.codes/#5f?fork=shanghai) instructions. - -Is not available in Yul. - -For EVMLA, see [EVM Legacy Assembly Translator](../../evmla-translator.md). - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-solidity/blob/main/src/evmla/assembly/instruction/stack.rs#L10). - -## DUP1 - DUP16 - -Original [EVM](https://www.evm.codes/#80?fork=shanghai) instructions. - -Is not available in Yul. - -For EVMLA, see [EVM Legacy Assembly Translator](../../evmla-translator.md). - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-solidity/blob/main/src/evmla/assembly/instruction/stack.rs#L48). - -## SWAP1 - SWAP16 - -Original [EVM](https://www.evm.codes/#90?fork=shanghai) instructions. - -Is not available in Yul. - -For EVMLA, see [EVM Legacy Assembly Translator](../../evmla-translator.md). - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-solidity/blob/main/src/evmla/assembly/instruction/stack.rs#L74). diff --git a/content/40.zk-stack/components/compiler/specification/instructions/evm/storage.md b/content/40.zk-stack/components/compiler/specification/instructions/evm/storage.md deleted file mode 100644 index 5608bc30..00000000 --- a/content/40.zk-stack/components/compiler/specification/instructions/evm/storage.md +++ /dev/null @@ -1,50 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Storage | zkSync Docs ---- - -# Storage Instructions - -## SLOAD - -Original [EVM](https://www.evm.codes/#54?fork=shanghai) instruction. - -Storage load operation is modeled with a native EraVM instruction. - -### LLVM IR - -```c++ -%value = load i256, ptr addrspace(5) %pointer, align 1 -``` - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/storage.rs#L13) -is common for Yul and EVMLA representations. - -### EraVM Assembly - -```asm -sload r1, r2 -``` - -## SSTORE - -Original [EVM](https://www.evm.codes/#55?fork=shanghai) instruction. - -Storage store operation is modeled with a native EraVM instruction. - -### LLVM IR - -```c++ -store i256 42, ptr addrspace(5) inttoptr (i256 1 to ptr addrspace(5)), align 1 -``` - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/storage.rs#L34) -is common for Yul and EVMLA representations. - -### EraVM Assembly - -```asm -sstore r1, r2 -``` diff --git a/content/40.zk-stack/components/compiler/specification/instructions/evmla.md b/content/40.zk-stack/components/compiler/specification/instructions/evmla.md deleted file mode 100644 index 8d86a668..00000000 --- a/content/40.zk-stack/components/compiler/specification/instructions/evmla.md +++ /dev/null @@ -1,92 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: EVM Legacy Assembly | zkSync Docs ---- - -# EVM Legacy Assembly Auxiliary Instructions - -These instructions do not have a direct representation in EVM or EraVM. Instead, they perform auxiliary operations -required for generating the target bytecode. - -## PUSH [$] - -The same as [datasize](./yul.md#datasize). - -LLVM IR codegen references: - -1. [zksolc compiler](https://github.com/matter-labs/era-compiler-solidity/blob/main/src/evmla/ethereal_ir/function/block/element/mod.rs#L144) -2. [Shared FE code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/create.rs#L149) - -## PUSH #[$] - -The same as [dataoffset](./yul.md#dataoffset). - -LLVM IR codegen references: - -1. [zksolc compiler](https://github.com/matter-labs/era-compiler-solidity/blob/main/src/evmla/ethereal_ir/function/block/element/mod.rs#L135) -2. [Shared FE code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/create.rs#L97) - -## ASSIGNIMMUTABLE - -The same as [setimmutable](./yul.md#setimmutable). - -For more information, see the -[Differences with Ethereum](../../../../../build/developer-reference/differences-with-ethereum.md#setimmutable-loadimmutable). - -LLVM IR codegen references: - -1. [zksolc compiler](https://github.com/matter-labs/era-compiler-solidity/blob/main/src/evmla/ethereal_ir/function/block/element/mod.rs#L760) -2. [Shared FE code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/immutable.rs#L79) - -## PUSHIMMUTABLE - -The same as [loadimmutable](./yul.md#loadimmutable). - -For more information, see the -[Differences with Ethereum](../../../../../build/developer-reference/differences-with-ethereum.md#setimmutable-loadimmutable). - -LLVM IR codegen references: - -1. [zksolc compiler](https://github.com/matter-labs/era-compiler-solidity/blob/main/src/evmla/ethereal_ir/function/block/element/mod.rs#L747) -2. [Shared FE code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/immutable.rs#L17) - -## PUSHLIB - -The same as [linkersymbol](./yul.md#linkersymbol). - -For more information, see the -[Differences with Ethereum](../../../../../build/developer-reference/differences-with-ethereum.md#libraries). - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-solidity/blob/main/src/yul/parser/statement/expression/function_call/mod.rs#L956). - -## PUSHDEPLOYADDRESS - -Returns the address the contract is deployed to. - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-solidity/blob/main/src/yul/parser/statement/expression/function_call/mod.rs#L956). - -## PUSHSIZE - -Can be only found in deploy code. On EVM, returns the total size of the runtime code and constructor arguments. - -On EraVM, it is always 0, since EraVM does not operate on runtime code in deploy code. - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-solidity/blob/main/src/yul/parser/statement/expression/function_call/mod.rs#L907). - -## PUSH data - -Pushes a data chunk onto the stack. Data chunks are resolved during the processing of input assembly JSON. - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-solidity/blob/main/src/evmla/ethereal_ir/function/block/element/mod.rs#L164). - -## PUSH [tag] - -Pushes an EVM Legacy Assembly destination block identifier onto the stack. - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-solidity/blob/main/src/evmla/assembly/instruction/stack.rs#L31). - -## Tag - -Starts a new EVM Legacy Assembly block. Tags are processed during the translation of EVM Legacy Assembly into EthIR. diff --git a/content/40.zk-stack/components/compiler/specification/instructions/overview.md b/content/40.zk-stack/components/compiler/specification/instructions/overview.md deleted file mode 100644 index d9d9b62d..00000000 --- a/content/40.zk-stack/components/compiler/specification/instructions/overview.md +++ /dev/null @@ -1,52 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Instructions | zkSync Docs ---- - -# Instruction Reference - -In this specification, instructions are grouped by their relevance to the EVM instruction set: - -- [Native EVM instructions](./evm/overview.md). -- [Yul auxiliary instructions](./yul.md). -- [EVM legacy assembly auxiliary instructions](./evmla.md). - -Most of the EVM native instructions are represented in both Yul and EVM legacy assembly IRs. If they are not, it is -stated explicitly in the description of each instruction. - -## Addressing modes - -EraVM is a register-based virtual machine with different addressing modes. -It overrides all stack mechanics described in [the original EVM opcodes documentation](https://www.evm.codes/) including -errors they produce on EVM. - -## Solidity Intermediate Representations (IRs) - -Every instruction is translated via two IRs available in the Solidity compiler unless stated otherwise: - -1. Yul -2. EVM legacy assembly - -## Yul Extensions - -At the moment there is no way of adding zkSync-specific instructions to Yul as long as we use the official Solidity -compiler, which would produce an error on an unknown instruction. - -There are two ways of supporting such instructions: one for Solidity and one for Yul. - -### The Solidity Mode - -In Solidity we have introduced **call simulations**. They are not actual calls, as they are substituted by our Yul -translator with the needed instruction, depending on the constant address. This way the Solidity compiler is not -optimizing them out and is not emitting compilation errors. - -The reference of such extensions is coming soon. - -### The Yul Mode - -The non-call zkSync-specific instructions are only available in the Yul mode of **zksolc**. -To have better compatibility, they are implemented as `verbatim` instructions with some predefined keys. - -The reference of such extensions is coming soon. diff --git a/content/40.zk-stack/components/compiler/specification/instructions/yul.md b/content/40.zk-stack/components/compiler/specification/instructions/yul.md deleted file mode 100644 index 49bb7531..00000000 --- a/content/40.zk-stack/components/compiler/specification/instructions/yul.md +++ /dev/null @@ -1,108 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Yul | zkSync Docs ---- - -# Yul Auxiliary Instructions - -These instructions do not have a direct representation in EVM or EraVM. Instead, they perform auxiliary operations -required for generating the target bytecode. - -## datasize - -Original [Yul](https://docs.soliditylang.org/en/latest/yul.html#datasize-dataoffset-datacopy) auxiliary instruction. - -Unlike on EVM, on EraVM target this instruction returns the size of the header part of the calldata sent to the -[ContractDeployer](../system-contracts.md#contract-deployer). For more information, see [CREATE](./evm/create.md). - -LLVM IR codegen references: - -1. [zksolc compiler](https://github.com/matter-labs/era-compiler-solidity/blob/main/src/yul/parser/statement/expression/function_call/mod.rs#L928) -2. [Shared FE code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/create.rs#L149) - -## dataoffset - -Original [Yul](https://docs.soliditylang.org/en/latest/yul.html#datasize-dataoffset-datacopy) auxiliary instruction. - -Unlike on EVM, on EraVM target this instruction has nothing to do with the offset. Instead, it returns the bytecode hash -of the contract referenced by the Yul object identifier. Since our compiler translates instructions without analyzing -the surrounding context, it is not possible to get the bytecode hash from anywhere else in [datacopy](#datacopy). For -more information, see [CREATE](./evm/create.md). - -LLVM IR codegen references: - -1. [zksolc compiler](https://github.com/matter-labs/era-compiler-solidity/blob/main/src/yul/parser/statement/expression/function_call/mod.rs#L918) -2. [Shared FE code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/create.rs#L97) - -## datacopy - -Original [Yul](https://docs.soliditylang.org/en/latest/yul.html#datasize-dataoffset-datacopy) auxiliary instruction. - -Unlike on EVM, on EraVM target this instruction copies the bytecode hash passed as [dataoffset](#dataoffset) to the -destination. For more information, see [CREATE](./evm/create.md). - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-solidity/blob/main/src/yul/parser/statement/expression/function_call/mod.rs#L938). - -## setimmutable - -Original [Yul](https://docs.soliditylang.org/en/latest/yul.html#setimmutable-loadimmutable) auxiliary instruction. - -Writes immutables to the auxiliary heap. - -For more information, see the -[Differences with Ethereum](../../../../../build/developer-reference/differences-with-ethereum.md#setimmutable-loadimmutable). - -LLVM IR codegen references: - -1. [zksolc compiler](https://github.com/matter-labs/era-compiler-solidity/blob/main/src/yul/parser/statement/expression/function_call/mod.rs#L562) -2. [Shared FE code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/immutable.rs#L79) - -## loadimmutable - -Original [Yul](https://docs.soliditylang.org/en/latest/yul.html#setimmutable-loadimmutable) auxiliary instruction. - -Reads immutables from the [ImmutableSimulator](../system-contracts.md#simulator-of-immutables). - -For more information, see the -[Differences with Ethereum](../../../../../build/developer-reference/differences-with-ethereum.md#setimmutable-loadimmutable). - -LLVM IR codegen references: - -1. [zksolc compiler](https://github.com/matter-labs/era-compiler-solidity/blob/main/src/yul/parser/statement/expression/function_call/mod.rs#L540) -2. [Shared FE code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/immutable.rs#L17) - -## linkersymbol - -Original [Yul](https://docs.soliditylang.org/en/latest/yul.html#linkersymbol) auxiliary instruction. - -Returns the address of a deployable library. The address must be passed to `zksolc` with the `--libraries` option, -otherwise a compile-time error will be produced. - -There is a special `zksolc` execution mode that can be enabled with `--missing-libraries` flag. In this mode, the -compiler will return the list of deployable libraries not provided with `--libraries`. This mode allows package managers -like Hardhat to automatically deploy libraries. - -For more information, see the -[Differences with Ethereum](../../../../../build/developer-reference/differences-with-ethereum.md#libraries). - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-solidity/blob/main/src/yul/parser/statement/expression/function_call/mod.rs#L956). - -## memoryguard - -Original [Yul](https://docs.soliditylang.org/en/latest/yul.html#memoryguard) auxiliary instruction. - -Is a Yul optimizer hint which is not used by our compiler. Instead, its only argument is simply unwrapped and returned. - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-solidity/blob/main/src/yul/parser/statement/expression/function_call/mod.rs#L968). - -## verbatim - -Original [Yul](https://docs.soliditylang.org/en/latest/yul.html#verbatim) auxiliary instruction. - -Unlike on EVM, on EraVM target this instruction has nothing to do with inserting of EVM bytecode. Instead, it is used to -implement [EraVM Yul Extensions](../instructions/overview.md#yul-extensions) available in the system mode. In order to -compile a Yul contract with extensions, both Yul and system mode must be enabled (`zksolc --yul --system-mode ...`). - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-solidity/blob/main/src/yul/parser/statement/expression/function_call/verbatim.rs). diff --git a/content/40.zk-stack/components/compiler/specification/overview.md b/content/40.zk-stack/components/compiler/specification/overview.md deleted file mode 100644 index 49dfe410..00000000 --- a/content/40.zk-stack/components/compiler/specification/overview.md +++ /dev/null @@ -1,46 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Compiler Specification | zkSync Docs ---- - -# Compiler Specification - -This is a technical deep-dive into the specifics of how the compiler works. If you're looking to just deploy a contract, -please visit -[Contract deployment](../../../../build/developer-reference/contract-development.md#smart-contract-development) to -better understand the workflow or [Toolchain](../toolchain/overview.md#compiler-toolchain-overview) to understand the -specifics around our Solidity, Vyper and LLVM compilers. - -## Glossary - -| Entity | Description | -| ------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| zksolc | The Solidity compiler, developed by Matter Labs. | -| solc | The original Solidity compiler, developed by the Ethereum community. Called by zksolc as a subprocess to get the IRs of the source code of the project. | -| LLVM | The compiler framework, used for optimizations and assembly generation. | -| EraVM assembler/linker | The tool written in Rust. Translates the assembly emitted by LLVM to the target bytecode. | -| Virtual machine | The zkSync Era virtual machine called EraVM with a custom instruction set. | -| [EraVM specification](https://matter-labs.github.io/eravm-spec/spec.html) | A combination of a human readable documentation and a formal description of EraVM, including its structure and operation, instruction syntax, semantic, and encoding. | -| Intermediate representation (IR) | The data structure or code used internally by the compiler to represent source code. | -| Yul | One of the Solidity IRs. Is a superset of the assembly available in Solidity. Used by default for contracts written in Solidity ≥0.8. | -| EVMLA | One of the Solidity IRs called EVM legacy assembly. Is a predecessor of Yul, but must closer to the pure EVM bytecode. Used by default for contracts written in Solidity <0.8. | -| LLVM IR | The IR native to the LLVM framework. | -| EraVM assembly | The text representation of the EraVM bytecode. Emitted by the LLVM framework. Translated into the EraVM bytecode by the EraVM assembler/linker. | -| EraVM bytecode | The smart contract bytecode, executed by EraVM. | -| Stack | The segment of the non-persistent contract memory. Consists of two parts: global data and function stack frame. | -| Heap | The segment of the non-persistent contract memory. All the data is globally accessible by both the compiler and user code. The allocation is handled by the solc’s Yul/EVMLA allocator only. | -| Auxiliary heap | The segment of the non-persistent contract memory, introduced to avoid conflicts with the solc’s allocator. All the data is globally accessible by the compiler only. The allocation is handled by the zksolc’s compiler only. All contract calls specific to zkSync, including the system contracts, are made via the auxiliary heap. It is also used to return data (e.g. the array of immutables) from the constructor. | -| Calldata | The segment of the non-persistent contract memory. The heap or auxiliary heap of the parent/caller contract. | -| Return data | The segment of the non-persistent contract memory. The heap or auxiliary heap of the child/callee contract. | -| Contract storage | The persistent contract memory. No relevant differences from that of EVM. | -| System contracts | The special set of zkSync kernel contracts written in Solidity by Matter Labs. | -| Contract context | The special storage of VM that keeps data like the current address, the caller’s address, etc. | - -## Concepts - -- [Code Separation](./code-separation.md) -- [System Contracts](./system-contracts.md) -- [Exception Handling](./exception-handling.md) -- [EVMLA translator](./evmla-translator.md) diff --git a/content/40.zk-stack/components/compiler/specification/system-contracts.md b/content/40.zk-stack/components/compiler/specification/system-contracts.md deleted file mode 100644 index 6c433321..00000000 --- a/content/40.zk-stack/components/compiler/specification/system-contracts.md +++ /dev/null @@ -1,144 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: System Contracts | zkSync Docs ---- - -# System Contracts Usage - -Many EVM instructions require special handling by the System Contracts. Among them are: `ORIGIN`, `CALLVALUE`, -`BALANCE`, `CREATE`, `SHA3`, and others. To see the full detailed list of instructions that require special handling, -see [the EVM instructions reference](../specification/instructions/evm/overview.md). - -There are several types of System Contracts from the perspective of how they are handled by the zkSync Era compilers: - -1. [Environmental data storage](#environmental-data-storage). -2. [KECCAK256 hash function](#keccak256-hash-function). -3. [Contract deployer](#contract-deployer). -4. [Ether value simulator](#ether-value-simulator). -5. [Simulator of immutables](#simulator-of-immutables). -6. [Event handler](#event-handler). - -### Environmental Data Storage - -Such storage contracts are accessed with static calls in order to retrieve values for the block, transaction, and other -environmental entities: `CHAINID`, `DIFFICULTY`, `BLOCKHASH`, etc. - -One good example of such contract is -[SystemContext](https://github.com/matter-labs/era-contracts/blob/main/system-contracts/contracts/SystemContext.sol) -that provides the majority of the environmental data. - -Since EVM is not using external calls for these instructions, we must use [the auxiliary heap](#auxiliary-heap) for -their calldata. - -Steps to handle such instructions: - -1. Store the calldata for the System Contract call on the auxiliary heap. -2. Call the System Contract with a static call. -3. Check the return status code of the call. -4. [Revert or throw](./exception-handling.md) if the status code is zero. -5. Read the ABI data and extract the result. All such System Contracts return a single 256-bit value. -6. Return the value as the result of the original instruction. - -For reference, see -[the LLVM IR codegen source code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/context/function/llvm_runtime.rs#L488). - -### KECCAK256 Hash Function - -Handling of this function is similar to [Environmental Data Storage](#environmental-data-storage) with one difference: - -Since EVM also uses heap to store the calldata for `KECCAK256`, the required memory chunk is allocated by the IR -generator, and zkSync Era compiler does not need to use [the auxiliary heap](#auxiliary-heap). - -For reference, see -[the LLVM IR codegen source code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/context/function/llvm_runtime.rs). - -### Contract Deployer - -See [handling CREATE](../../../../build/developer-reference/differences-with-ethereum.md#create-create2) and -[dependency code substitution instructions](../../../../build/developer-reference/differences-with-ethereum.md#datasize-dataoffset-datacopy) -on zkSync Era documentation. - -For reference, see LLVM IR codegen for -[the deployer call](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/context/function/runtime/deployer_call.rs) -and -[CREATE-related instructions](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/create.rs). - -### Ether Value Simulator - -EraVM does not support passing Ether natively, so this is handled by a special System Contract called -[MsgValueSimulator](https://github.com/matter-labs/era-contracts/blob/main/system-contracts/contracts/MsgValueSimulator.sol). - -An external call is redirected through the simulator if the following conditions are met: - -1. The [call](./instructions/evm/calls.md#call) has the Ether value parameter. -2. The Ether value is non-zero. - -Calls to the simulator require extra data passed via ABI using registers: - -1. Ether value. -2. The address of the contract to call. -3. The [system call bit](https://matter-labs.github.io/eravm-spec/spec.html#to_system), which is only set if a call to - the [ContractDeployer](#contract-deployer) is being redirected, that is `CREATE` or `CREATE2` is called with non-zero - Ether. - -Passing Ether value in EraVM is implemented by using a combination of: - -- a special 128-bit register [`context_u128`](https://matter-labs.github.io/eravm-spec/spec.html#gs_context_u128) which - is a part of the EraVM [transient state](https://matter-labs.github.io/eravm-spec/spec.html#StateDefinitions); -- an [immutable value of `context_u128`](https://matter-labs.github.io/eravm-spec/spec.html#ecf_context_u128_value) - captured in the stack frame in a moment of a call. - -The process of setting up a value and capturing it is described in details in the section -[Context Register of the EraVM specification](https://matter-labs.github.io/eravm-spec/spec.html#StateDefinitions). - -For reference, see -[the LLVM IR codegen source code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/call.rs#L530). - -### Simulator of Immutables - -See [handling immutables](../../../../build/developer-reference/differences-with-ethereum.md#setimmutable-loadimmutable) -on zkSync Era documentation. - -For reference, see LLVM IR codegen for -[instructions for immutables](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/immutable.rs) -and -[RETURN from the deploy code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/return.rs#L28). - -### Event Handler - -Event payloads are sent to a special System Contract called -[EventWriter](https://github.com/matter-labs/era-contracts/blob/main/system-contracts/contracts/EventWriter.yul). Like -on EVM, the payload consists of topics and data: - -1. The topics with a length-prefix are passed via ABI using registers. -2. The data is passed via the default heap, like on EVM. - -For reference, see -[the LLVM IR codegen source code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/event.rs). - -## Auxiliary Heap - -Both [zksolc](../toolchain/solidity.md) and [zkvyper](../toolchain/vyper.md) compilers for EraVM operate on -[the IR level](../toolchain/overview.md#ir-compilers), so they cannot control the heap memory allocator which remains a -responsibility of [the high-level source code compilers](../toolchain/overview.md#high-level-source-code-compilers) -emitting the IRs. - -However, there are several cases where EraVM needs to allocate memory on the heap and EVM does not. The auxiliary heap -is used for these cases: - -1. [Returning immutables](../../../../build/developer-reference/differences-with-ethereum.md#setimmutable-loadimmutable) - from the constructor. -2. Allocating calldata and return data for calling the System Contracts. - -While the ordinary heap contains calldata and return data for calls to **user contracts**, auxiliary heap contains -calldata and return data for calls to **System Contracts**. This ensures better compatibility with EVM as users should -be able to call EraVM-specific System Contracts in a transparent way, without System Contracts affecting calldata or -return data. This prevents situations where calling System Contracts interferes with the heap layout expected by the -contract developer. - -For more details on the heaps, refer to the EraVM specification, which describes -[types of heaps](https://matter-labs.github.io/eravm-spec/spec.html#data_page_params), their connections to the -[stack frames and memory growth](https://matter-labs.github.io/eravm-spec/spec.html#ctx_heap_page_id), and their role in -[communication between contracts](https://matter-labs.github.io/eravm-spec/spec.html#MemoryForwarding). diff --git a/content/40.zk-stack/components/compiler/toolchain/llvm.md b/content/40.zk-stack/components/compiler/toolchain/llvm.md deleted file mode 100644 index b6215948..00000000 --- a/content/40.zk-stack/components/compiler/toolchain/llvm.md +++ /dev/null @@ -1,33 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: LLVM Framework | zkSync Docs ---- - -# LLVM Framework - -::: warning To safeguard the security and efficiency of your application, always use the latest compiler version. ::: - -[The LLVM framework](https://github.com/matter-labs/era-compiler-llvm) is a soundly-architected and well-tested -framework for developing toolchains for smart contract languages. Its powerful intermediate representation (IR) allows -developers to design, implement, and optimize efficient language-specific features while benefiting from the extensive -LLVM ecosystem. This ensures high-performance execution, improved portability, and seamless integration with existing -LLVM-based tools. Furthermore, the modularity and extensibility of LLVM make it easier to support new smart contract -languages with LLVM front ends. - -Additionally, LLVM improves on the original EVM pipeline efficiency, as we can take advantage of the numerous -optimization passes, tools, and tests available in its mature ecosystem. - -In our toolchain, LLVM consumes the LLVM IR, applies extensive optimizations, and eventually passes the optimized IR to -the zkEVM back-end code generator in order to produce the zkEVM text assembly output. - -## Optimizer - -All our compilers utilize the state-of-the-art LLVM optimizer. By default, they optimize for performance, which -correlates with the number of VM cycles per transaction, thus affecting gas usage. The `z` option may reduce the -contract size for large contracts, making deployments cheaper while increasing the average transaction price. - -## Diving deeper - -For more information on the LLVM framework, [see the official documentation](https://llvm.org/). diff --git a/content/40.zk-stack/components/compiler/toolchain/overview.md b/content/40.zk-stack/components/compiler/toolchain/overview.md deleted file mode 100644 index 21a9e6d3..00000000 --- a/content/40.zk-stack/components/compiler/toolchain/overview.md +++ /dev/null @@ -1,87 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Compiler Toolchain Overview | zkSync Docs ---- - -# Compiler Toolchain Overview - -This section introduces the zkEVM LLVM-based compiler toolchain for smart contract languages with Ethereum Virtual -Machine (EVM) support. The toolchain works on top of existing compilers and requires their output, which typically -includes intermediate representations (IRs), abstract syntax trees (ASTs), and auxiliary contract metadata and -documentation. - -::: info At the time of writing, we support Solidity and Vyper. ::: - -The toolchain consists of the following: - -1. [High-level source code compilers](#high-level-source-code-compilers): `solc` and `vyper`. -2. [IR compilers, front ends to LLVM](#ir-compilers): `zksolc` and `zkvyper`. -3. [The LLVM framework](./llvm.md) with a zkEVM back end which emits zkEVM text assembly. -4. [The assembler](#assembler) which produces the zkEVM bytecode from text assembly. -5. [Hardhat plugins](#hardhat-plugins) which set up the environment. - -![Compiler Toolchain Visualization](../../../../assets/images/compiler-toolchain.png 'Compiler Toolchain') - -## High-level Source Code Compilers - -High-level source code is processed by third-party compilers. These compilers do the following: - -1. Process and validate the high-level source code. -2. Translate the source code into IR and metadata. -3. Pass the IR and metadata to our IR compilers via the standard I/O streams. - -We are using two high-level source code compilers at the time of writing: - -- [solc](https://github.com/ethereum/solc-bin): the official Solidity compiler. For more info, see the latest - [Solidity documentation](https://docs.soliditylang.org/en/latest/). -- [vyper](https://github.com/vyperlang/vyper/releases): the official Vyper compiler. For more info, see the latest - [Vyper documentation](https://docs.vyperlang.org/en/latest/index.html). - -::: info Security and best practices Follow the -[security considerations and best practices](../../../../build/quick-start/best-practices.md#security-and-best-practices) -to build smart contracts on zkSync Era. ::: - -## IR Compilers - -Our toolchain includes LLVM front ends, written in Rust, that process the output of high-level source code compilers: - -- [zksolc](https://github.com/matter-labs/zksolc-bin) which calls `solc` as a child process. For more info, see the - latest [zksolc documentation](./solidity.md). -- [zkvyper](https://github.com/matter-labs/zkvyper-bin): which calls `vyper` as a child process. For more info, see the - latest [zkvyper documentation](./vyper.md). - -These IR compilers perform the following steps: - -1. Receive the input, which is usually standard or combined JSON passed by the Hardhat plugin via standard input. -2. Save the relevant data, modify the input with zkEVM settings, and pass it to the underlying high-level source code - compiler which is called as a child process. -3. Receive the IR and metadata from the underlying compiler. -4. Translate the IR into LLVM IR, resolving dependencies with the help of metadata. -5. Optimize the LLVM IR with the powerful LLVM framework optimizer and emit zkEVM text assembly. -6. Print the output matching the format of the input method the IR compiler is called with. - -Our IR compilers leverage I/O mechanisms which already exist in the high-level source code compilers. They may modify -the input and output to some extent, add data for features unique to zkEVM, and remove unsupported feature artifacts. - -## Assembler - -The [assembler](https://github.com/matter-labs/era-zkEVM-assembly), which is written in Rust, compiles zkEVM assembly to -zkEVM bytecode. This tool is not a part of our LLVM back end as it uses several cryptographic libraries which are easier -to maintain outside of the framework. - -## Hardhat Plugins - -We recommend using our IR compilers via -[their corresponding Hardhat plugins](../../../../build/tooling/hardhat/getting-started.md). Add these plugins to the -Hardhat's config file to compile new projects or migrate existing ones to zkSync Era. For a lower-level approach, -download our compiler binaries via the links above and use their CLI interfaces. - -### Installing and configuring plugins - -Add the plugins below to the Hardhat's config file to compile new projects or migrate existing ones to zkSync Era. For a -lower-level approach, download our compiler binaries [links above](#ir-compilers) and use their CLI interfaces. - -- [hardhat-zksync-solc documentation](../../../../build/tooling/hardhat/hardhat-zksync-solc.md) -- [hardhat-zksync-vyper documentation](../../../../build/tooling/hardhat/hardhat-zksync-vyper.md) diff --git a/content/40.zk-stack/components/compiler/toolchain/solidity.md b/content/40.zk-stack/components/compiler/toolchain/solidity.md deleted file mode 100644 index f0ca7d7c..00000000 --- a/content/40.zk-stack/components/compiler/toolchain/solidity.md +++ /dev/null @@ -1,128 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Solidity Compiler | zkSync Docs ---- - -# Solidity - -The compiler we provide as a part of our toolchain is called [zksolc](https://github.com/matter-labs/zksolc-bin). It -operates on IR and metadata received from the underlying [solc](https://docs.soliditylang.org/en/latest/) compiler, -which must be available in `$PATH`, or its path must be explicitly passed via the CLI (command-line interface). - -::: warning To safeguard the security and efficiency of your application, always use the latest compiler version. ::: - -## Usage - -Make sure your machine satisfies the -[system requirements](https://github.com/matter-labs/era-compiler-solidity/tree/main#system-requirements). - -Using our compiler via the Hardhat plugin usually suffices. However, knowledge of its interface and I/O (input/output) -methods are crucial for integration, debugging, or contribution purposes. - -The CLI supports several I/O modes: - -1. Standard JSON. -2. Combined JSON. -3. Free-form output. - -All three modes use the standard JSON `solc` interface internally. This reduces the complexity of the `zksolc` interface -and facilitates testing. - -### Standard JSON - -The `zksolc` standard JSON I/O workflow closely follows that of the official `solc` compiler. However, `zksolc` does not -support some configuration settings which are only relevant to the EVM architecture. - -Additional zkEVM data is supported by `zksolc` but is omitted when passed to `solc`: - -- `settings/optimizer/mode`: sets the optimization mode. Available values: `0`, `1`, `2`, `3`, `s`, `z`. The default - setting is `3`. See [LLVM optimizer](./llvm.md#optimizer). -- `settings/optimizer/fallback_to_optimizing_for_size`: tries to compile again in `z` mode if the bytecode is too large - for zkEVM. -- `settings/optimizer/disable_system_request_memoization`: disables the memoization of data received in requests to - System Contracts. - -Unsupported sections of the input JSON, ignored by `zksolc`: - -- `sources/<file>/urls` -- `sources/destructible` -- `settings/stopAfter` -- `settings/evmVersion` -- `settings/debug` -- `settings/metadata`: for zkEVM you can only append `keccak256` metadata hash to the bytecode. -- `settings/modelChecker` - -Additional zkEVM data inserted by `zksolc`: - -- `long_version`: the full `solc` version output. -- `zk_version`: the `zksolc` version. -- `contract/hash`: the hash of the zkEVM bytecode. -- `contract/factory_dependencies`: bytecode hashes of contracts created in the current contract with `CREATE`. - [More details here](../../../../build/developer-reference/contract-deployment.md#note-on-factory-deps). - -Unsupported sections of the output JSON, ignored by `zksolc`: - -- `contracts/<file>/<contract>/evm/bytecode`: replaced with a JSON object with zkEVM build data. -- `contracts/<file>/<contract>/ewasm` - -See the complete standard JSON data structures in -[the zksolc repository](https://github.com/matter-labs/era-compiler-solidity/tree/main/src/solc/standard_json). - -### Combined JSON - -The `zksolc` standard JSON I/O workflow closely follows that of the official `solc` compiler. However, `zksolc` does not -support some configuration settings which are only relevant to the EVM architecture. - -Combined JSON is only an output format; there is no combined JSON input format. Instead, CLI arguments are used for -configuration. - -Additional zkEVM data, inserted by `zksolc`: - -- `zk_version`: the version of `zksolc`. -- `contract/factory_deps`: bytecode hashes of contracts created by the current contract with `CREATE`. - [More details here](../../../../build/developer-reference/contract-deployment.md#note-on-factory-deps). - -Unsupported combined JSON flags, rejected by `zksolc`: - -- `function-debug` -- `function-debug-runtime` -- `generated-sources` -- `generated-sources-runtime` -- `opcodes` -- `srcmap` -- `srcmap-runtime` - -For more information, see the complete combined JSON data structures in -[the zksolc repository](https://github.com/matter-labs/era-compiler-solidity/tree/main/src/solc/combined_json). - -### Free-form output - -This output format is utilized in Yul and LLVM IR compilation modes. These modes currently only support compiling a -single file. Only `--asm` and `--bin` output flags are supported, so this mode can be useful for debugging and -prototyping. - -## Limitations - -Currently, Solidity versions as old as `0.4.12` are supported, although **we strongly recommend using** the latest -supported revision of `0.8`, as older versions contain known bugs and have limitations dictated by the absence of IR -with sufficient level of abstraction over EVM. - -Projects written in Solidity `>=0.8` are compiled by default through the Yul pipeline, whereas those written in `<=0.7` -are compiled via EVM legacy assembly which is a less friendly IR due to its obfuscation of control-flow and call graphs. -Due to this obfuscation, there are several limitations in zkSync for contracts written in Solidity `<=0.7`: - -1. Recursion on the stack is not supported. -2. Internal function pointers are not supported. -3. Contract size and performance may be affected. - -## Using libraries - -The usage of libraries in Solidity is supported in zkSync Era with the following considerations: - -- If a Solidity library can be inlined (i.e. it only contains `private` or `internal` methods), it can be used without - any additional configuration. -- However, if a library contains at least one `public` or `external` method, it cannot be inlined and its address needs - to be passed explicitly to the compiler; see - [compiling non-inlinable libraries](../../../../build/tooling/hardhat/compiling-libraries.md#compiling-non-inlinable-libraries). diff --git a/content/40.zk-stack/components/compiler/toolchain/vyper.md b/content/40.zk-stack/components/compiler/toolchain/vyper.md deleted file mode 100644 index a2442a9b..00000000 --- a/content/40.zk-stack/components/compiler/toolchain/vyper.md +++ /dev/null @@ -1,52 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Vyper Compiler | zkSync Docs ---- - -# Vyper - -The Vyper compiler we provide as part of our toolchain is called [zkvyper](https://github.com/matter-labs/zkvyper-bin). -It operates on Vyper’s LLL IR, and metadata received from the underlying -[vyper](https://docs.vyperlang.org/en/latest/index.html) compiler, which must be available in `$PATH`, or its path must -be explicitly passed via the CLI (command-line interface). - -::: warning To safeguard the security and efficiency of your application, always use the latest compiler version. ::: - -## Usage - -Make sure your machine satisfies the -[system requirements](https://github.com/matter-labs/era-compiler-vyper/tree/main#system-requirements). - -Using our compiler via the Hardhat plugin usually suffices. However, knowledge of its interface and I/O (input/output) -methods are crucial for integration, debugging, or contribution purposes. - -#### Combined JSON - -The `zkvyper` standard JSON I/O workflow closely follows that of the official `vyper` compiler. However, `zkvyper` does -not support some configuration settings which are only relevant to the EVM architecture. - -Combined JSON is only an output format; there is no combined JSON input format. Instead, CLI arguments are used for -configuration. - -Additional zkEVM data is inserted into the output combined JSON by `zksolc`: - -- `zk_version`: the `zksolc` version. -- `contract/factory_deps`: bytecode hashes of contracts created in the current contract with `CREATE`. Since Vyper does - not support `CREATE` directly, only the forwarder can be present in this mapping. - [More details here](../../../../build/developer-reference/contract-deployment.md#note-on-factory-deps). - -Regardless of the requested output, only the `combined_json`, `abi`, `method_identifiers`, `bytecode`, -`bytecode_runtime` flags are supported, while the rest are ignored. - -Other output formats are available via the `-f` option. Check out `vyper --help` for more details. - -## Limitations - -Versions from 0.3.4 to 0.3.8 are not supported. The only supported versions are 0.3.3, 0.3.9, 0.3.10. - -Also, since there is no separation of deploy and runtime code on EraVM, the following Vyper built-ins are not supported: - -- `create_copy_of` -- `create_from_blueprint` diff --git a/content/40.zk-stack/components/fee-withdrawer.md b/content/40.zk-stack/components/fee-withdrawer.md deleted file mode 100644 index 32bd6978..00000000 --- a/content/40.zk-stack/components/fee-withdrawer.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Fee Withdrawer | zkSync Docs ---- - -# Fee Withdrawer - -[The Fee Withdrawer](https://github.com/matter-labs/era-fee-withdrawer) automates the withdrawal of the hyperchain -collected fees to an address on the base layer. - -This helps ensure the ETH operator on the base layer side has a constant influx of the gas token to keep working -properly. diff --git a/content/40.zk-stack/components/overview.md b/content/40.zk-stack/components/overview.md deleted file mode 100644 index b544ab77..00000000 --- a/content/40.zk-stack/components/overview.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Getting Started | zkSync Docs ---- - -# Overview - -ZK Stack is a modular framework for building sovereign ZK-powered Ethereum rollups (called hyperchains); it is a -modular, open-source framework that is both free and designed to build custom hyperchains (ZK-powered L2s and L3s), -based on the code of zkSync Era, the first hyperchain. - -At its core, the ZK Stack offers two key features: sovereignty and seamless connectivity. The creator (you) possesses -full rights to the code and enjoys unrestricted autonomy to customize and shape many aspects of your chain. Hyperchains -operate independently but are interconnected by a network of hyperbridges, enabling trustless, fast (within minutes), -and cheap (cost of a single transaction) interoperability. diff --git a/content/40.zk-stack/components/portal-wallet-bridge.md b/content/40.zk-stack/components/portal-wallet-bridge.md deleted file mode 100644 index 80fa1876..00000000 --- a/content/40.zk-stack/components/portal-wallet-bridge.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Portal - Wallet + Bridge | zkSync Docs ---- - -# Portal + Bridge - -[The Portal](https://github.com/matter-labs/dapp-portal) is a dApp that allows you (and your users) to easily interact -with your hyperchain. - -This includes: - -- Bridging assets to and from the L1, -- Sending them within your hyperchain, -- Checking historical transactions, and -- Managing contracts - -You can also enhance its capabilities by running [the Block Explorer Indexer/API.](./block-explorer.md) diff --git a/content/40.zk-stack/components/prover/boojum-function-check-if-satisfied.md b/content/40.zk-stack/components/prover/boojum-function-check-if-satisfied.md deleted file mode 100644 index cf67fa74..00000000 --- a/content/40.zk-stack/components/prover/boojum-function-check-if-satisfied.md +++ /dev/null @@ -1,104 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Boojum Function - `check_if_satisfied` | zkSync Docs ---- - -# Boojum Function: `check_if_satisfied` - -_Note: Please read our other documentation and tests first before reading this page._ - -Our circuits (and tests) depend on a function from Boojum called -[`check_if_satisfied`](https://github.com/matter-labs/era-boojum/blob/main/src/cs/implementations/satisfiability_test.rs#L11). -You don’t need to understand it to run circuit tests, but it can be informative to learn more about Boojum and our proof -system. - -First we prepare the constants, variables, and witness. As a reminder, the constants are just constant numbers, the -variables circuit columns that are under PLONK copy-permutation constraints (so they are close in semantics to variables -in programming languages), and the witness ephemeral values that can be used to prove certain constraints, for example -by providing an inverse if the variable must be non-zero. - -![Check_if_satisfied.png](../../../assets/images/Check_if_satisfied.png) - -Next we prepare a view. Instead of working with all of the columns at once, it can be helpful to work with only a -subset. - -![Check_if_satisfied(1).png](../../../assets/images/Check_if_satisfied-1.png) - -Next we create the paths_mappings. For each gate in the circuit, we create a vector of booleans in the correct shape. -Later, when we traverse the gates with actual inputs, we’ll be able to remember which gates should be satisfied at -particular rows by computing the corresponding selector using constant columns and the paths_mappings. - -![Check_if_satisfied(2).png](../../../assets/images/Check_if_satisfied-2.png) - -Now, we have to actually check everything. The checks for the rows depend on whether they are under general purpose -columns, or under special purpose columns. - -**General purpose rows:** - -For each row and gate, we need several things. - -- Evaluator for the gate, to compute the result of the gate -- Path for the gate from the paths_mappings, to locate the gate -- Constants_placement_offset, to find the constants -- Num_terms in the evaluator - - If this is zero, we can skip the row since there is nothing to do -- Gate_debug_name -- num_constants_used -- this_view -- placement (described below) -- evaluation function - -![Check_if_satisfied(3).png](../../../assets/images/Check_if_satisfied-3.png) - -Placement is either UniqueOnRow or MultipleOnRow. UniqueOnRow means there is only one gate on the row (typically because -the gate is larger / more complicated). MultipleOnRow means there are multiple gates within the same row (typically -because the gate is smaller). For example, if a gate only needs 30 columns, but we have 150 columns, we could include -five copies for that gate in the same row. - -Next, if the placement is UniqueOnRow, we call evaluate_over_general_purpose_columns. All of the evaluations should be -equal to zero, or we panic. - -![Check_if_satisfied(4).png](../../../assets/images/Check_if_satisfied-4.png) - -If the placement is MultipleOnRow, we again call evaluate_over_general_purpose_columns. If any of the evaluations are -non-zero, we log some extra debug information, and then panic. - -![Check_if_satisfied(7).png](../../../assets/images/Check_if_satisfied-7.png) - -This concludes evaluating and checking the generalized rows. Now we will check the specialized rows. - -![Check_if_satisfied(8).png](../../../assets/images/Check_if_satisfied-8.png) - -We start by initializing vectors for specialized_placement_data, evaluation_functions, views, and evaluator_names. Then, -we iterate over each gate_type_id and evaluator. - -![Check_if_satisfied(9).png](../../../assets/images/Check_if_satisfied-9.png) - -If gate_type_id is a LookupFormalGate, we don’t need to do anything in this loop because it is handled by the lookup -table. For all other cases, we need to check the evaluator’s total_quotient_terms_over_all_repetitions is non-zero. - -![Check_if_satisfied(11).png](../../../assets/images/Check_if_satisfied-11.png) - -Next, we get num_terms, num_repetitions, and share_constants, total_terms, initial_offset, per_repetition_offset, and -total_constants_available. All of these together form our placement data. - -![Check_if_satisfied(12).png](../../../assets/images/Check_if_satisfied-12.png) - -![Check_if_satisfied(13).png](../../../assets/images/Check_if_satisfied-13.png) - -Once we know the placement_data, we can keep it for later, as well as the evaluator for this gate. - -![Check_if_satisfied(14).png](../../../assets/images/Check_if_satisfied-14.png) - -We also will keep the view and evaluator name. This is all the data we need from our specialized columns. - -To complete the satisfiability test on the special columns, we just need to loop through and check that each of the -evaluations are zero. - -![Check_if_satisfied(16).png](../../../assets/images/Check_if_satisfied-16.png) - -![Check_if_satisfied(17).png](../../../assets/images/Check_if_satisfied-17.png) - -Now we have checked every value on every row, so the satisfiability test is passed, and we can return true. diff --git a/content/40.zk-stack/components/prover/boojum-gadgets.md b/content/40.zk-stack/components/prover/boojum-gadgets.md deleted file mode 100644 index af20665c..00000000 --- a/content/40.zk-stack/components/prover/boojum-gadgets.md +++ /dev/null @@ -1,198 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Boojum Gadgets | zkSync Docs ---- - -# Boojum Gadgets - -Gadgets in ZK programming are common arrangement of circuits abstracted for ease of use. Boojum gadgets are low-level -implementations of tools for constraint systems. They consist of various types such as curves, hash functions, lookup -tables, and different circuit types. - -These gadgets are mostly a reference from [franklin-crypto](https://github.com/matter-labs/franklin-crypto), with -additional hash functions added. These gadgets have been changed to use the Goldilocks field (order 2^64 - 2^32 + 1), -which is much smaller than bn256. This allows us to reduce the proof system. - -## Circuits types - -We have next types with we use for circuits: - -**Num (Number):** - -```rust -pub struct Num<F: SmallField> { - pub(crate) variable: Variable, - pub(crate) _marker: std::marker::PhantomData<F>, -} -``` - -**Boolean:** - -```rust -pub struct Boolean<F: SmallField> { - pub(crate) variable: Variable, - pub(crate) _marker: std::marker::PhantomData<F>, -} -``` - -**U8:** - -```rust -pub struct UInt8<F: SmallField> { - pub(crate) variable: Variable, - pub(crate) _marker: std::marker::PhantomData<F>, -} -``` - -**U16:** - -```rust -pub struct UInt16<F: SmallField> { - pub(crate) variable: Variable, - pub(crate) _marker: std::marker::PhantomData<F>, -} -``` - -**U32:** - -```rust -pub struct UInt32<F: SmallField> { - pub(crate) variable: Variable, - pub(crate) _marker: std::marker::PhantomData<F>, -} -``` - -**U160:** - -```rust -pub struct UInt160<F: SmallField> { - pub inner: [UInt32<F>; 5], -} -``` - -**U256:** - -```rust -pub struct UInt256<F: SmallField> { - pub inner: [UInt32<F>; 8], -} -``` - -**U512:** - -```rust -pub struct UInt512<F: SmallField> { - pub inner: [UInt32<F>; 16], -} -``` - -Every type consists of a Variable (the number inside Variable is just the index): - -```rust -pub struct Variable(pub(crate) u64); -``` - -which is represented in the current Field. Variable is quite diverse. To have "good" alignment and size we manually do -encoding management to be able to represent it as both a variable (that can be copied) or witness. - -The implementation of this circuit type itself is similar. We can also divide them into classes as main and dependent: -Such type like U8-U512 decoding inside functions to Num<F> for using them in logical operations. As mentioned -above, the property of these types is to perform logical operations and allocate witnesses. - -Let's demonstrate this in a Boolean example: - -```rust -impl<F: SmallField> CSAllocatable<F> for Boolean<F> { - type Witness = bool; - fn placeholder_witness() -> Self::Witness { - false - } - - #[inline(always)] - fn allocate_without_value<CS: ConstraintSystem<F>>(cs: &mut CS) -> Self { - let var = cs.alloc_variable_without_value(); - - Self::from_variable_checked(cs, var) - } - - fn allocate<CS: ConstraintSystem<F>>(cs: &mut CS, witness: Self::Witness) -> Self { - let var = cs.alloc_single_variable_from_witness(F::from_u64_unchecked(witness as u64)); - - Self::from_variable_checked(cs, var) - } -} -``` - -As you see, you can allocate both with and without witnesses. - -## Hash function - -In gadgets we have a lot of hast implementation: - -- blake2s -- keccak256 -- poseidon/poseidon2 -- sha256 - -Each of them perform different functions in our proof system. - -## Queues - -One of the most important gadgets in our system is queue. It helps us to send data between circuits. Here is the quick -explanation how it works: - -```rust -Struct CircuitQueue{ - head: HashState, - tail: HashState, - length: UInt32, - witness: VecDeque<Witness>, -} -``` - -The structure consists of `head` and `tail` commitments that basically are rolling hashes. Also, it has a `length` of -the queue. These three fields are allocated inside the constraint system. Also, there is a `witness`, that keeps actual -values that are now stored in the queue. - -And here is the main functions: - -```rust -fn push(&mut self, value: Element) { - // increment length - // head - hash(head, value) - // witness.push_back(value.witness) -} - -fn pop(&mut self) -> Element { - // check length > 0 - // decrement length - // value = witness.pop_front() - // tail = hash(tail, value) - // return value -} - -fn final_check(&self) -> Element { - // check that length == 0 - // check that head == tail -} -``` - -So the key point, of how the queue proofs that popped elements are the same as pushed ones, is equality of rolling -hashes that stored in fields `head` and `tail`. - -Also, we check that we can’t pop an element before it was pushed. This is done by checking that `length >= 0`. - -Very important is making the `final_check` that basically checks the equality of two hashes. So if the queue is never -empty, and we haven’t checked the equality of `head` and `tail` in the end, we also haven’t proven that the elements we -popped are correct. - -For now, we use poseidon2 hash. Here is the link to queue implementations: - -- [CircuitQueue](https://github.com/matter-labs/era-boojum/blob/main/src/gadgets/queue/mod.rs#L29) -- [FullStateCircuitQueue](https://github.com/matter-labs/era-boojum/blob/main/src/gadgets/queue/full_state_queue.rs#L20C12-L20C33) - -The difference is that we actually compute and store a hash inside CircuitQueue during `push` and `pop` operations. But -in FullStateCircuitQueue our `head` and `tail` are just states of sponges. So instead of computing a full hash, we just -absorb a pushed (popped) element. diff --git a/content/40.zk-stack/components/prover/circuit-testing/README.md b/content/40.zk-stack/components/prover/circuit-testing/README.md deleted file mode 100644 index 254c2ca3..00000000 --- a/content/40.zk-stack/components/prover/circuit-testing/README.md +++ /dev/null @@ -1,66 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Circuit Testing | zkSync Docs ---- - -# Circuit testing - -This page explains unit tests for circuits. Specifically, it goes through a unit test of -[ecrecover](https://github.com/matter-labs/era-zkevm_circuits/blob/main/src/ecrecover/mod.rs#L796). The tests for other -circuits are very similar. - -Many of the tests for different circuits are nearly identical, for example: - -- test_signature_for_address_verification (ecrecover) -- test_code_unpacker_inner -- test_demultiplex_storage_logs_inner -- and several others. - -If you understand one, you will quickly be able to understand them all. - -Let’s focus on ecrecover. Ecrecover is a precompile that, given your signature, can compute your address. If our circuit -works correctly, we should be able to recover the proper address, and be able to prove the computation was done -correctly. - -![ECRecover testing](../../../../assets/images/circuit-ecrecover.png) - -The test begins by defining `geometry`, `max_variables`, and `max_trace_len`. This data will be used to create the -constraint system. Next, we define a helper function: - -![ECRecover geometry](../../../../assets/images/circuits-ecrecover-geometry.png) - -To help run the test, we have a helper function called `configure` that returns a builder. The builder knows all of the -gates and gate placement strategy, which will be useful for setting up the constraint system. - -![Code block showing usage of `configure`](../../../../assets/images/circuits-configure-builder.png) - -The constraint system is almost ready! We still need to add the lookup tables for common boolean functions: - -![Code block showing creation of lookup tables](../../../../assets/images/circuit-lookup.png) - -Now the constraint system is ready! We can start the main part of the test! - -![Code block showing signature simulation](../../../../assets/images/circuits-address.png) - -Here we have hard coded a secret key with its associated public key, and generate a signature. We will test our circuit -on these inputs! Next we “allocate” these inputs as witnessess: - -![Code block showing witness allocation](../../../../assets/images/circuit-allocate.png) - -We have to use special integer types because we are working in a finite field. - -![Code block showing integer types](../../../../assets/images/circuit-finite-fields.png) - -The constants here are specific to the curve used, and are described in detail by code comments in the -ecrecover_precompile_inner_routine. - -Finally we can call the ecrecover_precompile_inner_routine: - -![Code block showing ecrecover precompile](../../../../assets/images/circuit-ecrecover-precompile.png) - -Lastly, we need to check to make sure that 1) we recovered the correct address, and 2) the constraint system can be -satisfied, meaning the proof works. - -![Code block comparing recovered address with original](../../../../assets/images/circuit-compare-addresses.png) diff --git a/content/40.zk-stack/components/prover/circuits/code-decommitter.md b/content/40.zk-stack/components/prover/circuits/code-decommitter.md deleted file mode 100644 index 7a62b43d..00000000 --- a/content/40.zk-stack/components/prover/circuits/code-decommitter.md +++ /dev/null @@ -1,215 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Circuits - Code Decommitter | zkSync Docs ---- - -# CodeDecommitter - -## CodeDecommitter PI - -### [Input](https://github.com/matter-labs/era-zkevm_circuits/blob/main/src/code_unpacker_sha256/input.rs#L80) - -```rust -pub struct CodeDecommitterInputData<F: SmallField> { - pub memory_queue_initial_state: QueueState<F, FULL_SPONGE_QUEUE_STATE_WIDTH>, - pub sorted_requests_queue_initial_state: QueueState<F, FULL_SPONGE_QUEUE_STATE_WIDTH>, -} -``` - -### [Output](https://github.com/matter-labs/era-zkevm_circuits/blob/main/src/code_unpacker_sha256/input.rs#L100) - -```rust -pub struct CodeDecommitterOutputData<F: SmallField> { - pub memory_queue_final_state: QueueState<F, FULL_SPONGE_QUEUE_STATE_WIDTH>, -} -``` - -### [FSM Input and FSM Output](https://github.com/matter-labs/era-zkevm_circuits/blob/main/src/code_unpacker_sha256/input.rs#L61) - -```rust -pub struct CodeDecommitterFSMInputOutput<F: SmallField> { - pub internal_fsm: CodeDecommittmentFSM<F>, - pub decommittment_requests_queue_state: QueueState<F, FULL_SPONGE_QUEUE_STATE_WIDTH>, - pub memory_queue_state: QueueState<F, FULL_SPONGE_QUEUE_STATE_WIDTH>, -} - -pub struct CodeDecommittmentFSM<F: SmallField> { - pub sha256_inner_state: [UInt32<F>; 8], // 8 uint32 words of internal sha256 state - pub hash_to_compare_against: UInt256<F>, - pub current_index: UInt32<F>, - pub current_page: UInt32<F>, - pub timestamp: UInt32<F>, - pub num_rounds_left: UInt16<F>, - pub length_in_bits: UInt32<F>, - pub state_get_from_queue: Boolean<F>, - pub state_decommit: Boolean<F>, - pub finished: Boolean<F>, -} -``` - -## Main circuit logic - -This circuit takes a queue of decommit requests for DecommitSorter circuit. For each decommit request, it checks that -the linear hash of all opcodes will be equal to this hash that is stored in the decommit request. Also, it writes code -to the corresponding memory page. Briefly, it unpacks the queue from the opcode and updates the memory queue and check -correctness. - -### [First part](https://github.com/matter-labs/era-zkevm_circuits/blob/main/src/code_unpacker_sha256/mod.rs#L48) - -The circuit begins with allocating input part of the PI. - -```rust -let CodeDecommitterCircuitInstanceWitness { - closed_form_input, - sorted_requests_queue_witness, - code_words, -} = witness; - -let mut structured_input = - CodeDecommitterCycleInputOutput::alloc_ignoring_outputs(cs, closed_form_input.clone()); -``` - -We chose what `memory_queue` state and `decommitments_queue` state to continue to work with. - -```rust -let requests_queue_state = QueueState::conditionally_select( - cs, - structured_input.start_flag, - &structured_input - .observable_input - .sorted_requests_queue_initial_state, - &structured_input - .hidden_fsm_input - .decommittment_requests_queue_state, -); - -let memory_queue_state = QueueState::conditionally_select( - cs, - structured_input.start_flag, - &structured_input.observable_input.memory_queue_initial_state, - &structured_input.hidden_fsm_input.memory_queue_state, -); -``` - -We do the same with inner FSM part. - -```rust -let initial_state = CodeDecommittmentFSM::conditionally_select( - cs, - structured_input.start_flag, - &starting_fsm_state, - &structured_input.hidden_fsm_input.internal_fsm, -); -``` - -### [Main part](https://github.com/matter-labs/era-zkevm_circuits/blob/main/src/code_unpacker_sha256/mod.rs#L168) - -Here’s the part, where all the main logic is implemented. Firstly, we take a new decommit request if the queue is not -empty yet. - -```rust -let (may_be_new_request, _) = - unpack_requests_queue.pop_front(cs, state.state_get_from_queue); -``` - -Then we update the state of the circuit. - -```rust -state.num_rounds_left = UInt16::conditionally_select( - cs, - state.state_get_from_queue, - &length_in_rounds, - &state.num_rounds_left, -); -... -``` - -Then we create two write memory queries and push them to memory queue. - -```rust -let mem_query_0 = MemoryQuery { - timestamp: state.timestamp, - memory_page: state.current_page, - index: state.current_index, - rw_flag: boolean_true, - value: code_word_0, - is_ptr: boolean_false, -}; - -let mem_query_1 = MemoryQuery { - timestamp: state.timestamp, - memory_page: state.current_page, - index: state.current_index, - rw_flag: boolean_true, - value: code_word_1, - is_ptr: boolean_false, -}; - -memory_queue.push(cs, mem_query_0, state.state_decommit); -memory_queue.push(cs, mem_query_1, process_second_word); -``` - -Now we create a new input for hash to be absorbed. - -```rust -let mut sha256_input = [zero_u32; 16]; -for (dst, src) in sha256_input.iter_mut().zip( - code_word_0_be_bytes - .array_chunks::<4>() - .chain(code_word_1_be_bytes.array_chunks::<4>()), -) { - *dst = UInt32::from_be_bytes(cs, *src); -} -``` - -And absorb it to current state. - -```rust -let mut new_internal_state = state.sha256_inner_state; -round_function_over_uint32(cs, &mut new_internal_state, &sha256_input); -``` - -Also, we update current state. - -```rust -state.sha256_inner_state = <[UInt32<F>; 8]>::conditionally_select( - cs, - state.state_decommit, - &new_internal_state, - &state.sha256_inner_state, -); -``` - -Finally, we check the hash if necessary. - -```rust -for (part_of_first, part_of_second) in hash - .inner - .iter() - .zip(state.hash_to_compare_against.inner.iter()) -{ - Num::conditionally_enforce_equal( - cs, - finalize, - &part_of_first.into_num(), - &part_of_second.into_num(), - ); -} -``` - -### [Final part](https://github.com/matter-labs/era-zkevm_circuits/blob/main/src/code_unpacker_sha256/mod.rs#L111) - -Now we update PI output parts and compute a commitment. Then we allocate it as public variables. - -```rust -let compact_form = - ClosedFormInputCompactForm::from_full_form(cs, &structured_input, round_function); - -let input_commitment = commit_variable_length_encodable_item(cs, &compact_form, round_function); -for el in input_commitment.iter() { - let gate = PublicInputGate::new(el.get_variable()); - gate.add_to_cs(cs); -} -``` diff --git a/content/40.zk-stack/components/prover/circuits/demux-log-queue.md b/content/40.zk-stack/components/prover/circuits/demux-log-queue.md deleted file mode 100644 index 6f2c354e..00000000 --- a/content/40.zk-stack/components/prover/circuits/demux-log-queue.md +++ /dev/null @@ -1,233 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Circuits - DemuxLogQueue | zkSync Docs ---- - -# DemuxLogQueue - -## DemuxLogQueue PI - -### [Input](https://github.com/matter-labs/era-zkevm_circuits/blob/main/src/demux_log_queue/input.rs#L49) - -```rust -pub struct LogDemuxerInputData<F: SmallField> { - pub initial_log_queue_state: QueueState<F, QUEUE_STATE_WIDTH>, -} -``` - -### [Output](https://github.com/matter-labs/era-zkevm_circuits/blob/main/src/fsm_input_output/circuit_inputs/main_vm.rs#L33) - -```rust -pub struct LogDemuxerOutputData<F: SmallField> { - pub storage_access_queue_state: QueueState<F, QUEUE_STATE_WIDTH>, - pub events_access_queue_state: QueueState<F, QUEUE_STATE_WIDTH>, - pub l1messages_access_queue_state: QueueState<F, QUEUE_STATE_WIDTH>, - pub keccak256_access_queue_state: QueueState<F, QUEUE_STATE_WIDTH>, - pub sha256_access_queue_state: QueueState<F, QUEUE_STATE_WIDTH>, - pub ecrecover_access_queue_state: QueueState<F, QUEUE_STATE_WIDTH>, -} -``` - -### [FSM Input and FSM Output](https://github.com/matter-labs/era-zkevm_circuits/blob/main/src/demux_log_queue/input.rs#L22) - -```rust -pub struct LogDemuxerFSMInputOutput<F: SmallField> { - pub initial_log_queue_state: QueueState<F, QUEUE_STATE_WIDTH>, - pub storage_access_queue_state: QueueState<F, QUEUE_STATE_WIDTH>, - pub events_access_queue_state: QueueState<F, QUEUE_STATE_WIDTH>, - pub l1messages_access_queue_state: QueueState<F, QUEUE_STATE_WIDTH>, - pub keccak256_access_queue_state: QueueState<F, QUEUE_STATE_WIDTH>, - pub sha256_access_queue_state: QueueState<F, QUEUE_STATE_WIDTH>, - pub ecrecover_access_queue_state: QueueState<F, QUEUE_STATE_WIDTH>, -} -``` - -## Main circuit logic - -The input of Log_Demuxer receives log_queue, consisting of a request to storage, events, L1messages request, and a -request to the precompiles ecrecover, sha256, and keccak256. It divides this queue into six new queues. See our diagram. - -### Start - -The function of circuits is `demultiplex_storage_logs_enty_point`. We start for allocation of queue witnesses: - -```rust -let mut structured_input = - LogDemuxerInputOutput::alloc_ignoring_outputs(cs, closed_form_input.clone()); -``` - -Then we must verify that no elements have already been retrieved from the queue: - -```rust -structured_input - .observable_input - .initial_log_queue_state - .enforce_trivial_head(cs); -``` - -So long as `tail` is some equivalent of the merkle tree root and `head` is an equivalent of the current node hash, we -provide some path witness when we pop elements and require that we properly end up in the root. So we must prove that -element of head is zero: - -```rust -pub fn enforce_trivial_head<CS: ConstraintSystem<F>>(&self, cs: &mut CS) { - let zero_num = Num::zero(cs); - for el in self.head.iter() { - Num::enforce_equal(cs, el, &zero_num); - } -} -``` - -Depends on `start_flag` we select which queue `observable_input` or `fsm_input`(internal intermediate queue) we took: - -```rust -let state = QueueState::conditionally_select( - cs, - structured_input.start_flag, - &structured_input.observable_input.initial_log_queue_state, - &structured_input.hidden_fsm_input.initial_log_queue_state, -); -``` - -Wrap the state and witnesses in `StorageLogQueue`, thereby preparing the input data for `inner` part: - -```rust -let mut initial_queue = StorageLogQueue::<F, R>::from_state(cs, state); -use std::sync::Arc; -let initial_queue_witness = CircuitQueueWitness::from_inner_witness(initial_queue_witness); -initial_queue.witness = Arc::new(initial_queue_witness); -``` - -For the rest, it selects between empty or from FSM: - -```rust -let queue_states_from_fsm = [ -&structured_input.hidden_fsm_input.storage_access_queue_state, -&structured_input.hidden_fsm_input.events_access_queue_state, -&structured_input - .hidden_fsm_input - .l1messages_access_queue_state, -&structured_input - .hidden_fsm_input - .keccak256_access_queue_state, -&structured_input.hidden_fsm_input.sha256_access_queue_state, -&structured_input - .hidden_fsm_input - .ecrecover_access_queue_state, -]; - -let empty_state = QueueState::empty(cs); -let [mut storage_access_queue, mut events_access_queue, mut l1messages_access_queue, mut keccak256_access_queue, mut sha256_access_queue, mut ecrecover_access_queue] = -queue_states_from_fsm.map(|el| { -let state = QueueState::conditionally_select( - cs, - structured_input.start_flag, - &empty_state, - &el, - ); - StorageLogQueue::<F, R>::from_state(cs, state) -}); -``` - -Prepared all queues into `input_queues` and call `inner` part: - -```rust -demultiplex_storage_logs_inner(cs, &mut initial_queue, input_queues, limit); -``` - -The last step is to form the final state. The flag `completed` shows us if `initial_queue` is empty or not. If not, we -fill fsm_output. If it is empty, we select observable_output for the different queues. - -Finally, we compute a commitment to PublicInput and allocate it as witness variables. - -```rust -let compact_form = - ClosedFormInputCompactForm::from_full_form(cs, &structured_input, round_function); - -let input_commitment = commit_variable_length_encodable_item(cs, &compact_form, round_function); -for el in input_commitment.iter() { - let gate = PublicInputGate::new(el.get_variable()); - gate.add_to_cs(cs); -} -``` - -### Inner part - -This is the logic part of the circuit. It depends on the main queue `storage_log_queue`, which separates the other -queues. After we have dealt with the initial precompile, we need to allocate constant addresses for -`keccak_precompile_address`, `sha256_precompile_address`, `ecrecover_precompile_address` and allocate constants for -`STORAGE_AUX_BYTE`, `EVENT_AUX_BYTE`, `L1_MESSAGE_AUX_BYTE`, `PRECOMPILE_AUX_BYTE`. Execution happens when we pop all -elements from `storage_log_queue`. We have appropriate flags for this, which depend on each other: - -```rust -let queue_is_empty = storage_log_queue.is_empty(cs); -let execute = queue_is_empty.negated(cs); -``` - -Here, we choose flags depending on the popped element data: - -```rust -let is_storage_aux_byte = UInt8::equals(cs, &aux_byte_for_storage, &popped.0.aux_byte); -let is_event_aux_byte = UInt8::equals(cs, &aux_byte_for_event, &popped.0.aux_byte); -let is_l1_message_aux_byte = - UInt8::equals(cs, &aux_byte_for_l1_message, &popped.0.aux_byte); -let is_precompile_aux_byte = - UInt8::equals(cs, &aux_byte_for_precompile_call, &popped.0.aux_byte); - -let is_keccak_address = UInt160::equals(cs, &keccak_precompile_address, &popped.0.address); -let is_sha256_address = UInt160::equals(cs, &sha256_precompile_address, &popped.0.address); -let is_ecrecover_address = - UInt160::equals(cs, &ecrecover_precompile_address, &popped.0.address); -``` - -Put up the right flag for shards: - -```rust -let is_rollup_shard = popped.0.shard_id.is_zero(cs); -let is_porter_shard = is_rollup_shard.negated(cs); -``` - -Execute all and push them into output queues: - -```rust -let execute_rollup_storage = Boolean::multi_and(cs, &[is_storage_aux_byte, is_rollup_shard, execute]); -let execute_porter_storage = Boolean::multi_and(cs, &[is_storage_aux_byte, is_porter_shard, execute]); - -let execute_event = Boolean::multi_and(cs, &[is_event_aux_byte, execute]); -let execute_l1_message = Boolean::multi_and(cs, &[is_l1_message_aux_byte, execute]); -let execute_keccak_call = Boolean::multi_and(cs, &[is_precompile_aux_byte, is_keccak_address, execute]); -let execute_sha256_call = Boolean::multi_and(cs, &[is_precompile_aux_byte, is_sha256_address, execute]); -let execute_ecrecover_call = Boolean::multi_and(cs, &[is_precompile_aux_byte, is_ecrecover_address, execute]); - -let bitmask = [ - execute_rollup_storage, - execute_event, - execute_l1_message, - execute_keccak_call, - execute_sha256_call, - execute_ecrecover_call, -]; - -push_with_optimize( - cs, - [ - rollup_storage_queue, - events_queue, - l1_messages_queue, - keccak_calls_queue, - sha256_calls_queue, - ecdsa_calls_queue, - ], - bitmask, - popped.0, -); -``` - -Note: since we do not have a porter, the flag is automatically set to `false`: - -```rust -let boolean_false = Boolean::allocated_constant(cs, false); -Boolean::enforce_equal(cs, &execute_porter_storage, &boolean_false); -``` diff --git a/content/40.zk-stack/components/prover/circuits/ecrecover.md b/content/40.zk-stack/components/prover/circuits/ecrecover.md deleted file mode 100644 index 60f49ee4..00000000 --- a/content/40.zk-stack/components/prover/circuits/ecrecover.md +++ /dev/null @@ -1,327 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Circuits - ECRecover | zkSync Docs ---- - -# Ecrecover - -## Ecrecover PI - -### [Input](https://github.com/matter-labs/era-zkevm_circuits/blob/main/src/fsm_input_output/circuit_inputs/main_vm.rs#L9) - -```rust -pub struct PrecompileFunctionInputData<F: SmallField> { - pub initial_log_queue_state: QueueState<F, QUEUE_STATE_WIDTH>, - pub initial_memory_queue_state: QueueState<F, FULL_SPONGE_QUEUE_STATE_WIDTH>, -} -``` - -### [Output](https://github.com/matter-labs/era-zkevm_circuits/blob/main/src/base_structures/precompile_input_outputs/mod.rs#L42) - -```rust -pub struct PrecompileFunctionOutputData<F: SmallField> { - pub final_memory_state: QueueState<F, FULL_SPONGE_QUEUE_STATE_WIDTH>, -} -``` - -### [FSM Input and FSM Output](https://github.com/matter-labs/era-zkevm_circuits/blob/main/src/keccak256_round_function/input.rs#L59) - -```rust -pub struct EcrecoverCircuitFSMInputOutput<F: SmallField> { - pub log_queue_state: QueueState<F, QUEUE_STATE_WIDTH>, - pub memory_queue_state: QueueState<F, FULL_SPONGE_QUEUE_STATE_WIDTH>, -} -``` - -## Main circuit logic - -This circuit implements the ecrecover precompile described in the Ethereum yellow paper: -<https://ethereum.github.io/yellowpaper/paper.pdf> - -The purpose of ecrecover is to recover the signer’s public key from digital signature. - -A special note about this circuit is that there are hardcoded ‘valid’ field element values provided to the circuit. This -is to prevent the circuit from not satisfying in case the user-provided inputs are incorrect and, when the circuit -detects this, the bad values are swapped out for the hardcoded ones. In this event, exceptions are logged and pushed -into a vector which are returned to the caller, informing them that the provided inputs were incorrect and the result -should be discarded. - -Most of the relevant circuit logic resides in the `ecrecover_precompile_inner_routine` function. Let’s take the circuit -step by step. - -1. The circuit starts off by declaring a set of constants which are useful to have throughout the circuit. These include - the B parameter of the secp256k1 curve, the constant -1 in the curve’s base field, and the base field and scalar - field modulus. We also create the vector that should capture any exceptions. - -```rust -let curve_b = Secp256Affine::b_coeff(); - -let mut minus_one = Secp256Fq::one(); -minus_one.negate(); - -let mut curve_b_nn = - Secp256BaseNNField::<F>::allocated_constant(cs, curve_b, &base_field_params); -let mut minus_one_nn = - Secp256BaseNNField::<F>::allocated_constant(cs, minus_one, &base_field_params); - -let secp_n_u256 = U256([ - scalar_field_params.modulus_u1024.as_ref().as_words()[0], - scalar_field_params.modulus_u1024.as_ref().as_words()[1], - scalar_field_params.modulus_u1024.as_ref().as_words()[2], - scalar_field_params.modulus_u1024.as_ref().as_words()[3], -]); -let secp_n_u256 = UInt256::allocated_constant(cs, secp_n_u256); - -let secp_p_u256 = U256([ - base_field_params.modulus_u1024.as_ref().as_words()[0], - base_field_params.modulus_u1024.as_ref().as_words()[1], - base_field_params.modulus_u1024.as_ref().as_words()[2], - base_field_params.modulus_u1024.as_ref().as_words()[3], -]); -let secp_p_u256 = UInt256::allocated_constant(cs, secp_p_u256); - -let mut exception_flags = ArrayVec::<_, EXCEPTION_FLAGS_ARR_LEN>::new(); -``` - -1. Next, the circuit checks whether or not the given `x` input (which is the x-coordinate of the signature) falls within - the scalar field of the curve. Since, in ecrecover, `x = r + kn`, almost any `r` will encode a unique x-coordinate, - except for when `r > scalar_field_modulus`. If this is the case, `x = r + n`, otherwise, `x = r`. `x` is recovered - here from `r`. - -```rust -let [y_is_odd, x_overflow, ..] = - Num::<F>::from_variable(recid.get_variable()).spread_into_bits::<_, 8>(cs); - -let (r_plus_n, of) = r.overflowing_add(cs, &secp_n_u256); -let mut x_as_u256 = UInt256::conditionally_select(cs, x_overflow, &r_plus_n, &r); -let error = Boolean::multi_and(cs, &[x_overflow, of]); -exception_flags.push(error); - -// we handle x separately as it is the only element of base field of a curve (not a scalar field element!) -// check that x < q - order of base point on Secp256 curve -// if it is not actually the case - mask x to be zero -let (_res, is_in_range) = x_as_u256.overflowing_sub(cs, &secp_p_u256); -x_as_u256 = x_as_u256.mask(cs, is_in_range); -let x_is_not_in_range = is_in_range.negated(cs); -exception_flags.push(x_is_not_in_range); -``` - -1. Then, all field elements are interpreted as such within the circuit. As they are passed in, they are simply byte - arrays which are interpreted initially as `UInt256` numbers. These get converted to field elements by using the - conversion functions defined near the top of the file. Additionally, checks are done to make sure none of the passed - in field elements are zero. - -```rust -let mut x_fe = convert_uint256_to_field_element(cs, &x_as_u256, &base_field_params); - -let (mut r_fe, r_is_zero) = - convert_uint256_to_field_element_masked(cs, &r, &scalar_field_params); -exception_flags.push(r_is_zero); -let (mut s_fe, s_is_zero) = - convert_uint256_to_field_element_masked(cs, &s, &scalar_field_params); -exception_flags.push(s_is_zero); - -// NB: although it is not strictly an exception we also assume that hash is never zero as field element -let (mut message_hash_fe, message_hash_is_zero) = - convert_uint256_to_field_element_masked(cs, &message_hash, &scalar_field_params); -exception_flags.push(message_hash_is_zero); -``` - -1. Now we are going to compute `t` and check whether or not it is quadratic residue in the base field. To start, we take - `x` which we calculated before, and calculate `t` by doing `x^3 + b`, where `b` is the B parameter of the secp256k1 - curve. We check to make sure that `t` is not zero. - -```rust -let mut t = x_fe.square(cs); // x^2 -t = t.mul(cs, &mut x_fe); // x^3 -t = t.add(cs, &mut curve_b_nn); // x^3 + b - -let t_is_zero = t.is_zero(cs); -exception_flags.push(t_is_zero); -``` - -1. The Legendre symbol for `t` is computed to do a quadratic residue check. We need to compute `t^b` which corresponds - to `t^{2^255} / ( t^{2^31} * t^{2^8} * t^{2^7} * t^{2^6} * t^{2^5} * t^{2^3} * t)`. First, an array of powers of `t` - is created (up to `t^255`). Then, we multiply together all the elements in the denominator of the equation, which are - `t^{2^31} * t^{2^8} * t^{2^7} * t^{2^6} * t^{2^5} * t^{2^3} * t`. Lastly, the division is performed and we end up - with `t^b`. - -```rust -let t_is_zero = t.is_zero(cs); // We first do a zero check -exception_flags.push(t_is_zero); - -// if t is zero then just mask -let t = Selectable::conditionally_select(cs, t_is_zero, &valid_t_in_external_field, &t); - -// array of powers of t of the form t^{2^i} starting from i = 0 to 255 -let mut t_powers = Vec::with_capacity(X_POWERS_ARR_LEN); -t_powers.push(t); - -for _ in 1..X_POWERS_ARR_LEN { - let prev = t_powers.last_mut().unwrap(); - let next = prev.square(cs); - t_powers.push(next); -} - -let mut acc = t_powers[0].clone(); -for idx in [3, 5, 6, 7, 8, 31].into_iter() { - let other = &mut t_powers[idx]; - acc = acc.mul(cs, other); -} -let mut legendre_symbol = t_powers[255].div_unchecked(cs, &mut acc); -``` - -1. Before we proceed to the quadratic residue check, we take advantage of the powers we just calculated to compute the - square root of `t`, in order to determine whether the y-coordinate of the signature we’ve passed is positive or - negative. - -```rust -let mut acc_2 = t_powers[2].clone(); -for idx in [4, 5, 6, 7, 30].into_iter() { - let other = &mut t_powers[idx]; - acc_2 = acc_2.mul(cs, other); -} - -let mut may_be_recovered_y = t_powers[254].div_unchecked(cs, &mut acc_2); -may_be_recovered_y.normalize(cs); -let mut may_be_recovered_y_negated = may_be_recovered_y.negated(cs); -may_be_recovered_y_negated.normalize(cs); - -let [lowest_bit, ..] = - Num::<F>::from_variable(may_be_recovered_y.limbs[0]).spread_into_bits::<_, 16>(cs); - -// if lowest bit != parity bit, then we need conditionally select -let should_swap = lowest_bit.xor(cs, y_is_odd); -let may_be_recovered_y = Selectable::conditionally_select( - cs, - should_swap, - &may_be_recovered_y_negated, - &may_be_recovered_y, -); -``` - -1. Then, proceed with the quadratic residue check. In case `t` is nonresidue, we swap out our inputs for the hardcoded - ‘valid’ inputs. - -```rust -let t_is_nonresidue = - Secp256BaseNNField::<F>::equals(cs, &mut legendre_symbol, &mut minus_one_nn); -exception_flags.push(t_is_nonresidue); -// unfortunately, if t is found to be a quadratic nonresidue, we can't simply let x to be zero, -// because then t_new = 7 is again a quadratic nonresidue. So, in this case we let x to be 9, then -// t = 16 is a quadratic residue -let x = - Selectable::conditionally_select(cs, t_is_nonresidue, &valid_x_in_external_field, &x_fe); -let y = Selectable::conditionally_select( - cs, - t_is_nonresidue, - &valid_y_in_external_field, - &may_be_recovered_y, -); -``` - -1. The next step is computing the public key. We compute the public key `Q` by calculating `Q = (s * X - hash * G) / r`. - We can simplify this in-circuit by calculating `s / r` and `hash / r` separately, and then doing an MSM to get the - combined output. First, we pre-compute these divided field elements, and then compute the point like so: - -```rust -let mut r_fe_inversed = r_fe.inverse_unchecked(cs); -let mut s_by_r_inv = s_fe.mul(cs, &mut r_fe_inversed); -let mut message_hash_by_r_inv = message_hash_fe.mul(cs, &mut r_fe_inversed); - -s_by_r_inv.normalize(cs); -message_hash_by_r_inv.normalize(cs); - -let mut gen_negated = Secp256Affine::one(); -gen_negated.negate(); -let (gen_negated_x, gen_negated_y) = gen_negated.into_xy_unchecked(); -let gen_negated_x = - Secp256BaseNNField::allocated_constant(cs, gen_negated_x, base_field_params); -let gen_negated_y = - Secp256BaseNNField::allocated_constant(cs, gen_negated_y, base_field_params); - -let s_by_r_inv_normalized_lsb_bits: Vec<_> = s_by_r_inv - .limbs - .iter() - .map(|el| Num::<F>::from_variable(*el).spread_into_bits::<_, 16>(cs)) - .flatten() - .collect(); -let message_hash_by_r_inv_lsb_bits: Vec<_> = message_hash_by_r_inv - .limbs - .iter() - .map(|el| Num::<F>::from_variable(*el).spread_into_bits::<_, 16>(cs)) - .flatten() - .collect(); - -let mut recovered_point = (x, y); -let mut generator_point = (gen_negated_x, gen_negated_y); -// now we do multiexponentiation -let mut q_acc = - SWProjectivePoint::<F, Secp256Affine, Secp256BaseNNField<F>>::zero(cs, base_field_params); - -// we should start from MSB, double the accumulator, then conditionally add -for (cycle, (x_bit, hash_bit)) in s_by_r_inv_normalized_lsb_bits - .into_iter() - .rev() - .zip(message_hash_by_r_inv_lsb_bits.into_iter().rev()) - .enumerate() -{ - if cycle != 0 { - q_acc = q_acc.double(cs); - } - let q_plus_x = q_acc.add_mixed(cs, &mut recovered_point); - let mut q_0: SWProjectivePoint<F, Secp256Affine, NonNativeFieldOverU16<F, Secp256Fq, 17>> = - Selectable::conditionally_select(cs, x_bit, &q_plus_x, &q_acc); - - let q_plux_gen = q_0.add_mixed(cs, &mut generator_point); - let q_1 = Selectable::conditionally_select(cs, hash_bit, &q_plux_gen, &q_0); - - q_acc = q_1; -} - -let ((mut q_x, mut q_y), is_infinity) = - q_acc.convert_to_affine_or_default(cs, Secp256Affine::one()); -exception_flags.push(is_infinity); -let any_exception = Boolean::multi_or(cs, &exception_flags[..]); - -q_x.normalize(cs); -q_y.normalize(cs); -``` - -1. Now that we have our public key recovered, the last thing we will need to do is take the keccak hash of the public - key and then take the first 20 bytes to recover the address. - -```rust -let zero_u8 = UInt8::zero(cs); - -let mut bytes_to_hash = [zero_u8; 64]; -let it = q_x.limbs[..16] - .iter() - .rev() - .chain(q_y.limbs[..16].iter().rev()); - -for (dst, src) in bytes_to_hash.array_chunks_mut::<2>().zip(it) { - let limb = unsafe { UInt16::from_variable_unchecked(*src) }; - *dst = limb.to_be_bytes(cs); -} - -let mut digest_bytes = keccak256(cs, &bytes_to_hash); -// digest is 32 bytes, but we need only 20 to recover address -digest_bytes[0..12].copy_from_slice(&[zero_u8; 12]); // empty out top bytes -digest_bytes.reverse(); -``` - -1. At this point, we are basically done! What’s left now is to ensure we send a masked value in case of any exception, - and then we can output the resulting address and any exceptions which occurred for the caller to handle. This wraps - up the ecrecover circuit! - -```rust -let written_value_unmasked = UInt256::from_le_bytes(cs, digest_bytes); - -let written_value = written_value_unmasked.mask_negated(cs, any_exception); -let all_ok = any_exception.negated(cs); - -(all_ok, written_value) // Return any exceptions and the resulting address value -``` diff --git a/content/40.zk-stack/components/prover/circuits/keccak-round-function.md b/content/40.zk-stack/components/prover/circuits/keccak-round-function.md deleted file mode 100644 index 3c44ba14..00000000 --- a/content/40.zk-stack/components/prover/circuits/keccak-round-function.md +++ /dev/null @@ -1,210 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Circuits - KeccakRoundFunction | zkSync Docs ---- - -# KeccakRoundFunction - -## KeccakRoundFunction PI - -### [Input](https://github.com/matter-labs/era-zkevm_circuits/blob/main/src/fsm_input_output/circuit_inputs/main_vm.rs#L9) - -```rust -pub struct PrecompileFunctionInputData<F: SmallField> { - pub initial_log_queue_state: QueueState<F, QUEUE_STATE_WIDTH>, - pub initial_memory_queue_state: QueueState<F, FULL_SPONGE_QUEUE_STATE_WIDTH>, -} -``` - -### [Output](https://github.com/matter-labs/era-zkevm_circuits/blob/main/src/base_structures/precompile_input_outputs/mod.rs#L42) - -```rust -pub struct PrecompileFunctionOutputData<F: SmallField> { - pub final_memory_state: QueueState<F, FULL_SPONGE_QUEUE_STATE_WIDTH>, -} -``` - -### [FSM Input and FSM Output](https://github.com/matter-labs/era-zkevm_circuits/blob/main/src/keccak256_round_function/input.rs#L59) - -```rust -pub struct Keccak256RoundFunctionFSMInputOutput<F: SmallField> { - pub internal_fsm: Keccak256RoundFunctionFSM<F>, - pub log_queue_state: QueueState<F, QUEUE_STATE_WIDTH>, - pub memory_queue_state: QueueState<F, FULL_SPONGE_QUEUE_STATE_WIDTH>, -} - -pub struct Keccak256RoundFunctionFSM<F: SmallField> { - pub read_precompile_call: Boolean<F>, - pub read_unaligned_words_for_round: Boolean<F>, - pub completed: Boolean<F>, - pub keccak_internal_state: [[[UInt8<F>; BYTES_PER_WORD]; LANE_WIDTH]; LANE_WIDTH], - pub timestamp_to_use_for_read: UInt32<F>, - pub timestamp_to_use_for_write: UInt32<F>, - pub precompile_call_params: Keccak256PrecompileCallParams<F>, - pub u8_words_buffer: [UInt8<F>; BYTES_BUFFER_SIZE], - pub u64_words_buffer_markers: [Boolean<F>; BUFFER_SIZE_IN_U64_WORDS], -} -``` - -## Main circuit logic - -Keccak is a precompile for the keccak hash function, and is responsible for hashing any input data sent in by contract -executions. Roughly speaking, the keccak circuit will receive metadata about queued up precompile calls, and ensure that -the first-in-line call is indeed a call to the keccak precompile. The circuit then collects some metadata about the call -itself, which tells the circuit at which memory position the input can be found, and at which memory position the output -should be written, along with some peripheral data like the timestamp of the hash. - -Next, the circuit will take data from another queue, which contains memory queries. This will give the circuit witnesses -to push into the keccak buffer. - -Learn more about Keccak here: <https://keccak.team/keccak.html>. - -### [First part](https://github.com/matter-labs/era-zkevm_circuits/blob/main/src/keccak256_round_function/mod.rs#L423) - -The circuit begins with allocating input part of the PI. - -```rust -let Keccak256RoundFunctionCircuitInstanceWitness { - closed_form_input, - requests_queue_witness, - memory_reads_witness, -} = witness; - -let mut structured_input = Keccak256RoundFunctionCircuitInputOutput::alloc_ignoring_outputs( - cs, - closed_form_input.clone(), -); -``` - -We chose what `memory_queue` state and `log_queue` state to continue to work with. - -```rust -let requests_queue_state = QueueState::conditionally_select( - cs, - start_flag, - &requests_queue_state_from_input, - &requests_queue_state_from_fsm, -); - -let memory_queue_state = QueueState::conditionally_select( - cs, - start_flag, - &memory_queue_state_from_input, - &memory_queue_state_from_fsm, -); -``` - -We do the same with inner FSM part. - -```rust -let initial_state = Keccak256RoundFunctionFSM::conditionally_select( - cs, - start_flag, - &starting_fsm_state, - &structured_input.hidden_fsm_input.internal_fsm, -); -``` - -### [Main part](https://github.com/matter-labs/era-zkevm_circuits/blob/main/src/keccak256_round_function/mod.rs#L114) - -Our main cycle starts with getting a new precompile request from the queue. - -```rust -let (precompile_call, _) = precompile_calls_queue.pop_front(cs, state.read_precompile_call); -``` - -We check that fields are correct. - -```rust -Num::conditionally_enforce_equal( - cs, - state.read_precompile_call, - &Num::from_variable(precompile_call.aux_byte.get_variable()), - &Num::from_variable(aux_byte_for_precompile.get_variable()), -); -for (a, b) in precompile_call - .address - .inner - .iter() - .zip(precompile_address.inner.iter()) -{ - Num::conditionally_enforce_equal( - cs, - state.read_precompile_call, - &Num::from_variable(a.get_variable()), - &Num::from_variable(b.get_variable()), - ); -} -``` - -Also, we prepare some additional information for the call. - -```rust -state.precompile_call_params = Keccak256PrecompileCallParams::conditionally_select( - cs, - state.read_precompile_call, - &call_params, - &state.precompile_call_params, -); -... -``` - -Then we do some memory queries to read data that needed to be hashed. - -```rust -let read_query = MemoryQuery { - timestamp: state.timestamp_to_use_for_read, - memory_page: state.precompile_call_params.input_page, - index: state.precompile_call_params.input_offset, - rw_flag: boolean_false, - is_ptr: boolean_false, - value: read_query_value, -}; - -memory_queue.push(cs, read_query, should_read); -``` - -After some another preparations, we are ready to create a full input. - -```rust -let mut input = [zero_u8; keccak256::KECCAK_RATE_BYTES]; - input.copy_from_slice(&state.u8_words_buffer[..keccak256::KECCAK_RATE_BYTES]); -``` - -And run the round function. - -```rust -let squeezed = - keccak256_absorb_and_run_permutation(cs, &mut state.keccak_internal_state, &input); -``` - -Now, if it was the last round, we can make a write memory query of the result. - -```rust -let write_query = MemoryQuery { - timestamp: state.timestamp_to_use_for_write, - memory_page: state.precompile_call_params.output_page, - index: state.precompile_call_params.output_offset, - rw_flag: boolean_true, - is_ptr: boolean_false, - value: result, -}; - -memory_queue.push(cs, write_query, write_result); -``` - -### [Final part](https://github.com/matter-labs/era-zkevm_circuits/blob/main/src/keccak256_round_function/mod.rs#L495) - -Now we update PI output parts and compute a commitment. Then we allocate it as public variables. - -```rust -let compact_form = - ClosedFormInputCompactForm::from_full_form(cs, &structured_input, round_function); -let input_commitment = commit_variable_length_encodable_item(cs, &compact_form, round_function); -for el in input_commitment.iter() { - let gate = PublicInputGate::new(el.get_variable()); - gate.add_to_cs(cs); -} -``` diff --git a/content/40.zk-stack/components/prover/circuits/l1-messages-hasher.md b/content/40.zk-stack/components/prover/circuits/l1-messages-hasher.md deleted file mode 100644 index cb25b179..00000000 --- a/content/40.zk-stack/components/prover/circuits/l1-messages-hasher.md +++ /dev/null @@ -1,156 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Circuits - L1MessagesHasher | zkSync Docs ---- - -# L1MessagesHasher - -## L1MessagesHasher PI - -### [Input](https://github.com/matter-labs/era-zkevm_circuits/blob/main/src/linear_hasher/input.rs#L27) - -```rust -pub struct LinearHasherInputData<F: SmallField> { - pub queue_state: QueueState<F, QUEUE_STATE_WIDTH>, -} -``` - -### [Output](https://github.com/matter-labs/era-zkevm_circuits/blob/main/src/linear_hasher/input.rs#L42) - -```rust -pub struct LinearHasherOutputData<F: SmallField> { - pub keccak256_hash: [UInt8<F>; 32], -} -``` - -### FSM Input and FSM Output - -```rust -() // this circuit has big capacity, so we don't need several instances -``` - -## Main circuit logic - -It takes a queue of L1 messages and hash everything with keccak. - -The main logic is implemented in `linear_hasher_entry_point` function -[here](https://github.com/matter-labs/era-zkevm_circuits/blob/main/src/linear_hasher/mod.rs#L35). - -It can be spited into 3 parts: - -### [First part](https://github.com/matter-labs/era-zkevm_circuits/blob/main/src/linear_hasher/mod.rs#L54) - -Firstly, we allocate the “input” part of PI (`start flag`, `Input` and `FSM Input`): - -```rust -let mut structured_input = - LinearHasherInputOutput::alloc_ignoring_outputs(cs, closed_form_input.clone()); - -let start_flag = structured_input.start_flag; -let queue_state_from_input = structured_input.observable_input.queue_state; - -let mut queue = StorageLogQueue::<F, R>::from_state(cs, queue_state_from_input); -let queue_witness = CircuitQueueWitness::from_inner_witness(queue_witness); -queue.witness = Arc::new(queue_witness); -``` - -Also, we do some checks for them and allocate empty hash state: - -```rust -let keccak_accumulator_state = - [[[zero_u8; keccak256::BYTES_PER_WORD]; keccak256::LANE_WIDTH]; keccak256::LANE_WIDTH]; - -let mut keccak_accumulator_state = - keccak_accumulator_state.map(|el| el.map(|el| el.map(|el| el.get_variable()))); -``` - -### [Main part](https://github.com/matter-labs/era-zkevm_circuits/blob/main/src/linear_hasher/mod.rs#L105) - -This part is the main one. We run a loop with some limit, where on each iteration we try to pop the next element from -the queue, if it’s not empty. - -```rust -let queue_is_empty = queue.is_empty(cs); -let should_pop = queue_is_empty.negated(cs); - -let (storage_log, _) = queue.pop_front(cs, should_pop); -``` - -Then we absorb it to the buffer, and if it’s full we run a round function. - -```rust -if buffer.len() >= 136 { - let buffer_for_round: [UInt8<F>; KECCAK_RATE_BYTES] = buffer[..136].try_into().unwrap(); - let buffer_for_round = buffer_for_round.map(|el| el.get_variable()); - let carry_on = buffer[136..].to_vec(); - - buffer = carry_on; - - // absorb if we are not done yet - keccak256_conditionally_absorb_and_run_permutation( - cs, - continue_to_absorb, - &mut keccak_accumulator_state, - &buffer_for_round, - ); -} -``` - -If this element was the last one, we create a padding and run a round function. - -```rust -if tail_len == KECCAK_RATE_BYTES - 1 { - // unreachable, but we set it for completeness - last_round_buffer[tail_len] = UInt8::allocated_constant(cs, 0x81); -} else { - last_round_buffer[tail_len] = UInt8::allocated_constant(cs, 0x01); - last_round_buffer[KECCAK_RATE_BYTES - 1] = UInt8::allocated_constant(cs, 0x80); -} - -let last_round_buffer = last_round_buffer.map(|el| el.get_variable()); - -// absorb if it's the last round -keccak256_conditionally_absorb_and_run_permutation( - cs, - absorb_as_last_round, - &mut keccak_accumulator_state, - &last_round_buffer, -); -``` - -### [Final part](https://github.com/matter-labs/era-zkevm_circuits/blob/main/src/linear_hasher/mod.rs#L169) - -Firstly, we verify that the queue is empty now. - -```rust -let completed = queue.is_empty(cs); -Boolean::enforce_equal(cs, &completed, &boolean_true); -``` - -Then we compute the final hash and create an output. - -```rust -// squeeze -let mut keccak256_hash = [MaybeUninit::<UInt8<F>>::uninit(); keccak256::KECCAK256_DIGEST_SIZE]; -for (i, dst) in keccak256_hash.array_chunks_mut::<8>().enumerate() { - for (dst, src) in dst.iter_mut().zip(keccak_accumulator_state[i][0].iter()) { - let tmp = unsafe { UInt8::from_variable_unchecked(*src) }; - dst.write(tmp); - } -} - -let mut observable_output = LinearHasherOutputData::placeholder(cs); -observable_output.keccak256_hash = keccak256_hash; -``` - -Finally, we compute a commitment to PI and allocate it as witness variables. - -```rust -let input_commitment = commit_variable_length_encodable_item(cs, &compact_form, round_function); -for el in input_commitment.iter() { - let gate = PublicInputGate::new(el.get_variable()); - gate.add_to_cs(cs); -} -``` diff --git a/content/40.zk-stack/components/prover/circuits/log-sorter.md b/content/40.zk-stack/components/prover/circuits/log-sorter.md deleted file mode 100644 index 6f940d18..00000000 --- a/content/40.zk-stack/components/prover/circuits/log-sorter.md +++ /dev/null @@ -1,358 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Circuits - LogSorter | zkSync Docs ---- - -# LogSorter - -`LogSorter` is one circuit that is used as both `EventsSorter` and `L1MessagesSorter`. - -## LogSorter PI - -### [Input](https://github.com/matter-labs/era-zkevm_circuits/blob/main/src/log_sorter/input.rs#L57) - -```rust -pub struct EventsDeduplicatorInputData<F: SmallField> { - pub initial_log_queue_state: QueueState<F, QUEUE_STATE_WIDTH>, - pub intermediate_sorted_queue_state: QueueState<F, QUEUE_STATE_WIDTH>, -} -``` - -### [Output](https://github.com/matter-labs/era-zkevm_circuits/blob/main/src/log_sorter/input.rs#L74) - -```rust -pub struct EventsDeduplicatorOutputData<F: SmallField> { - pub final_queue_state: QueueState<F, QUEUE_STATE_WIDTH>, -} -``` - -### [FSM Input and FSM Output](https://github.com/matter-labs/era-zkevm_circuits/blob/main/src/log_sorter/input.rs#L28) - -```rust -pub struct EventsDeduplicatorFSMInputOutput<F: SmallField> { - pub lhs_accumulator: [Num<F>; DEFAULT_NUM_PERMUTATION_ARGUMENT_REPETITIONS], - pub rhs_accumulator: [Num<F>; DEFAULT_NUM_PERMUTATION_ARGUMENT_REPETITIONS], - pub initial_unsorted_queue_state: QueueState<F, QUEUE_STATE_WIDTH>, - pub intermediate_sorted_queue_state: QueueState<F, QUEUE_STATE_WIDTH>, - pub final_result_queue_state: QueueState<F, QUEUE_STATE_WIDTH>, - pub previous_key: UInt32<F>, - pub previous_item: LogQuery<F>, -} -``` - -## Main circuit logic - -The main logic of this circuit is sorting and deduplicating logs from `initial_log_queue_state`. The result is pushed to -`final_queue_state`. - -With sorting, we get 2 queues – a simple one, and a sorted one. - -We start with the witness allocation: - -```rust -let mut structured_input = - EventsDeduplicatorInputOutput::alloc_ignoring_outputs(cs, closed_form_input.clone()); -``` - -Now the scheme is familiar. - -Check if we didn't take elements from the queue: - -```rust -unsorted_queue_from_passthrough_state.enforce_trivial_head(cs); -``` - -Judging by the flag, we choose a queue: - -```rust -let state = QueueState::conditionally_select( - cs, - structured_input.start_flag, - &unsorted_queue_from_passthrough_state, - &unsorted_queue_from_fsm_input_state, - ); -``` - -Wrap the state and witnesses for it in `StorageLogQueue`, thereby preparing the input data for `inner`: - -```rust -let mut unsorted_queue = StorageLogQueue::<F, R>::from_state(cs, state); - - use std::sync::Arc; - let initial_queue_witness = CircuitQueueWitness::from_inner_witness(initial_queue_witness); - unsorted_queue.witness = Arc::new(initial_queue_witness); - - let intermediate_sorted_queue_from_passthrough_state = structured_input - .observable_input - .intermediate_sorted_queue_state; -``` - -For `sorted_queue`, it is the same procedure. - -We generate challenges and accumulators for the permutation argument. A detailed explanation can be found -[here](https://github.com/code-423n4/2023-10-zksync/blob/c3ff020df5d11fe91209bd99d7fb0ec1272dc387/docs/Circuits%20Section/Circuits/Sorting.md). - -```rust -let challenges = crate::utils::produce_fs_challenges::< - F, - CS, - R, - QUEUE_STATE_WIDTH, - { MEMORY_QUERY_PACKED_WIDTH + 1 }, - DEFAULT_NUM_PERMUTATION_ARGUMENT_REPETITIONS, - >( - cs, - structured_input - .observable_input - .initial_log_queue_state - .tail, - structured_input - .observable_input - .intermediate_sorted_queue_state - .tail, - round_function, - ); -``` - -Again, if it is not the rest cycle (`start_flag == false`), we should choose fsm: - -```rust -let one = Num::allocated_constant(cs, F::ONE); -let initial_lhs = Num::parallel_select( - cs, - structured_input.start_flag, - &[one; DEFAULT_NUM_PERMUTATION_ARGUMENT_REPETITIONS], - &structured_input.hidden_fsm_input.lhs_accumulator, -); - -let initial_rhs = Num::parallel_select( - cs, - structured_input.start_flag, - &[one; DEFAULT_NUM_PERMUTATION_ARGUMENT_REPETITIONS], - &structured_input.hidden_fsm_input.rhs_accumulator, -); -``` - -Depending on the flag, we prepare all the information for `inner` part: - -```rust -let zero_u32 = UInt32::zero(cs); -let previous_key = UInt32::conditionally_select( - cs, - structured_input.start_flag, - &zero_u32, - &structured_input.hidden_fsm_input.previous_key, -); -``` - -```rust -let empty_storage = LogQuery::placeholder(cs); -let previous_item = LogQuery::conditionally_select( - cs, - structured_input.start_flag, - &empty_storage, - &structured_input.hidden_fsm_input.previous_item, -); -``` - -After `inner` part we check `unsorted_queue` and `intermediate_sorted_queue`.: - -```rust -let unsorted_is_empty = unsorted_queue.is_empty(cs); -let sorted_is_empty = intermediate_sorted_queue.is_empty(cs); - -Boolean::enforce_equal(cs, &unsorted_is_empty, &sorted_is_empty); -``` - -We check that permutation accumulators are equal and if the queues are already empty: - -```rust -let completed = unsorted_queue.length.is_zero(cs); - for (lhs, rhs) in new_lhs.iter().zip(new_rhs.iter()) { - Num::conditionally_enforce_equal(cs, completed, lhs, rhs); - } -``` - -Finally, we compute a commitment to PublicInput and allocate it as witness variables. - -```rust -let input_commitment = commit_variable_length_encodable_item(cs, &compact_form, round_function); -for el in input_commitment.iter() { - let gate = PublicInputGate::new(el.get_variable()); - gate.add_to_cs(cs); -} -``` - -### Inner part - -Note: we have specific logic for rollback. When we have an event of some function and then that function makes a return -then we should cancel this event. Inside the VM, we create exactly the same event: same key, block number, timestamp, -etc. the only change is that the rollback flag is now true. In the inner part, first sort and look for these pairs and -self-destruct them. - -There are two cases: when `unsorted_queue` is empty, but it's the only circuit, in this case. Otherwise, we continue, -and then it's not trivial. - -```rust -let no_work = unsorted_queue.is_empty(cs); -let mut previous_is_trivial = Boolean::multi_or(cs, &[no_work, is_start]); -``` - -Additional checks for length. We should always check whether the sorted queue and the normal queue are of the same -length. - -```rust -let unsorted_queue_length = Num::from_variable(unsorted_queue.length.get_variable()); -let intermediate_sorted_queue_length = - Num::from_variable(intermediate_sorted_queue.length.get_variable()); - -Num::enforce_equal( - cs, - &unsorted_queue_length, - &intermediate_sorted_queue_length, -); -``` - -We can pop elements if unsorted_queue is empty. That’s why every time we set up the flags `original_is_empty`, -`sorted_is_empty`. We also ensure that items are "write" unless it's a padding. - -```rust -let original_is_empty = unsorted_queue.is_empty(cs); -let sorted_is_empty = intermediate_sorted_queue.is_empty(cs); -Boolean::enforce_equal(cs, &original_is_empty, &sorted_is_empty); - -let should_pop = original_is_empty.negated(cs); -let is_trivial = original_is_empty; - -let (_, original_encoding) = unsorted_queue.pop_front(cs, should_pop); -let (sorted_item, sorted_encoding) = intermediate_sorted_queue.pop_front(cs, should_pop); -``` - -The next block of code is sorting. You can find the main idea -[here](https://github.com/code-423n4/2023-10-zksync/blob/c3ff020df5d11fe91209bd99d7fb0ec1272dc387/docs/Circuits%20Section/Circuits/Sorting.md). - -Check if keys are equal and check a value. We compare timestamps and then resolve logic over rollbacks, so the only way -when keys are equal can be when we do a rollback. Ensure sorting for uniqueness timestamp and rollback flag. We know -that timestamps are unique across logs, and are also the same between write and rollback. Keys are always ordered no -matter what, and are never equal unless it's padding: - -```rust -let sorting_key = sorted_item.timestamp; -let (keys_are_equal, new_key_is_smaller) = - unpacked_long_comparison(cs, &[previous_key], &[sorting_key]); -new_key_is_smaller.conditionally_enforce_false(cs, should_pop); -``` - -There are only two cases when keys are equal: - -- it's a padding element -- it's a rollback - -It's enough to compare timestamps, as the VM circuit guarantees uniqueness if it's not a padding. Now ensure sorting: - -```rust -let previous_is_not_rollback = previous_item.rollback.negated(cs); -let enforce_sequential_rollback = Boolean::multi_and( - cs, - &[previous_is_not_rollback, sorted_item.rollback, should_pop], -); -keys_are_equal.conditionally_enforce_true(cs, enforce_sequential_rollback); - -let same_log = UInt32::equals(cs, &sorted_item.timestamp, &previous_item.timestamp); - -let values_are_equal = - UInt256::equals(cs, &sorted_item.written_value, &previous_item.written_value); - -let negate_previous_is_trivial = previous_is_trivial.negated(cs); -let should_enforce = Boolean::multi_and(cs, &[same_log, negate_previous_is_trivial]); - -values_are_equal.conditionally_enforce_true(cs, should_enforce); - -let this_item_is_non_trivial_rollback = - Boolean::multi_and(cs, &[sorted_item.rollback, should_pop]); -let negate_previous_item_rollback = previous_item.rollback.negated(cs); -let previous_item_is_non_trivial_write = Boolean::multi_and( - cs, - &[negate_previous_item_rollback, negate_previous_is_trivial], -); -let is_sequential_rollback = Boolean::multi_and( - cs, - &[ - this_item_is_non_trivial_rollback, - previous_item_is_non_trivial_write, - ], -); -same_log.conditionally_enforce_true(cs, is_sequential_rollback); -``` - -Decide if we should add the previous into the queue. We add only if the previous one is not trivial, it had a different -key, and it wasn't rolled back: - -```rust -let negate_same_log = same_log.and(cs, should_pop).negated(cs); -let add_to_the_queue = Boolean::multi_and( - cs, - &[ - negate_previous_is_trivial, - negate_same_log, - negate_previous_item_rollback, - ], -); -``` - -Further, we don't need in our `LogQueue` some fields, so we just clean up: - -```rust -let boolean_false = Boolean::allocated_constant(cs, false); -let query_to_add = LogQuery { - address: previous_item.address, - key: previous_item.key, - read_value: UInt256::zero(cs), - written_value: previous_item.written_value, - rw_flag: boolean_false, - aux_byte: UInt8::zero(cs), - rollback: boolean_false, - is_service: previous_item.is_service, - shard_id: previous_item.shard_id, - tx_number_in_block: previous_item.tx_number_in_block, - timestamp: UInt32::zero(cs), -}; -``` - -Finalization step - same way, check if the last item is not a rollback: - -```rust -let now_empty = unsorted_queue.is_empty(cs); - -let negate_previous_is_trivial = previous_is_trivial.negated(cs); -let negate_previous_item_rollback = previous_item.rollback.negated(cs); -let add_to_the_queue = Boolean::multi_and( - cs, - &[ - negate_previous_is_trivial, - negate_previous_item_rollback, - now_empty, - ], -); -let boolean_false = Boolean::allocated_constant(cs, false); -let query_to_add = LogQuery { - address: previous_item.address, - key: previous_item.key, - read_value: UInt256::zero(cs), - written_value: previous_item.written_value, - rw_flag: boolean_false, - aux_byte: UInt8::zero(cs), - rollback: boolean_false, - is_service: previous_item.is_service, - shard_id: previous_item.shard_id, - tx_number_in_block: previous_item.tx_number_in_block, - timestamp: UInt32::zero(cs), -}; - -result_queue.push(cs, query_to_add, add_to_the_queue); - -unsorted_queue.enforce_consistency(cs); -intermediate_sorted_queue.enforce_consistency(cs); -``` diff --git a/content/40.zk-stack/components/prover/circuits/main-vm.md b/content/40.zk-stack/components/prover/circuits/main-vm.md deleted file mode 100644 index b4586ef5..00000000 --- a/content/40.zk-stack/components/prover/circuits/main-vm.md +++ /dev/null @@ -1,349 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Circuits - Main VM | zkSync Docs ---- - -# Main Vm - -## MainVm PI - -### [Input](https://github.com/matter-labs/era-zkevm_circuits/blob/main/src/fsm_input_output/circuit_inputs/main_vm.rs#L9) - -```rust -pub struct VmInputData<F: SmallField> { - pub rollback_queue_tail_for_block: [Num<F>; QUEUE_STATE_WIDTH], - pub memory_queue_initial_state: QueueTailState<F, FULL_SPONGE_QUEUE_STATE_WIDTH>, - pub decommitment_queue_initial_state: QueueTailState<F, FULL_SPONGE_QUEUE_STATE_WIDTH>, - pub per_block_context: GlobalContext<F>, -} -``` - -### [Output](https://github.com/matter-labs/era-zkevm_circuits/blob/main/src/fsm_input_output/circuit_inputs/main_vm.rs#L33) - -```rust -pub struct VmOutputData<F: SmallField> { - pub log_queue_final_state: QueueState<F, QUEUE_STATE_WIDTH>, - pub memory_queue_final_state: QueueState<F, FULL_SPONGE_QUEUE_STATE_WIDTH>, - pub decommitment_queue_final_state: QueueState<F, FULL_SPONGE_QUEUE_STATE_WIDTH>, -} -``` - -### [FSM Input and FSM Output](https://github.com/matter-labs/era-zkevm_circuits/blob/main/src/base_structures/vm_state/mod.rs#L92) - -```rust -pub struct VmLocalState<F: SmallField> { - pub previous_code_word: UInt256<F>, - pub registers: [VMRegister<F>; REGISTERS_COUNT], - pub flags: ArithmeticFlagsPort<F>, - pub timestamp: UInt32<F>, - pub memory_page_counter: UInt32<F>, - pub tx_number_in_block: UInt32<F>, - pub previous_code_page: UInt32<F>, - pub previous_super_pc: UInt16<F>, - pub pending_exception: Boolean<F>, - pub ergs_per_pubdata_byte: UInt32<F>, - pub callstack: Callstack<F>, - pub memory_queue_state: [Num<F>; FULL_SPONGE_QUEUE_STATE_WIDTH], - pub memory_queue_length: UInt32<F>, - pub code_decommittment_queue_state: [Num<F>; FULL_SPONGE_QUEUE_STATE_WIDTH], - pub code_decommittment_queue_length: UInt32<F>, - pub context_composite_u128: [UInt32<F>; 4], -} -``` - -## Main circuit logic - -Main_vm – is instruction handler. VM circuit only accumulated memory queries using WITNESS provided by (presumably -honest) prover. In this sense VM is “local” - it doesn’t have access to full memory space, but only to values of -particular queries that it encountered during the execution. RAM circuit sorts all accumulated queries from VM and -ENFORCES the general RAM validity as described above. Those two actions together guarantee RAM validity, so for all the -descriptions below when we will talk about particular opcodes in VM we will use a language like “Operand number 0 is -read from the stack at the offset X” that means that even though such “memory read” technically means using a witness -provided by the prover, in practice we can assume that such witness is correct and we can view it as just normal RAM -access as one would expect to happen on the standard machine. - -We start with the allocation witnesses: - -```rust -let VmCircuitWitness { - closed_form_input, - witness_oracle, - } = witness; - - let mut structured_input = - VmCircuitInputOutput::alloc_ignoring_outputs(cs, closed_form_input.clone()); - - let start_flag = structured_input.start_flag; - let observable_input = structured_input.observable_input.clone(); - let hidden_fsm_input = structured_input.hidden_fsm_input.clone(); - - let VmInputData { - rollback_queue_tail_for_block, - memory_queue_initial_state, - decommitment_queue_initial_state, - per_block_context, - } = observable_input; -``` - -We also need to create the state that reflects the "initial" state for boot process: - -```rust -let bootloader_state = initial_bootloader_state( - cs, - memory_queue_initial_state.length, - memory_queue_initial_state.tail, - decommitment_queue_initial_state.length, - decommitment_queue_initial_state.tail, - rollback_queue_tail_for_block, - round_function, - ); -``` - -but depending from `start_flag` we should select between states: - -```rust -let mut state = - VmLocalState::conditionally_select(cs, start_flag, &bootloader_state, &hidden_fsm_input); - -let synchronized_oracle = SynchronizedWitnessOracle::new(witness_oracle); -``` - -Here we run the `vm_cycle` : - -```rust -for _cycle_idx in 0..limit { - state = vm_cycle( - cs, - state, - &synchronized_oracle, - &per_block_context, - round_function, - ); - } -``` - -The VM runs in cycles. For each cycle, - -1. Start in a prestate - perform all common operations for every opcode, namely deal with exceptions, resources, edge - cases like end of execution, select opcodes, compute common values. Within the zkEVM framework, numerous entities - identified as "opcodes" in the EVM paradigm are elegantly manifested as mere function calls. This modification is - rooted in the succinct observation that, from the perspective of an external caller, an inlined function (analogous - to an opcode) is inherently indistinguishable from an internal function call. - -```rust -let (draft_next_state, common_opcode_state, opcode_carry_parts) = - create_prestate(cs, current_state, witness_oracle, round_function); -``` - -1. Compute state diffs for every opcode. List of opcodes: - -```rust -pub enum Opcode { - Invalid(InvalidOpcode), - Nop(NopOpcode), - Add(AddOpcode), - Sub(SubOpcode), - Mul(MulOpcode), - Div(DivOpcode), - Jump(JumpOpcode), - Context(ContextOpcode), - Shift(ShiftOpcode), - Binop(BinopOpcode), - Ptr(PtrOpcode), - NearCall(NearCallOpcode), - Log(LogOpcode), - FarCall(FarCallOpcode), - Ret(RetOpcode), - UMA(UMAOpcode), -} -``` - -VM cycle calls such functions for different class of opcodes: nop, add_sup, jump, bind, context, ptr, log, -calls_and_ret, mul_div. - -Here we briefly mention all opcodes defined in the system. Each logical "opcode" comes with modifiers, categorized into -"exclusive" modifiers (where only one can be applied) and "flags" or "non-exclusive" modifiers (where multiple can be -activated simultaneously). The number of permissible "flags" can vary depending on the specific "exclusive" modifier -chosen. All data from opcodes we write to StateDiffsAccumulator: - -```rust -pub struct StateDiffsAccumulator<F: SmallField> { - // dst0 candidates - pub dst_0_values: Vec<(bool, Boolean<F>, VMRegister<F>)>, - // dst1 candidates - pub dst_1_values: Vec<(Boolean<F>, VMRegister<F>)>, - // flags candidates - pub flags: Vec<(Boolean<F>, ArithmeticFlagsPort<F>)>, - // specific register updates - pub specific_registers_updates: [Vec<(Boolean<F>, VMRegister<F>)>; REGISTERS_COUNT], - // zero out specific registers - pub specific_registers_zeroing: [Vec<Boolean<F>>; REGISTERS_COUNT], - // remove ptr markers on specific registers - pub remove_ptr_on_specific_registers: [Vec<Boolean<F>>; REGISTERS_COUNT], - // pending exceptions, to be resolved next cycle. Should be masked by opcode applicability already - pub pending_exceptions: Vec<Boolean<F>>, - // ergs left, PC - // new ergs left if it's not one available after decoding - pub new_ergs_left_candidates: Vec<(Boolean<F>, UInt32<F>)>, - // new PC in case if it's not just PC+1 - pub new_pc_candidates: Vec<(Boolean<F>, UInt16<F>)>, - // other meta parameters of VM - pub new_tx_number: Option<(Boolean<F>, UInt32<F>)>, - pub new_ergs_per_pubdata: Option<(Boolean<F>, UInt32<F>)>, - // memory bounds - pub new_heap_bounds: Vec<(Boolean<F>, UInt32<F>)>, - pub new_aux_heap_bounds: Vec<(Boolean<F>, UInt32<F>)>, - // u128 special register, one from context, another from call/ret - pub context_u128_candidates: Vec<(Boolean<F>, [UInt32<F>; 4])>, - // internal machinery - pub callstacks: Vec<(Boolean<F>, Callstack<F>)>, - // memory page counter - pub memory_page_counters: Option<UInt32<F>>, - // decommittment queue - pub decommitment_queue_candidates: Option<( - Boolean<F>, - UInt32<F>, - [Num<F>; FULL_SPONGE_QUEUE_STATE_WIDTH], - )>, - // memory queue - pub memory_queue_candidates: Vec<( - Boolean<F>, - UInt32<F>, - [Num<F>; FULL_SPONGE_QUEUE_STATE_WIDTH], - )>, - // forward piece of log queue - pub log_queue_forward_candidates: Vec<(Boolean<F>, UInt32<F>, [Num<F>; QUEUE_STATE_WIDTH])>, - // rollback piece of log queue - pub log_queue_rollback_candidates: Vec<(Boolean<F>, UInt32<F>, [Num<F>; QUEUE_STATE_WIDTH])>, - // sponges to run. Should not include common sponges for src/dst operands - pub sponge_candidates_to_run: Vec<( - bool, - bool, - Boolean<F>, - ArrayVec< - ( - Boolean<F>, - [Num<F>; FULL_SPONGE_QUEUE_STATE_WIDTH], - [Num<F>; FULL_SPONGE_QUEUE_STATE_WIDTH], - ), - MAX_SPONGES_PER_CYCLE, - >, - )>, - // add/sub relations to enforce - pub add_sub_relations: Vec<( - Boolean<F>, - ArrayVec<AddSubRelation<F>, MAX_ADD_SUB_RELATIONS_PER_CYCLE>, - )>, - // mul/div relations to enforce - pub mul_div_relations: Vec<( - Boolean<F>, - ArrayVec<MulDivRelation<F>, MAX_MUL_DIV_RELATIONS_PER_CYCLE>, - )>, -} -``` - -There will be no implementation details here because the code is commented step by step and is understandable. Short -description: - -Apply opcodes, for DST0 it's possible to have opcode-constrainted updates only into registers, apply -`StateDiffsAccumulator`, update the memory, update the registers, apply changes to VM state, such as ergs left, etc. -push data to queues for other circuits. If an event has rollback then create the same event data but with `rollback` -flag, enforce sponges. There are only 2 outcomes: - -- we have dst0 write (and may be src0 read), that we taken care above -- opcode itself modified memory queue, based on outcome of src0 read in parallel opcodes either -- do not use sponges and only rely on src0/dst0 -- can not have src0/dst0 in memory, but use sponges (UMA, near_call, far call, ret) - -No longer in the cyclical part `VM` we Setup different queues: - -1. Memory: - -```rust -let memory_queue_current_tail = QueueTailState { - tail: final_state.memory_queue_state, - length: final_state.memory_queue_length, - }; -let memory_queue_final_tail = QueueTailState::conditionally_select( - cs, - structured_input.completion_flag, - &memory_queue_current_tail, - &full_empty_state_large.tail, -); -``` - -1. Code decommit: - -```rust -let decommitment_queue_current_tail = QueueTailState { - tail: final_state.code_decommittment_queue_state, - length: final_state.code_decommittment_queue_length, - }; -let decommitment_queue_final_tail = QueueTailState::conditionally_select( - cs, - structured_input.completion_flag, - &decommitment_queue_current_tail, - &full_empty_state_large.tail, -); -``` - -1. Log: - -```rust -let final_log_state_tail = final_state.callstack.current_context.log_queue_forward_tail; - let final_log_state_length = final_state - .callstack - .current_context - .log_queue_forward_part_length; - -// but we CAN still check that it's potentially mergeable, basically to check that witness generation is good -for (a, b) in final_log_state_tail.iter().zip( - final_state - .callstack - .current_context - .saved_context - .reverted_queue_head - .iter(), -) { - Num::conditionally_enforce_equal(cs, structured_input.completion_flag, a, b); -} -let full_empty_state_small = QueueState::<F, QUEUE_STATE_WIDTH>::empty(cs); - -let log_queue_current_tail = QueueTailState { - tail: final_log_state_tail, - length: final_log_state_length, -}; -let log_queue_final_tail = QueueTailState::conditionally_select( - cs, - structured_input.completion_flag, - &log_queue_current_tail, - &full_empty_state_small.tail, -); -``` - -Wrap them: - -```rust -observable_output.log_queue_final_state.tail = log_queue_final_tail; -observable_output.memory_queue_final_state.tail = memory_queue_final_tail; -observable_output.decommitment_queue_final_state.tail = decommitment_queue_final_tail; - -structured_input.observable_output = observable_output; -structured_input.hidden_fsm_output = final_state; -``` - -Finally, we compute a commitment to PublicInput and allocate it as witness variables. - -```rust -let compact_form = - ClosedFormInputCompactForm::from_full_form(cs, &structured_input, round_function); - -let input_commitment: [_; INPUT_OUTPUT_COMMITMENT_LENGTH] = - commit_variable_length_encodable_item(cs, &compact_form, round_function); -for el in input_commitment.iter() { - let gate = PublicInputGate::new(el.get_variable()); - gate.add_to_cs(cs); -} -``` diff --git a/content/40.zk-stack/components/prover/circuits/overview.md b/content/40.zk-stack/components/prover/circuits/overview.md deleted file mode 100644 index 03529bfe..00000000 --- a/content/40.zk-stack/components/prover/circuits/overview.md +++ /dev/null @@ -1,128 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Circuits | zkSync Docs ---- - -# Circuits - -The main circuit is called `MainVM`. It is the one where all the main logic happens. - -It consists of multiple cycles, where on each iteration we take a next opcode and try to execute it the following way: - -```rust -if opcode == Add { - // do addition -} -if opcode == SRead { - // do storage read -} -... -``` - -You may notice that `Add` instruction is much simpler than the `SRead` one. When you work with circuits you still need -to execute every opcode. - -That’s why we can use the following approach: - -```rust -if opcode == Add { - // do addition -} -if opcode == SRead { - storage_queue.push((address, value)); - // proof storage read in other circuit -} -... -``` - -So instead of proving `SRead` we just push a proving request, that will be sent to another circuit, that will prove it. -That’s how we can make our prover structure more optimized and flexible. - -For now, we have 13 base layer circuits: - -- [MainVM](https://github.com/code-423n4/2023-10-zksync/blob/main/docs/Circuits%20Section/Circuits/Main%20Vm.md) -- [CodeDecommittmentsSorter](https://github.com/code-423n4/2023-10-zksync/blob/main/docs/Circuits%20Section/Circuits/SortDecommitments.md) -- [CodeDecommitter](https://github.com/code-423n4/2023-10-zksync/blob/main/docs/Circuits%20Section/Circuits/CodeDecommitter.md) -- [LogDemuxer](https://github.com/code-423n4/2023-10-zksync/blob/main/docs/Circuits%20Section/Circuits/DemuxLogQueue.md) -- [KeccakRoundFunction](https://github.com/code-423n4/2023-10-zksync/blob/main/docs/Circuits%20Section/Circuits/KeccakRoundFunction.md) -- [Sha256RoundFunction](https://github.com/code-423n4/2023-10-zksync/blob/main/docs/Circuits%20Section/Circuits/Sha256RoundFunction.md) -- [ECRecover](https://github.com/code-423n4/2023-10-zksync/blob/main/docs/Circuits%20Section/Circuits/Ecrecover.md) -- [RAMPermutation](https://github.com/code-423n4/2023-10-zksync/blob/main/docs/Circuits%20Section/Circuits/RAMPermutation.md) -- [StorageSorter](https://github.com/code-423n4/2023-10-zksync/blob/main/docs/Circuits%20Section/Circuits/StorageSorter.md) -- [StorageApplication](https://github.com/code-423n4/2023-10-zksync/blob/main/docs/Circuits%20Section/Circuits/StorageApplication.md) -- [EventsSorter](https://github.com/code-423n4/2023-10-zksync/blob/main/docs/Circuits%20Section/Circuits/LogSorter.md) -- [L1MessagesSorter](https://github.com/code-423n4/2023-10-zksync/blob/main/docs/Circuits%20Section/Circuits/LogSorter.md) -- [L1MessagesHasher](https://github.com/code-423n4/2023-10-zksync/blob/main/docs/Circuits%20Section/Circuits/L1MessagesHasher.md) - -- - -They mostly communicate by queues (the diagram of communication is below). - -## Public Input Structure - -Public Input (PI) is some piece of data, that is revealed to the verifier. Usually, it consists of some inputs and -outputs. - -The main challenge for base layer circuits is the ability to prove unlimited amount of execution. For example, our -`MainVm` circuit can handle execution of $x$ opcodes. Then, if some transaction causes execution of more than $x$ -opcodes, we won’t be able to prove it. That’s why every circuit could be extended to multiple instances. So you can -always use $n$ `MainVm` instances to handle up to $nx$ opcode executions. - -All circuits have the following PI structure: - -![Diagram of Public Inputs for Circuits](../../../../assets/images/circuit-pi-diagram.png) - -| start flag | Boolean that shows if this is the first instance of corresponding circuit type | -| ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| finished flag | Boolean that shows if this is the last instance of corresponding circuit type | -| Input | Structure that contains all inputs to this type of circuit (every instance of one circuit type has the same input) | -| FSM Input and FSM Output | The field has the same structure. It represents the inner state of circuit execution (the first fsm_input is empty, the second fsm_input equals the first fsm_output and so on…) | -| Output | Structure that contains all outputs of this type of circuit (the last instance contains the real output, the output field of the others is empty) | - -The code implementation can be found -[here](https://github.com/matter-labs/era-zkevm_circuits/blob/main/src/fsm_input_output/mod.rs#L32). - -In terms of Arithmetization we don’t allocate all these fields like public input variables. A more efficient approach -would be computing commitment of type `[Num<F>; 4]` with poseidon2 and then allocating these 4 variables as public -inputs. - -![Diagram showing computing commitments for efficient arithmetization](../../../../assets/images/circuit-commitments.png) - -The equality of corresponding parts in different circuits is done during aggregating base layer circuits. Aggregating is -done by recursion level circuits that also verify base layer proofs. For now this is out of our scope, so we will focus -only on base layer. - -## Overall View of Base Layer Circuits - -![Diagram showing how all base layer circuits fit together](../../../../assets/images/base-layer-circuit-diagram.png) - -## Base Layer Circuits - -[Main Vm](https://github.com/code-423n4/2023-10-zksync/blob/main/docs/Circuits%20Section/Circuits/Main%20Vm.md) - -[SortDecommitments](https://github.com/code-423n4/2023-10-zksync/blob/main/docs/Circuits%20Section/Circuits/SortDecommitments.md) - -[CodeDecommitter](https://github.com/code-423n4/2023-10-zksync/blob/main/docs/Circuits%20Section/Circuits/CodeDecommitter.md) - -[DemuxLogQueue](https://github.com/code-423n4/2023-10-zksync/blob/main/docs/Circuits%20Section/Circuits/DemuxLogQueue.md) - -[KeccakRoundFunction](https://github.com/code-423n4/2023-10-zksync/blob/main/docs/Circuits%20Section/Circuits/KeccakRoundFunction.md) - -[Sha256RoundFunction](https://github.com/code-423n4/2023-10-zksync/blob/main/docs/Circuits%20Section/Circuits/Sha256RoundFunction.md) - -[Ecrecover](https://github.com/code-423n4/2023-10-zksync/blob/main/docs/Circuits%20Section/Circuits/Ecrecover.md) - -[RAMPermutation](https://github.com/code-423n4/2023-10-zksync/blob/main/docs/Circuits%20Section/Circuits/RAMPermutation.md) - -[StorageSorter](https://github.com/code-423n4/2023-10-zksync/blob/main/docs/Circuits%20Section/Circuits/StorageSorter.md) - -[StorageApplication](https://github.com/code-423n4/2023-10-zksync/blob/main/docs/Circuits%20Section/Circuits/StorageApplication.md) - -[LogSorter](https://github.com/code-423n4/2023-10-zksync/blob/main/docs/Circuits%20Section/Circuits/LogSorter.md) - -[L1MessagesHasher](https://github.com/code-423n4/2023-10-zksync/blob/main/docs/Circuits%20Section/Circuits/L1MessagesHasher.md) - -There are a couple of circuits that do queue sorting. Here is the page that describes the algorithm: -[Sorting](https://github.com/code-423n4/2023-10-zksync/blob/main/docs/Circuits%20Section/Circuits/Sorting.md) diff --git a/content/40.zk-stack/components/prover/circuits/ram-permutation.md b/content/40.zk-stack/components/prover/circuits/ram-permutation.md deleted file mode 100644 index 15b50015..00000000 --- a/content/40.zk-stack/components/prover/circuits/ram-permutation.md +++ /dev/null @@ -1,202 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Circuits - RAMPermutation | zkSync Docs ---- - -# RAMPermutation - -## RAMPermutation PI - -### [Input](https://github.com/matter-labs/era-zkevm_circuits/blob/main/src/ram_permutation/input.rs#L27) - -```rust -pub struct RamPermutationInputData<F: SmallField> { - pub unsorted_queue_initial_state: QueueState<F, FULL_SPONGE_QUEUE_STATE_WIDTH>, - pub sorted_queue_initial_state: QueueState<F, FULL_SPONGE_QUEUE_STATE_WIDTH>, - pub non_deterministic_bootloader_memory_snapshot_length: UInt32<F>, -} -``` - -### Output - -```rust -() -``` - -### [FSM Input and FSM Output](https://github.com/matter-labs/era-zkevm_circuits/blob/main/src/ram_permutation/input.rs#L52) - -```rust -pub struct RamPermutationFSMInputOutput<F: SmallField> { - pub lhs_accumulator: [Num<F>; DEFAULT_NUM_PERMUTATION_ARGUMENT_REPETITIONS], - pub rhs_accumulator: [Num<F>; DEFAULT_NUM_PERMUTATION_ARGUMENT_REPETITIONS], - pub current_unsorted_queue_state: QueueState<F, FULL_SPONGE_QUEUE_STATE_WIDTH>, - pub current_sorted_queue_state: QueueState<F, FULL_SPONGE_QUEUE_STATE_WIDTH>, - pub previous_sorting_key: [UInt32<F>; RAM_SORTING_KEY_LENGTH], - pub previous_full_key: [UInt32<F>; RAM_FULL_KEY_LENGTH], - pub previous_value: UInt256<F>, - pub previous_is_ptr: Boolean<F>, - pub num_nondeterministic_writes: UInt32<F>, -} -``` - -## Main circuit logic - -The circuit starts [here](https://github.com/matter-labs/era-zkevm_circuits/blob/main/src/ram_permutation/mod.rs#L30). -This function allocate PI inputs that call the inner function, where all the main logic is implemented. In the end, it -forms the fsm output and compute PI commitment. The main purpose of this circuit is enforcing that memory queries are -executed correctly. - -### [First part](https://github.com/matter-labs/era-zkevm_circuits/blob/main/src/ram_permutation/mod.rs#L43) - -We start, as usually, with allocating input fields from PI. - -```rust -let RamPermutationCircuitInstanceWitness { - closed_form_input, - unsorted_queue_witness, - sorted_queue_witness, -} = closed_form_input_witness; - -let mut structured_input = - RamPermutationCycleInputOutput::alloc_ignoring_outputs(cs, closed_form_input.clone()); - -let start_flag = structured_input.start_flag; -let observable_input = structured_input.observable_input.clone(); -let hidden_fsm_input = structured_input.hidden_fsm_input.clone(); -``` - -Some field, like `unsorted_queue_initial_state` and `current_unsorted_queue_state` represents the same value. So we -should decide whether we take a new queue from `Input` or continue working with current one from `FSM Input`. We use -`start_flag` for such purpose. - -```rust -let unsorted_queue_state = QueueState::conditionally_select( - cs, - start_flag, - &observable_input.unsorted_queue_initial_state, - &hidden_fsm_input.current_unsorted_queue_state, -); - -let sorted_queue_state = QueueState::conditionally_select( - cs, - start_flag, - &observable_input.sorted_queue_initial_state, - &hidden_fsm_input.current_sorted_queue_state, -); -``` - -Also, we generate challenges and accumulators for permutation argument. The detailed explanation can be found -[here](https://github.com/code-423n4/2023-10-zksync/blob/c3ff020df5d11fe91209bd99d7fb0ec1272dc387/docs/Circuits%20Section/Circuits/Sorting.md). - -```rust -let fs_challenges = crate::utils::produce_fs_challenges( - cs, - observable_input.unsorted_queue_initial_state.tail, - observable_input.sorted_queue_initial_state.tail, - round_function, -); - -let mut lhs = <[Num<F>; DEFAULT_NUM_PERMUTATION_ARGUMENT_REPETITIONS]>::conditionally_select( - cs, - start_flag, - &[num_one; DEFAULT_NUM_PERMUTATION_ARGUMENT_REPETITIONS], - &hidden_fsm_input.lhs_accumulator, -); -let mut rhs = <[Num<F>; DEFAULT_NUM_PERMUTATION_ARGUMENT_REPETITIONS]>::conditionally_select( - cs, - start_flag, - &[num_one; DEFAULT_NUM_PERMUTATION_ARGUMENT_REPETITIONS], - &hidden_fsm_input.rhs_accumulator, -); -``` - -### [Main part](https://github.com/matter-labs/era-zkevm_circuits/blob/main/src/ram_permutation/mod.rs#L211) - -We call the inner function, where the main logic is implemented. - -Firstly, we check non-deterministic writes. These should be in the beginning of `sorted_queue`. We also count the number -of such writes. - -```rust -let is_nondeterministic_write = Boolean::multi_and( - cs, - &[ - can_pop, - ts_is_zero, - page_is_bootloader_heap, - is_write, - not_ptr, - ], -); - -*num_nondeterministic_writes = UInt32::conditionally_select( - cs, - is_nondeterministic_write, - &num_nondeterministic_writes_incremented, - &num_nondeterministic_writes, -); -``` - -For every new memory query from `sorted_queue` we enforce sorting by (`memory_page`, `index` and `timestamp`). - -```rust -let sorting_key = [ - sorted_item.timestamp, - sorted_item.index, - sorted_item.memory_page, - ]; - -let (_keys_are_equal, previous_key_is_smaller) = - unpacked_long_comparison(cs, &sorting_key, previous_sorting_key); -``` - -Then, if the query is read one, we have two cases: - -- should enforce that the value is the same as in the previous value, if it has the same `memory_page` and `index` -- should enforce that the value is zero otherwise - -```rust -let value_equal = UInt256::equals(cs, &sorted_item.value, &previous_element_value); -let value_is_zero = UInt256::equals(cs, &sorted_item.value, &uint256_zero); -``` - -In the end, we compute permutation argument contributions to accumulators. The code is -[here](https://github.com/matter-labs/era-zkevm_circuits/blob/main/src/ram_permutation/mod.rs#L363). The detailed -explanation can be found -[here](https://github.com/code-423n4/2023-10-zksync/blob/c3ff020df5d11fe91209bd99d7fb0ec1272dc387/docs/Circuits%20Section/Circuits/Sorting.md). - -### [Final part](https://github.com/matter-labs/era-zkevm_circuits/blob/main/src/ram_permutation/mod.rs#L159) - -If the queues are empty now, that means that this instance should be the last one. - -```rust -let completed = unsorted_queue.length.is_zero(cs); -``` - -If so, we should check that permutation argument accumulators are equal and number of nondeterministic writes is -correct. - -```rust -for (lhs, rhs) in lhs.iter().zip(rhs.iter()) { - Num::conditionally_enforce_equal(cs, completed, lhs, rhs); -} - -let num_nondeterministic_writes_equal = UInt32::equals( - cs, - &num_nondeterministic_writes, - &observable_input.non_deterministic_bootloader_memory_snapshot_length, -); -num_nondeterministic_writes_equal.conditionally_enforce_true(cs, completed); -``` - -Finally, we form the output part of PI and compute a commitment to PI and allocate it as witness variables. - -```rust -let input_commitment = commit_variable_length_encodable_item(cs, &compact_form, round_function); -for el in input_commitment.iter() { - let gate = PublicInputGate::new(el.get_variable()); - gate.add_to_cs(cs); -} -``` diff --git a/content/40.zk-stack/components/prover/circuits/sha256-round-function.md b/content/40.zk-stack/components/prover/circuits/sha256-round-function.md deleted file mode 100644 index 348eb862..00000000 --- a/content/40.zk-stack/components/prover/circuits/sha256-round-function.md +++ /dev/null @@ -1,376 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Circuits - Sha256RoundFunction | zkSync Docs ---- - -# Sha256RoundFunction - -## Sha256RoundFunction PI - -### [Input](https://github.com/matter-labs/era-zkevm_circuits/blob/main/src/fsm_input_output/circuit_inputs/main_vm.rs#L9) - -```rust -pub struct PrecompileFunctionInputData<F: SmallField> { - pub initial_log_queue_state: QueueState<F, QUEUE_STATE_WIDTH>, - pub initial_memory_queue_state: QueueState<F, FULL_SPONGE_QUEUE_STATE_WIDTH>, -} -``` - -### [Output](https://github.com/matter-labs/era-zkevm_circuits/blob/main/src/base_structures/precompile_input_outputs/mod.rs#L42) - -```rust -pub struct PrecompileFunctionOutputData<F: SmallField> { - pub final_memory_state: QueueState<F, FULL_SPONGE_QUEUE_STATE_WIDTH>, -} -``` - -### [FSM Input and FSM Output](https://github.com/matter-labs/era-zkevm_circuits/blob/main/src/keccak256_round_function/input.rs#L59) - -```rust -pub struct Sha256RoundFunctionFSMInputOutput<F: SmallField> { - pub internal_fsm: Sha256RoundFunctionFSM<F>, - pub log_queue_state: QueueState<F, QUEUE_STATE_WIDTH>, - pub memory_queue_state: QueueState<F, FULL_SPONGE_QUEUE_STATE_WIDTH>, -} - -pub struct Sha256RoundFunctionFSM<F: SmallField> { - pub read_precompile_call: Boolean<F>, - pub read_words_for_round: Boolean<F>, - pub completed: Boolean<F>, - pub sha256_inner_state: [UInt32<F>; 8], - pub timestamp_to_use_for_read: UInt32<F>, - pub timestamp_to_use_for_write: UInt32<F>, - pub precompile_call_params: Sha256PrecompileCallParams<F>, -} -``` - -## Main circuit logic - -This is a precompile for the SHA256 hash function’s round function. - -We start from witness allocation: - -```rust -let Sha256RoundFunctionCircuitInstanceWitness { - closed_form_input, - requests_queue_witness, - memory_reads_witness, - } = witness; - -let mut structured_input = Sha256RoundFunctionCircuitInputOutput::alloc_ignoring_outputs( - cs, - closed_form_input.clone(), -); - -let start_flag = structured_input.start_flag; - -let requests_queue_state_from_input = structured_input.observable_input.initial_log_queue_state; -``` - -Check if `requests_queue_state_from_input` is trivial ( we didn't pop elements yet) and choose between input and `fsm` -queue state: - -```rust -requests_queue_state_from_input.enforce_trivial_head(cs); - -let requests_queue_state_from_fsm = structured_input.hidden_fsm_input.log_queue_state; - -let requests_queue_state = QueueState::conditionally_select( - cs, - start_flag, - &requests_queue_state_from_input, - &requests_queue_state_from_fsm, -); -``` - -the same procedure we do for `memory_queue`: - -```rust -let memory_queue_state_from_input = - structured_input.observable_input.initial_memory_queue_state; - -// it must be trivial -memory_queue_state_from_input.enforce_trivial_head(cs); - -let memory_queue_state_from_fsm = structured_input.hidden_fsm_input.memory_queue_state; - -let memory_queue_state = QueueState::conditionally_select( - cs, - start_flag, - &memory_queue_state_from_input, - &memory_queue_state_from_fsm, -); -``` - -Call `inner` part where is main logic: - -```rust -let final_state = sha256_precompile_inner::<F, CS, R>( - cs, - &mut memory_queue, - &mut requests_queue, - read_queries_allocator, - initial_state, - round_function, - limit, - ); -``` - -Form the final state (depending on flag we choose between states): - -```rust - - let done = final_state.completed; - structured_input.completion_flag = done; - structured_input.observable_output = PrecompileFunctionOutputData::placeholder(cs); - - structured_input.observable_output.final_memory_state = QueueState::conditionally_select( - cs, - structured_input.completion_flag, - &final_memory_state, - &structured_input.observable_output.final_memory_state, - ); - - structured_input.hidden_fsm_output.internal_fsm = final_state; - structured_input.hidden_fsm_output.log_queue_state = final_request_state; - structured_input.hidden_fsm_output.memory_queue_state = final_memory_state; -``` - -Finally, we compute a commitment to PublicInput and allocate it as witness variables. - -```rust -let compact_form = - ClosedFormInputCompactForm::from_full_form(cs, &structured_input, round_function); - let input_commitment = commit_variable_length_encodable_item(cs, &compact_form, round_function); - for el in input_commitment.iter() { - let gate = PublicInputGate::new(el.get_variable()); - gate.add_to_cs(cs); - } -``` - -### Inner part - -Start for set up different flags: `precompile_address`, `aux_byte_for_precompile`, and plugs: - -```rust -let precompile_address = UInt160::allocated_constant( - cs, - *zkevm_opcode_defs::system_params::SHA256_ROUND_FUNCTION_PRECOMPILE_FORMAL_ADDRESS, - ); -let aux_byte_for_precompile = UInt8::allocated_constant(cs, PRECOMPILE_AUX_BYTE); - -let boolean_false = Boolean::allocated_constant(cs, false); -let boolean_true = Boolean::allocated_constant(cs, true); -let zero_u32 = UInt32::zero(cs); -let zero_u256 = UInt256::zero(cs); -``` - -We can have a degenerate case when the queue is empty, but it's the first circuit in the queue, so we take default `FSM` -state that has `state.read_precompile_call = true`, we can only skip the full circuit if we are not in any form of -progress: - -```rust -let input_queue_is_empty = precompile_calls_queue.is_empty(cs); -let can_finish_immediately = - Boolean::multi_and(cs, &[state.read_precompile_call, input_queue_is_empty]); -``` - -Main work cycle: - -Check income data with constants(precompile addresses aux byte for precompile and must match): - -```rust -Num::conditionally_enforce_equal( - cs, - state.read_precompile_call, - &Num::from_variable(precompile_call.aux_byte.get_variable()), - &Num::from_variable(aux_byte_for_precompile.get_variable()), - ); -for (a, b) in precompile_call - .address - .inner - .iter() - .zip(precompile_address.inner.iter()) -{ - Num::conditionally_enforce_equal( - cs, - state.read_precompile_call, - &Num::from_variable(a.get_variable()), - &Num::from_variable(b.get_variable()), - ); -} -``` - -Create parameters that describe the call itself: - -```rust -let params_encoding = precompile_call.key; -let call_params = Sha256PrecompileCallParams::from_encoding(cs, params_encoding); - -state.precompile_call_params = Sha256PrecompileCallParams::conditionally_select( - cs, - state.read_precompile_call, - &call_params, - &state.precompile_call_params, -); -``` - -- `input_page` – memory page for `read_queue` -- `input_offset` – page index`read_queue` -- `output_page` – memory page for `write_queue` -- `output_offset` – page index`write_queue` -- `num_rounds` – number of rounds for hash function - -```rust -pub struct Sha256PrecompileCallParams<F: SmallField> { - pub input_page: UInt32<F>, - pub input_offset: UInt32<F>, - pub output_page: UInt32<F>, - pub output_offset: UInt32<F>, - pub num_rounds: UInt32<F>, -} -``` - -Setup `timestamp:` - -```rust -state.timestamp_to_use_for_read = UInt32::conditionally_select( - cs, - state.read_precompile_call, - &precompile_call.timestamp, - &state.timestamp_to_use_for_read, - ); - -// timestamps have large space, so this can be expected -let timestamp_to_use_for_write = - unsafe { state.timestamp_to_use_for_read.increment_unchecked(cs) }; -state.timestamp_to_use_for_write = UInt32::conditionally_select( - cs, - state.read_precompile_call, - ×tamp_to_use_for_write, - &state.timestamp_to_use_for_write, -); -``` - -Reset buffer if needed: - -```rust -let reset_buffer = Boolean::multi_or(cs, &[state.read_precompile_call, state.completed]); -state.read_words_for_round = Boolean::multi_or( - cs, - &[state.read_precompile_call, state.read_words_for_round], -); -state.read_precompile_call = boolean_false; -``` - -Now perform a few memory queries to read content: - -```rust -let zero_rounds_left = state.precompile_call_params.num_rounds.is_zero(cs); - -let mut memory_queries_as_u32_words = [zero_u32; 8 * MEMORY_READ_QUERIES_PER_CYCLE]; -let should_read = zero_rounds_left.negated(cs); -let mut bias_variable = should_read.get_variable(); -for dst in memory_queries_as_u32_words.array_chunks_mut::<8>() { - let read_query_value = - memory_read_witness.conditionally_allocate_biased(cs, should_read, bias_variable); - bias_variable = read_query_value.inner[0].get_variable(); - - let read_query = MemoryQuery { - timestamp: state.timestamp_to_use_for_read, - memory_page: state.precompile_call_params.input_page, - index: state.precompile_call_params.input_offset, - rw_flag: boolean_false, - is_ptr: boolean_false, - value: read_query_value, - }; - - let may_be_new_offset = unsafe { - state - .precompile_call_params - .input_offset - .increment_unchecked(cs) - }; - state.precompile_call_params.input_offset = UInt32::conditionally_select( - cs, - state.read_words_for_round, - &may_be_new_offset, - &state.precompile_call_params.input_offset, - ); - - // perform read - memory_queue.push(cs, read_query, should_read); -``` - -We need to change endianness. Memory is BE, and each of the 4-byte chunks should be interpreted as BE u32 for sha256: - -```rust -let be_bytes = read_query_value.to_be_bytes(cs); -for (dst, src) in dst.iter_mut().zip(be_bytes.array_chunks::<4>()) { - let as_u32 = UInt32::from_be_bytes(cs, *src); - *dst = as_u32; -} -``` - -get the initial state for `SHA256`: - -```rust -let sha256_empty_internal_state = sha256::ivs_as_uint32(cs); -let mut current_sha256_state = <[UInt32<F>; 8]>::conditionally_select( - cs, - reset_buffer, - &sha256_empty_internal_state, - &state.sha256_inner_state, - ); -``` - -finally, compute sha256 and write into memory if we completed all hash rounds. BTW `SHA256` algorithm you can read -[here](https://eips.ethereum.org/assets/eip-2680/sha256-384-512.pdf): - -```rust -let sha256_output = sha256::round_function::round_function_over_uint32( - cs, - &mut current_sha256_state, - &memory_queries_as_u32_words, -); -state.sha256_inner_state = current_sha256_state; - -let no_rounds_left = state.precompile_call_params.num_rounds.is_zero(cs); -let write_result = Boolean::multi_and(cs, &[state.read_words_for_round, no_rounds_left]); - -let mut write_word = zero_u256; -// some endianness magic -for (dst, src) in write_word - .inner - .iter_mut() - .rev() - .zip(sha256_output.array_chunks::<4>()) -{ - *dst = UInt32::from_le_bytes(cs, *src); -} - -let write_query = MemoryQuery { - timestamp: state.timestamp_to_use_for_write, - memory_page: state.precompile_call_params.output_page, - index: state.precompile_call_params.output_offset, - rw_flag: boolean_true, - is_ptr: boolean_false, - value: write_word, -}; -``` - -Update state: - -```rust -let input_is_empty = precompile_calls_queue.is_empty(cs); -let input_is_not_empty = input_is_empty.negated(cs); -let nothing_left = Boolean::multi_and(cs, &[write_result, input_is_empty]); -let process_next = Boolean::multi_and(cs, &[write_result, input_is_not_empty]); - -state.read_precompile_call = process_next; -state.completed = Boolean::multi_or(cs, &[nothing_left, state.completed]); -let t = Boolean::multi_or(cs, &[state.read_precompile_call, state.completed]); -state.read_words_for_round = t.negated(cs); -``` diff --git a/content/40.zk-stack/components/prover/circuits/sorting/log-sorter.md b/content/40.zk-stack/components/prover/circuits/sorting/log-sorter.md deleted file mode 100644 index 6f940d18..00000000 --- a/content/40.zk-stack/components/prover/circuits/sorting/log-sorter.md +++ /dev/null @@ -1,358 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Circuits - LogSorter | zkSync Docs ---- - -# LogSorter - -`LogSorter` is one circuit that is used as both `EventsSorter` and `L1MessagesSorter`. - -## LogSorter PI - -### [Input](https://github.com/matter-labs/era-zkevm_circuits/blob/main/src/log_sorter/input.rs#L57) - -```rust -pub struct EventsDeduplicatorInputData<F: SmallField> { - pub initial_log_queue_state: QueueState<F, QUEUE_STATE_WIDTH>, - pub intermediate_sorted_queue_state: QueueState<F, QUEUE_STATE_WIDTH>, -} -``` - -### [Output](https://github.com/matter-labs/era-zkevm_circuits/blob/main/src/log_sorter/input.rs#L74) - -```rust -pub struct EventsDeduplicatorOutputData<F: SmallField> { - pub final_queue_state: QueueState<F, QUEUE_STATE_WIDTH>, -} -``` - -### [FSM Input and FSM Output](https://github.com/matter-labs/era-zkevm_circuits/blob/main/src/log_sorter/input.rs#L28) - -```rust -pub struct EventsDeduplicatorFSMInputOutput<F: SmallField> { - pub lhs_accumulator: [Num<F>; DEFAULT_NUM_PERMUTATION_ARGUMENT_REPETITIONS], - pub rhs_accumulator: [Num<F>; DEFAULT_NUM_PERMUTATION_ARGUMENT_REPETITIONS], - pub initial_unsorted_queue_state: QueueState<F, QUEUE_STATE_WIDTH>, - pub intermediate_sorted_queue_state: QueueState<F, QUEUE_STATE_WIDTH>, - pub final_result_queue_state: QueueState<F, QUEUE_STATE_WIDTH>, - pub previous_key: UInt32<F>, - pub previous_item: LogQuery<F>, -} -``` - -## Main circuit logic - -The main logic of this circuit is sorting and deduplicating logs from `initial_log_queue_state`. The result is pushed to -`final_queue_state`. - -With sorting, we get 2 queues – a simple one, and a sorted one. - -We start with the witness allocation: - -```rust -let mut structured_input = - EventsDeduplicatorInputOutput::alloc_ignoring_outputs(cs, closed_form_input.clone()); -``` - -Now the scheme is familiar. - -Check if we didn't take elements from the queue: - -```rust -unsorted_queue_from_passthrough_state.enforce_trivial_head(cs); -``` - -Judging by the flag, we choose a queue: - -```rust -let state = QueueState::conditionally_select( - cs, - structured_input.start_flag, - &unsorted_queue_from_passthrough_state, - &unsorted_queue_from_fsm_input_state, - ); -``` - -Wrap the state and witnesses for it in `StorageLogQueue`, thereby preparing the input data for `inner`: - -```rust -let mut unsorted_queue = StorageLogQueue::<F, R>::from_state(cs, state); - - use std::sync::Arc; - let initial_queue_witness = CircuitQueueWitness::from_inner_witness(initial_queue_witness); - unsorted_queue.witness = Arc::new(initial_queue_witness); - - let intermediate_sorted_queue_from_passthrough_state = structured_input - .observable_input - .intermediate_sorted_queue_state; -``` - -For `sorted_queue`, it is the same procedure. - -We generate challenges and accumulators for the permutation argument. A detailed explanation can be found -[here](https://github.com/code-423n4/2023-10-zksync/blob/c3ff020df5d11fe91209bd99d7fb0ec1272dc387/docs/Circuits%20Section/Circuits/Sorting.md). - -```rust -let challenges = crate::utils::produce_fs_challenges::< - F, - CS, - R, - QUEUE_STATE_WIDTH, - { MEMORY_QUERY_PACKED_WIDTH + 1 }, - DEFAULT_NUM_PERMUTATION_ARGUMENT_REPETITIONS, - >( - cs, - structured_input - .observable_input - .initial_log_queue_state - .tail, - structured_input - .observable_input - .intermediate_sorted_queue_state - .tail, - round_function, - ); -``` - -Again, if it is not the rest cycle (`start_flag == false`), we should choose fsm: - -```rust -let one = Num::allocated_constant(cs, F::ONE); -let initial_lhs = Num::parallel_select( - cs, - structured_input.start_flag, - &[one; DEFAULT_NUM_PERMUTATION_ARGUMENT_REPETITIONS], - &structured_input.hidden_fsm_input.lhs_accumulator, -); - -let initial_rhs = Num::parallel_select( - cs, - structured_input.start_flag, - &[one; DEFAULT_NUM_PERMUTATION_ARGUMENT_REPETITIONS], - &structured_input.hidden_fsm_input.rhs_accumulator, -); -``` - -Depending on the flag, we prepare all the information for `inner` part: - -```rust -let zero_u32 = UInt32::zero(cs); -let previous_key = UInt32::conditionally_select( - cs, - structured_input.start_flag, - &zero_u32, - &structured_input.hidden_fsm_input.previous_key, -); -``` - -```rust -let empty_storage = LogQuery::placeholder(cs); -let previous_item = LogQuery::conditionally_select( - cs, - structured_input.start_flag, - &empty_storage, - &structured_input.hidden_fsm_input.previous_item, -); -``` - -After `inner` part we check `unsorted_queue` and `intermediate_sorted_queue`.: - -```rust -let unsorted_is_empty = unsorted_queue.is_empty(cs); -let sorted_is_empty = intermediate_sorted_queue.is_empty(cs); - -Boolean::enforce_equal(cs, &unsorted_is_empty, &sorted_is_empty); -``` - -We check that permutation accumulators are equal and if the queues are already empty: - -```rust -let completed = unsorted_queue.length.is_zero(cs); - for (lhs, rhs) in new_lhs.iter().zip(new_rhs.iter()) { - Num::conditionally_enforce_equal(cs, completed, lhs, rhs); - } -``` - -Finally, we compute a commitment to PublicInput and allocate it as witness variables. - -```rust -let input_commitment = commit_variable_length_encodable_item(cs, &compact_form, round_function); -for el in input_commitment.iter() { - let gate = PublicInputGate::new(el.get_variable()); - gate.add_to_cs(cs); -} -``` - -### Inner part - -Note: we have specific logic for rollback. When we have an event of some function and then that function makes a return -then we should cancel this event. Inside the VM, we create exactly the same event: same key, block number, timestamp, -etc. the only change is that the rollback flag is now true. In the inner part, first sort and look for these pairs and -self-destruct them. - -There are two cases: when `unsorted_queue` is empty, but it's the only circuit, in this case. Otherwise, we continue, -and then it's not trivial. - -```rust -let no_work = unsorted_queue.is_empty(cs); -let mut previous_is_trivial = Boolean::multi_or(cs, &[no_work, is_start]); -``` - -Additional checks for length. We should always check whether the sorted queue and the normal queue are of the same -length. - -```rust -let unsorted_queue_length = Num::from_variable(unsorted_queue.length.get_variable()); -let intermediate_sorted_queue_length = - Num::from_variable(intermediate_sorted_queue.length.get_variable()); - -Num::enforce_equal( - cs, - &unsorted_queue_length, - &intermediate_sorted_queue_length, -); -``` - -We can pop elements if unsorted_queue is empty. That’s why every time we set up the flags `original_is_empty`, -`sorted_is_empty`. We also ensure that items are "write" unless it's a padding. - -```rust -let original_is_empty = unsorted_queue.is_empty(cs); -let sorted_is_empty = intermediate_sorted_queue.is_empty(cs); -Boolean::enforce_equal(cs, &original_is_empty, &sorted_is_empty); - -let should_pop = original_is_empty.negated(cs); -let is_trivial = original_is_empty; - -let (_, original_encoding) = unsorted_queue.pop_front(cs, should_pop); -let (sorted_item, sorted_encoding) = intermediate_sorted_queue.pop_front(cs, should_pop); -``` - -The next block of code is sorting. You can find the main idea -[here](https://github.com/code-423n4/2023-10-zksync/blob/c3ff020df5d11fe91209bd99d7fb0ec1272dc387/docs/Circuits%20Section/Circuits/Sorting.md). - -Check if keys are equal and check a value. We compare timestamps and then resolve logic over rollbacks, so the only way -when keys are equal can be when we do a rollback. Ensure sorting for uniqueness timestamp and rollback flag. We know -that timestamps are unique across logs, and are also the same between write and rollback. Keys are always ordered no -matter what, and are never equal unless it's padding: - -```rust -let sorting_key = sorted_item.timestamp; -let (keys_are_equal, new_key_is_smaller) = - unpacked_long_comparison(cs, &[previous_key], &[sorting_key]); -new_key_is_smaller.conditionally_enforce_false(cs, should_pop); -``` - -There are only two cases when keys are equal: - -- it's a padding element -- it's a rollback - -It's enough to compare timestamps, as the VM circuit guarantees uniqueness if it's not a padding. Now ensure sorting: - -```rust -let previous_is_not_rollback = previous_item.rollback.negated(cs); -let enforce_sequential_rollback = Boolean::multi_and( - cs, - &[previous_is_not_rollback, sorted_item.rollback, should_pop], -); -keys_are_equal.conditionally_enforce_true(cs, enforce_sequential_rollback); - -let same_log = UInt32::equals(cs, &sorted_item.timestamp, &previous_item.timestamp); - -let values_are_equal = - UInt256::equals(cs, &sorted_item.written_value, &previous_item.written_value); - -let negate_previous_is_trivial = previous_is_trivial.negated(cs); -let should_enforce = Boolean::multi_and(cs, &[same_log, negate_previous_is_trivial]); - -values_are_equal.conditionally_enforce_true(cs, should_enforce); - -let this_item_is_non_trivial_rollback = - Boolean::multi_and(cs, &[sorted_item.rollback, should_pop]); -let negate_previous_item_rollback = previous_item.rollback.negated(cs); -let previous_item_is_non_trivial_write = Boolean::multi_and( - cs, - &[negate_previous_item_rollback, negate_previous_is_trivial], -); -let is_sequential_rollback = Boolean::multi_and( - cs, - &[ - this_item_is_non_trivial_rollback, - previous_item_is_non_trivial_write, - ], -); -same_log.conditionally_enforce_true(cs, is_sequential_rollback); -``` - -Decide if we should add the previous into the queue. We add only if the previous one is not trivial, it had a different -key, and it wasn't rolled back: - -```rust -let negate_same_log = same_log.and(cs, should_pop).negated(cs); -let add_to_the_queue = Boolean::multi_and( - cs, - &[ - negate_previous_is_trivial, - negate_same_log, - negate_previous_item_rollback, - ], -); -``` - -Further, we don't need in our `LogQueue` some fields, so we just clean up: - -```rust -let boolean_false = Boolean::allocated_constant(cs, false); -let query_to_add = LogQuery { - address: previous_item.address, - key: previous_item.key, - read_value: UInt256::zero(cs), - written_value: previous_item.written_value, - rw_flag: boolean_false, - aux_byte: UInt8::zero(cs), - rollback: boolean_false, - is_service: previous_item.is_service, - shard_id: previous_item.shard_id, - tx_number_in_block: previous_item.tx_number_in_block, - timestamp: UInt32::zero(cs), -}; -``` - -Finalization step - same way, check if the last item is not a rollback: - -```rust -let now_empty = unsorted_queue.is_empty(cs); - -let negate_previous_is_trivial = previous_is_trivial.negated(cs); -let negate_previous_item_rollback = previous_item.rollback.negated(cs); -let add_to_the_queue = Boolean::multi_and( - cs, - &[ - negate_previous_is_trivial, - negate_previous_item_rollback, - now_empty, - ], -); -let boolean_false = Boolean::allocated_constant(cs, false); -let query_to_add = LogQuery { - address: previous_item.address, - key: previous_item.key, - read_value: UInt256::zero(cs), - written_value: previous_item.written_value, - rw_flag: boolean_false, - aux_byte: UInt8::zero(cs), - rollback: boolean_false, - is_service: previous_item.is_service, - shard_id: previous_item.shard_id, - tx_number_in_block: previous_item.tx_number_in_block, - timestamp: UInt32::zero(cs), -}; - -result_queue.push(cs, query_to_add, add_to_the_queue); - -unsorted_queue.enforce_consistency(cs); -intermediate_sorted_queue.enforce_consistency(cs); -``` diff --git a/content/40.zk-stack/components/prover/circuits/sorting/overview.md b/content/40.zk-stack/components/prover/circuits/sorting/overview.md deleted file mode 100644 index 774a3635..00000000 --- a/content/40.zk-stack/components/prover/circuits/sorting/overview.md +++ /dev/null @@ -1,64 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Circuits - Sorting and Deduplicating | zkSync Docs ---- - -# Sorting - -We have four circuits, that receive some queue of elements and do sorting and deduplicating: -[SortDecommitments](./sort-decommitments.md), [StorageSorter](./storage-sorter.md), EventsSorter and L1MessageSorter -(Both EventsSorter and L1MessageSorter use [LogSorter](./log-sorter.md)). - -The main scenario is the following: we have an `input_queue` of elements, that - -1. could be compared between each other, - -2. could be represented (encoded) as `[Num<F>; N]`. - -Then we create `sorted_queue`, that contains all the elements in sorted order. - -And we create an empty `result_queue` to store the results. - -In the end, we can compute `challenges` that is `[Num<F>, N+1]` from states of `input_queue` and `sorted_queue`. - -Then the algorithm is the following: - -```rust -let mut lhs = 1; -let mut rhs = 1; - -assert!(input_queue.len() == sorted_queue.len()); -let previous_element = input_queue.pop(); -let previous_sorted_element = sorted_queue.pop(); -loop { - previous_encoding: [Num<F>; N] = previous_element.to_encoding(); - previous_sorted_encoding: [Num<F>; N] = previous_sorted_element.to_encoding(); - - lhs *= previous_encoding[0] * challenges[0] - + previous_encoding[1] * challenges[1] - + ... - + challenges[N]; - - rhs *= previous_sorted_encoding[0] * challenges[0] - + previous_sorted_encoding[1] * challenges[1] - + ... - + challenges[N]; - - if input_queue.is_empty() || sorted_queue.is_empty() { - break; - } - - let next_element = input_queue.pop(); - let next_sorted_element = sorted_queue.pop(); - - assert!(next_sorted_element >= previous_sorted_element); - - previous_element = next_element; - previous_sorted_element = next_sorted_element; -} -assert!(lhs == rhs); -``` - -You can read more about permutation argument [here](https://triton-vm.org/spec/permutation-argument.html). diff --git a/content/40.zk-stack/components/prover/circuits/sorting/sort-decommitments.md b/content/40.zk-stack/components/prover/circuits/sorting/sort-decommitments.md deleted file mode 100644 index 026a6dbe..00000000 --- a/content/40.zk-stack/components/prover/circuits/sorting/sort-decommitments.md +++ /dev/null @@ -1,239 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Circuits - SortDecommitments | zkSync Docs ---- - -# SortDecommitments - -## SortDecommitments PI - -### [Input](https://github.com/matter-labs/era-zkevm_circuits/blob/main/src/sort_Decommitment_requests/input.rs#L62) - -```rust -pub struct CodeDecommitmentsDeduplicatorInputData<F: SmallField> { - pub initial_queue_state: QueueState<F, FULL_SPONGE_QUEUE_STATE_WIDTH>, - pub sorted_queue_initial_state: QueueState<F, FULL_SPONGE_QUEUE_STATE_WIDTH>, -} -``` - -### [Output](https://github.com/matter-labs/era-zkevm_circuits/blob/main/src/sort_Decommitment_requests/input.rs#L81) - -```rust -pub struct CodeDecommittmentsDeduplicatorOutputData<F: SmallField> { - pub final_queue_state: QueueState<F, FULL_SPONGE_QUEUE_STATE_WIDTH>, -} -``` - -### [FSM Input and FSM Output](https://github.com/matter-labs/era-zkevm_circuits/blob/main/src/sort_decommittment_requests/input.rs#L26) - -```rust -pub struct CodeDecommittmentsDeduplicatorFSMInputOutput<F: SmallField> { - pub initial_queue_state: QueueState<F, FULL_SPONGE_QUEUE_STATE_WIDTH>, - pub sorted_queue_state: QueueState<F, FULL_SPONGE_QUEUE_STATE_WIDTH>, - pub final_queue_state: QueueState<F, FULL_SPONGE_QUEUE_STATE_WIDTH>, - - pub lhs_accumulator: [Num<F>; DEFAULT_NUM_PERMUTATION_ARGUMENT_REPETITIONS], - pub rhs_accumulator: [Num<F>; DEFAULT_NUM_PERMUTATION_ARGUMENT_REPETITIONS], - - pub previous_packed_key: [UInt32<F>; PACKED_KEY_LENGTH], - pub first_encountered_timestamp: UInt32<F>, - pub previous_record: DecommitQuery<F>, -} -``` - -## Main circuit logic - -This circuit handles the sorting and deduplication of code cancellation requests. Before starting, during the pre-start -phase, the first decommitter queue is generated. To decommitter a code, the input will receive the hash root of the -code, the length of the code, the code hash of the opcode, the number of opcodes and the code of the page. Next, it -sorts the queue and, in the process, identifies and removes identical requests, serving as a filtering mechanism in case -the same contract is called several times. - -The detailed explanation of sorting and deduplicating can be found -[here](https://github.com/code-423n4/2023-10-zksync/blob/c3ff020df5d11fe91209bd99d7fb0ec1272dc387/docs/Circuits%20Section/Circuits/Sorting.md). - -### [First part](https://github.com/matter-labs/era-zkevm_circuits/blob/main/src/sort_decommittment_requests/mod.rs#L51) - -The circuit begins with allocating input part of the PI. - -```rust -let CodeDecommitmentsDeduplicatorInstanceWitness { - closed_form_input, - initial_queue_witness, - sorted_queue_witness, -} = witness; - -let mut structured_input = CodeDecommitmentsDeduplicatorInputOutput::alloc_ignoring_outputs( - cs, - closed_form_input.clone(), -); -``` - -In this part, we should decide what `initial_queue_state` to use (the one from `Input` or the other one from -`FSM Input`). We do the same for sorted queue. - -```rust -let state = QueueState::conditionally_select( - cs, - structured_input.start_flag, - &initial_queue_from_passthrough_state, - &initial_log_queue_state_from_fsm_state, -); -``` - -Also, we decide to create a new result queue or use one from the previous circuit. - -```rust -let state = QueueState::conditionally_select( - cs, - structured_input.start_flag, - &empty_state, - &final_sorted_queue_from_fsm_state, -); -``` - -Now we need to generate challenges for permutation argument. - -```rust -let challenges = crate::utils::produce_fs_challenges::< - F, - CS, - R, - FULL_SPONGE_QUEUE_STATE_WIDTH, - { DECOMMIT_QUERY_PACKED_WIDTH + 1 }, - DEFAULT_NUM_PERMUTATION_ARGUMENT_REPETITIONS, ->( - cs, - structured_input.observable_input.initial_queue_state.tail, - structured_input - .observable_input - .sorted_queue_initial_state - .tail, - round_function, -); -``` - -And decide whether we generate new accumulators for permutation argument or use existing ones. - -```rust -let initial_lhs = Num::parallel_select( - cs, - structured_input.start_flag, - &[one; DEFAULT_NUM_PERMUTATION_ARGUMENT_REPETITIONS], - &structured_input.hidden_fsm_input.lhs_accumulator, -); - -let initial_rhs = Num::parallel_select( - cs, - structured_input.start_flag, - &[one; DEFAULT_NUM_PERMUTATION_ARGUMENT_REPETITIONS], - &structured_input.hidden_fsm_input.rhs_accumulator, -); -``` - -Also, we make other parts of FSM state based on `start_flag`. - -```rust -let mut previous_record = DecommitQuery::conditionally_select( - cs, - structured_input.start_flag, - &trivial_record, - &structured_input.hidden_fsm_input.previous_record, -); - -let mut previous_packed_key = <[UInt32<F>; PACKED_KEY_LENGTH]>::conditionally_select( - cs, - structured_input.start_flag, - &[zero_u32; PACKED_KEY_LENGTH], - &structured_input.hidden_fsm_input.previous_packed_key, -); - -let mut first_encountered_timestamp = UInt32::conditionally_select( - cs, - structured_input.start_flag, - &zero_u32, - &structured_input - .hidden_fsm_input - .first_encountered_timestamp, -); -``` - -### [Main part](https://github.com/matter-labs/era-zkevm_circuits/blob/main/src/sort_Decommitment_requests/mod.rs#L234) - -Here we implement the main logic of the circuit. We run a cycle where on each iteration we try to pop a new element. - -```rust -let (_, original_encoding) = original_queue.pop_front(cs, should_pop); -let (sorted_item, sorted_encoding) = sorted_queue.pop_front(cs, should_pop); -``` - -We compute contribution to permutation argument accumulators. - -```rust -for ((challenges, lhs), rhs) in fs_challenges.iter().zip(lhs.iter_mut()).zip(rhs.iter_mut()) -{ - ... -} -``` - -After, we enforce that elements from sorted queue are actually sorted. - -```rust -new_key_is_greater.conditionally_enforce_true(cs, should_pop); -``` - -Also, we need to deduplicate some decommit requests if there are the same ones. - -```rust -// decide if we should add the PREVIOUS into the queue -let add_to_the_queue = Boolean::multi_and(cs, &[previous_is_non_trivial, different_hash]); - -result_queue.push(cs, record_to_add, add_to_the_queue); -``` - -Now we update inner variables. - -```rust -previous_item_is_trivial = is_trivial; -// may be update the timestamp -*first_encountered_timestamp = UInt32::conditionally_select( - cs, - same_hash, - &first_encountered_timestamp, - &sorted_item.timestamp, -); -*previous_record = sorted_item; -*previous_packed_key = packed_key; -``` - -In the end, if the queues are empty, and we have taken the last element, we push it immediately. - -```rust -let add_to_the_queue = Boolean::multi_and(cs, &[previous_is_non_trivial, completed]); - -result_queue.push(cs, record_to_add, add_to_the_queue); -``` - -### [Final part](https://github.com/matter-labs/era-zkevm_circuits/blob/main/src/sort_Decommitment_requests/mod.rs#L191C1-L191C1) - -We check that permutation accumulators are equal, if the queues are already empty. - -```rust -for (lhs, rhs) in new_lhs.iter().zip(new_rhs.iter()) { - Num::conditionally_enforce_equal(cs, completed, lhs, rhs); -} -``` - -Now we update PI output parts and compute a commitment. Then we allocate it as public variables. - -```rust -let compact_form = - ClosedFormInputCompactForm::from_full_form(cs, &structured_input, round_function); -let input_commitment = commit_variable_length_encodable_item(cs, &compact_form, round_function); -for el in input_commitment.iter() { - let gate = PublicInputGate::new(el.get_variable()); - gate.add_to_cs(cs); -} -``` diff --git a/content/40.zk-stack/components/prover/circuits/sorting/storage-sorter.md b/content/40.zk-stack/components/prover/circuits/sorting/storage-sorter.md deleted file mode 100644 index ea2bcd25..00000000 --- a/content/40.zk-stack/components/prover/circuits/sorting/storage-sorter.md +++ /dev/null @@ -1,289 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Circuits - SortDecommitments | zkSync Docs ---- - -# StorageSorter - -## StorageSorter PI - -### [Input](https://github.com/matter-labs/era-zkevm_circuits/blob/main/src/storage_validity_by_grand_product/input.rs#L84C57-L84C57) - -```rust -pub struct StorageDeduplicatorInputData<F: SmallField> { - pub shard_id_to_process: UInt8<F>, - pub unsorted_log_queue_state: QueueState<F, QUEUE_STATE_WIDTH>, - pub intermediate_sorted_queue_state: QueueState<F, QUEUE_STATE_WIDTH>, -} -``` - -### [Output](https://github.com/matter-labs/era-zkevm_circuits/blob/main/src/storage_validity_by_grand_product/input.rs#L103) - -```rust -pub struct StorageDeduplicatorOutputData<F: SmallField> { - pub final_sorted_queue_state: QueueState<F, QUEUE_STATE_WIDTH>, -} -``` - -### [FSM Input and FSM Output](https://github.com/matter-labs/era-zkevm_circuits/blob/main/src/storage_validity_by_grand_product/input.rs#L37) - -```rust -pub struct StorageDeduplicatorFSMInputOutput<F: SmallField> { - pub lhs_accumulator: [Num<F>; DEFAULT_NUM_PERMUTATION_ARGUMENT_REPETITIONS], - pub rhs_accumulator: [Num<F>; DEFAULT_NUM_PERMUTATION_ARGUMENT_REPETITIONS], - pub current_unsorted_queue_state: QueueState<F, QUEUE_STATE_WIDTH>, - pub current_intermediate_sorted_queue_state: QueueState<F, QUEUE_STATE_WIDTH>, - pub current_final_sorted_queue_state: QueueState<F, QUEUE_STATE_WIDTH>, - pub cycle_idx: UInt32<F>, - pub previous_packed_key: [UInt32<F>; PACKED_KEY_LENGTH], - pub previous_key: UInt256<F>, - pub previous_address: UInt160<F>, - pub previous_timestamp: UInt32<F>, - pub this_cell_has_explicit_read_and_rollback_depth_zero: Boolean<F>, - pub this_cell_base_value: UInt256<F>, - pub this_cell_current_value: UInt256<F>, - pub this_cell_current_depth: UInt32<F>, -} -``` - -## Main circuit logic - -The main logic of this circuit is sorting and deduplicating storage requests from `unsorted_log_queue_state`. The result -storage requests are pushed to `final_sorted_queue_state`. - -### [First part](https://github.com/matter-labs/era-zkevm_circuits/blob/main/src/storage_validity_by_grand_product/mod.rs#L177) - -We start, as usually, with allocating input fields from PI. - -```rust -let mut structured_input = StorageDeduplicatorInputOutput::alloc_ignoring_outputs( - cs, - structured_input_witness.clone(), -); -``` - -In this part, we should decide what `unsorted_queue_state` to use (the one from `Input` or the other one from -`FSM Input`). We do the same for sorted queue. - -```rust -let state = QueueState::conditionally_select( - cs, - structured_input.start_flag, - &unsorted_queue_from_passthrough_state, - &unsorted_queue_from_fsm_input_state, -); - -let state = QueueState::conditionally_select( - cs, - structured_input.start_flag, - &intermediate_sorted_queue_from_passthrough.into_state(), - &intermediate_sorted_queue_from_fsm_input.into_state(), -); -``` - -Also, we decide to create a new queue for the output, or continue working with the existing one. - -```rust -let state = QueueState::conditionally_select( - cs, - structured_input.start_flag, - &empty_final_sorted_queue.into_state(), - &final_sorted_queue_from_fsm_input.into_state(), -); -``` - -Now we need to generate challenges for permutation argument. - -```rust -let challenges = crate::utils::produce_fs_challenges::< - F, - CS, - R, - QUEUE_STATE_WIDTH, - { TIMESTAMPED_STORAGE_LOG_ENCODING_LEN + 1 }, - DEFAULT_NUM_PERMUTATION_ARGUMENT_REPETITIONS, ->( - cs, - structured_input - .observable_input - .unsorted_log_queue_state - .tail, - structured_input - .observable_input - .intermediate_sorted_queue_state - .tail, - round_function, -); -``` - -And decide whether we generate new accumulators for permutation argument or use existing ones. - -```rust -let initial_lhs = - <[Num<F>; DEFAULT_NUM_PERMUTATION_ARGUMENT_REPETITIONS]>::conditionally_select( - cs, - structured_input.start_flag, - &[one; DEFAULT_NUM_PERMUTATION_ARGUMENT_REPETITIONS], - &structured_input.hidden_fsm_input.lhs_accumulator, - ); - -let initial_rhs = - <[Num<F>; DEFAULT_NUM_PERMUTATION_ARGUMENT_REPETITIONS]>::conditionally_select( - cs, - structured_input.start_flag, - &[one; DEFAULT_NUM_PERMUTATION_ARGUMENT_REPETITIONS], - &structured_input.hidden_fsm_input.rhs_accumulator, - ); -``` - -### [Main part](https://github.com/matter-labs/era-zkevm_circuits/blob/main/src/storage_validity_by_grand_product/mod.rs#L558) - -Here we implement the main logic of the circuit. We run a cycle where on each iteration we try to pop a new element. - -```rust -let (_, original_encoding) = original_queue.pop_front(cs, should_pop); -let (sorted_item, sorted_encoding) = intermediate_sorted_queue.pop_front(cs, should_pop); -``` - -Then we accumulate encodings for permutation argument. You can read more about it -[here](https://github.com/code-423n4/2023-10-zksync/blob/c3ff020df5d11fe91209bd99d7fb0ec1272dc387/docs/Circuits%20Section/Circuits/Sorting.md). - -```rust -for (((lhs_dst, rhs_dst), challenges), additive_part) in lhs - .iter_mut() - .zip(rhs.iter_mut()) - .zip(fs_challenges.iter()) - .zip(additive_parts.iter()) -{ - lhs_lc.clear(); - rhs_lc.clear(); - - for ((original_el, sorted_el), challenge) in extended_original_encoding - .iter() - .zip(sorted_encoding.iter()) - .zip(challenges.iter()) - { - let lhs_contribution = original_el.mul(cs, &challenge); - let rhs_contribution = sorted_el.mul(cs, &challenge); - - lhs_lc.push((lhs_contribution.get_variable(), F::ONE)); - rhs_lc.push((rhs_contribution.get_variable(), F::ONE)); - } - - lhs_lc.push((additive_part.get_variable(), F::ONE)); - rhs_lc.push((additive_part.get_variable(), F::ONE)); - - let lhs_lc = Num::linear_combination(cs, &lhs_lc); - let rhs_lc = Num::linear_combination(cs, &rhs_lc); - - let lhs_candidate = lhs_dst.mul(cs, &lhs_lc); - let rhs_candidate = rhs_dst.mul(cs, &rhs_lc); - - *lhs_dst = Num::conditionally_select(cs, should_pop, &lhs_candidate, &*lhs_dst); - *rhs_dst = Num::conditionally_select(cs, should_pop, &rhs_candidate, &*rhs_dst); -} -``` - -Now we enforce sorting. - -```rust -previous_key_is_greater.conditionally_enforce_false(cs, not_item_is_trivial); -``` - -Maybe we should push the old query if the new key is different. So we push if at least one of these conditions holds: - -- there was a read at depth 0; -- the sell is changes; -- write that was declined, but not by a rollback. - -```rust -let query = LogQuery { - address: previous_address, - key: previous_key, - read_value: this_cell_base_value, - written_value: this_cell_current_value, - rw_flag: should_write, - aux_byte: UInt8::zero(cs), - rollback: Boolean::allocated_constant(cs, false), - is_service: Boolean::allocated_constant(cs, false), - shard_id: shard_id_to_process, - tx_number_in_block: UInt32::zero(cs), - timestamp: UInt32::zero(cs), -}; - -sorted_queue.push(cs, query, should_push); -``` - -After that, we update some inner variables. - -```rust -let meaningful_value = UInt256::conditionally_select( - cs, - record.rw_flag, - &record.written_value, - &record.read_value, -); - -this_cell_base_value = UInt256::conditionally_select( - cs, - new_non_trivial_cell, - &record.read_value, - &this_cell_base_value, -); - -... -``` - -Now we continue working with current query. We check that the read field is correct. - -```rust -let read_is_equal_to_current = - UInt256::equals(cs, &this_cell_current_value, &record.read_value); -read_is_equal_to_current.conditionally_enforce_true(cs, check_read_consistency); -``` - -After that, we do some other variable updates. - -After the main cycle, we do one more iteration if we took the last query from the queue during the last cycle. - -```rust -let query = LogQuery { - address: previous_address, - key: previous_key, - read_value: this_cell_base_value, - written_value: this_cell_current_value, - rw_flag: should_write, - aux_byte: UInt8::zero(cs), - rollback: Boolean::allocated_constant(cs, false), - is_service: Boolean::allocated_constant(cs, false), - shard_id: shard_id_to_process, - tx_number_in_block: UInt32::zero(cs), - timestamp: UInt32::zero(cs), -}; - -sorted_queue.push(cs, query, should_push); -``` - -### [Final part](https://github.com/matter-labs/era-zkevm_circuits/blob/main/src/storage_validity_by_grand_product/mod.rs#L424) - -If the queues are empty, we check the permutation argument accumulators equality. - -```rust -let completed = unsorted_is_empty.and(cs, sorted_is_empty); -new_lhs.iter().zip(new_rhs).for_each(|(l, r)| { - Num::conditionally_enforce_equal(cs, completed, &l, &r); -}); -``` - -Now we update PI output parts and compute a commitment. Then we allocate it as public variables. - -```rust -let input_commitment = - commit_variable_length_encodable_item(cs, &compact_form, round_function); -for el in input_commitment.iter() { - let gate = PublicInputGate::new(el.get_variable()); - gate.add_to_cs(cs); -} -``` diff --git a/content/40.zk-stack/components/prover/circuits/storage-application.md b/content/40.zk-stack/components/prover/circuits/storage-application.md deleted file mode 100644 index 25140d7d..00000000 --- a/content/40.zk-stack/components/prover/circuits/storage-application.md +++ /dev/null @@ -1,220 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Circuits - StorageApplication | zkSync Docs ---- - -# StorageApplication - -## StorageApplication PI - -### [Input](https://github.com/matter-labs/era-zkevm_circuits/blob/main/src/storage_application/input.rs#L56) - -```rust -pub struct StorageApplicationInputData<F: SmallField> { - pub shard: UInt8<F>, - pub initial_root_hash: [UInt8<F>; 32], - pub initial_next_enumeration_counter: [UInt32<F>; 2], - pub storage_application_log_state: QueueState<F, QUEUE_STATE_WIDTH>, -} -``` - -### [Output](https://github.com/matter-labs/era-zkevm_circuits/blob/main/src/storage_application/input.rs#L77) - -```rust -pub struct StorageApplicationOutputData<F: SmallField> { - pub new_root_hash: [UInt8<F>; 32], - pub new_next_enumeration_counter: [UInt32<F>; 2], - pub state_diffs_keccak256_hash: [UInt8<F>; 32], -} -``` - -### [FSM Input and FSM Output](https://github.com/matter-labs/era-zkevm_circuits/blob/main/src/storage_application/input.rs#L29) - -```rust -pub struct StorageApplicationFSMInputOutput<F: SmallField> { - pub current_root_hash: [UInt8<F>; 32], - pub next_enumeration_counter: [UInt32<F>; 2], - pub current_storage_application_log_state: QueueState<F, QUEUE_STATE_WIDTH>, - pub current_diffs_keccak_accumulator_state: - [[[UInt8<F>; keccak256::BYTES_PER_WORD]; keccak256::LANE_WIDTH]; keccak256::LANE_WIDTH], -} -``` - -## Main circuit logic - -This circuit takes storage requests from `storage_application_log_state`. Then for each query, it verifies the read -value and updates the `root_hash` is needed. Also, it outputs the hash of storage diffs. Shard_id if enforces to be 0 -for now, because we have only one shard. - -### [First part](https://github.com/matter-labs/era-zkevm_circuits/blob/main/src/storage_application/mod.rs#L281) - -The circuit begins with allocating input part of the PI. - -```rust -let StorageApplicationCircuitInstanceWitness { - closed_form_input, - storage_queue_witness, - merkle_paths, - leaf_indexes_for_reads, -} = witness; - -let mut structured_input = - StorageApplicationInputOutput::alloc_ignoring_outputs(cs, closed_form_input.clone()); -``` - -We chose what `storage_application_log_state`, `root_hash` and other fields to continue to work with. - -```rust -let mut current_root_hash = UInt8::<F>::parallel_select( - cs, - start_flag, - &structured_input.observable_input.initial_root_hash, - &structured_input.hidden_fsm_input.current_root_hash, -); - -let storage_accesses_queue_state = QueueState::conditionally_select( - cs, - start_flag, - &storage_queue_state_from_input, - &storage_queue_state_from_fsm, -); - -... -``` - -### [Main part](https://github.com/matter-labs/era-zkevm_circuits/blob/main/src/storage_application/mod.rs#L393) - -Here’s the part, where all the main logic is implemented. Firstly, we take a new storage request if needed. - -```rust -let (storage_log, _) = storage_accesses_queue.pop_front(cs, parse_next_queue_elem); -``` - -Now we can parse it and do some checks. - -```rust -let LogQuery { - address, - key, - read_value, - written_value, - rw_flag, - shard_id, - .. -} = storage_log; -``` - -We need a merkle path for executing query. - -```rust -for _ in 0..STORAGE_DEPTH { - let wit = merkle_path_witness_allocator.conditionally_allocate_biased( - cs, - parse_next_queue_elem, - bias_variable, - ); - bias_variable = wit.inner[0].get_variable(); - new_merkle_path_witness.push(wit); -} -``` - -Also, we update `state_diffs` data. - -```rust -state_diff_data.address = UInt8::parallel_select( - cs, - parse_next_queue_elem, - &address_bytes, - &state_diff_data.address, -); -state_diff_data.key = - UInt8::parallel_select(cs, parse_next_queue_elem, &key_bytes, &state_diff_data.key); -state_diff_data.derived_key = UInt8::parallel_select( - cs, - parse_next_queue_elem, - &derived_key, - &state_diff_data.derived_key, -); -... -``` - -Finally, we compute a new merkle path. - -```rust -let mut current_hash = blake2s(cs, &leaf_bytes); - -for (path_bit, path_witness) in path_selectors - .into_iter() - .zip(merkle_path_witness.into_iter()) -{ - let left = UInt8::parallel_select(cs, path_bit, &path_witness, ¤t_hash); - let right = UInt8::parallel_select(cs, path_bit, ¤t_hash, &path_witness); - let mut input = [zero_u8; 64]; - input[0..32].copy_from_slice(&left); - input[32..64].copy_from_slice(&right); - - current_hash = blake2s(cs, &input); -} -``` - -If it was a write request, then we update the `root_hash`. Otherwise, we enforce that it’s still the same. - -```rust -current_root_hash = UInt8::parallel_select( - cs, - write_stage_in_progress, - ¤t_hash, - ¤t_root_hash, -); - -for (a, b) in current_root_hash.iter().zip(current_hash.iter()) { - Num::conditionally_enforce_equal( - cs, - should_compare_roots, - &Num::from_variable(a.get_variable()), - &Num::from_variable(b.get_variable()), - ); -} -``` - -In the end, we update `state_diffs` state. - -```rust -for block in - extended_state_diff_encoding.array_chunks::<{ keccak256::KECCAK_RATE_BYTES }>() -{ - keccak256_conditionally_absorb_and_run_permutation( - cs, - write_stage_in_progress, - &mut diffs_keccak_accumulator_state, - block, - ); -} -``` - -### [Final part](https://github.com/matter-labs/era-zkevm_circuits/blob/main/src/storage_application/mod.rs#L643) - -We need to run padding and one more permutation for final output. - -```rust -keccak256_conditionally_absorb_and_run_permutation( - cs, - boolean_true, - &mut diffs_keccak_accumulator_state, - &padding_block, -); -``` - -Now we update PI output parts and compute a commitment. Then we allocate it as public variables. - -```rust -let compact_form = - ClosedFormInputCompactForm::from_full_form(cs, &structured_input, round_function); -let input_commitment = commit_variable_length_encodable_item(cs, &compact_form, round_function); -for el in input_commitment.iter() { - let gate = PublicInputGate::new(el.get_variable()); - gate.add_to_cs(cs); -} -``` diff --git a/content/40.zk-stack/components/prover/overview.md b/content/40.zk-stack/components/prover/overview.md deleted file mode 100644 index c0493a8a..00000000 --- a/content/40.zk-stack/components/prover/overview.md +++ /dev/null @@ -1,69 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Prover | zkSync Docs ---- - -# Prover - -As a ZK rollup, we want everything to be verified by cryptography and secured by Ethereum. The power of ZK allows for -transaction compression, reducing fees for users while inheriting the same security. - -ZK Proofs allow a verifier to easily check whether a prover has done a computation correctly. For zkSync, the prover -will prove the correct execution of zkSync’s EVM, and a smart contract on Ethereum will verify the proof is correct. - -In more detail, there are several steps. - -- Witness generation: witness generation can be perceived as part of the process where the user (prover) generates proof - of transaction validity. For instance, when a user initiates a transaction, a corresponding witness is generated, - which serves as proof that the transaction is valid and adheres to the network's consensus rules. The zero-knowledge - aspect ensures that the witness reveals no information about the transaction's specifics, maintaining user privacy and - data security. New transactions are proved in batches. These batches will be processed and sent to the circuits. -- Circuits: Our virtual machine needs to prove that the execution was completed correctly to generate proofs correctly. - This is accomplished using circuits. In order for proofs to work, normal code logic must be transformed into a format - readable by the proof system. The virtual machine reads the code that will be executed and sorts the parts into - various circuits. These circuits then break down the parts of code, which can then be sent to the proof system. -- Proof system: We need a proof system to process the ZK circuit. Our proving system is called Boojum. - -Here are the different repositories we use: - -- **Boojum**: Think of this as the toolbox. It holds essential tools and parts like the prover (which helps confirm the - circuit's functionality), verifier (which double-checks everything), and various other backend components. These are - the technical bits and pieces, like defining Booleans, Nums, and Variables that will be used in the circuits. -- **zkevm_circuits**: This is where we build and store the actual circuits. The circuits are built from Boojum and - designed to replicate the behavior of the EVM. -- **zkevm_test_harness**: It's like our testing ground. Here, we have different tests to ensure our circuits work - correctly. Additionally, it has the necessary code that helps kickstart and run these circuits smoothly. - -### What is a circuit - -ZK circuits get their name from Arithmetic Circuits, which look like this (see picture). You can read the circuit by -starting at the bottom with the inputs, and following the arrows, computing each operation as you go. - -<p > -<img src="../../../assets/images/circuit.png" alt="Arithmetic Circuit Diagram" style="background-color: white;align:center"> -</p> - -The prover will prove that the circuit is “satisfied” by the inputs, meaning every step is computed correctly, leading -to a correct output. - -It is very important that every step is actually “constrained”. The prover must be forced to compute the correct values. -If the circuit is missing a constraint, then a malicious prover can create proofs that will pass verification but not be -valid. The ZK terminology for this is that an underconstrained circuit could lead to a soundness error. - -### What do zkSync’s circuits prove - -The main goal of our circuits is to prove correct execution of our VM. This includes proving each opcode run within the -VM, as well as other components such as precompiles, storage, and circuits that connect everything else together. This -is described in more detail in -[Circuits](https://github.com/code-423n4/2023-10-zksync/blob/main/docs/Circuits%20Section/Circuits.md) - -### More details - -The process of turning code into constraints is called arithmetization. Our arithmetization is based on a variation of -“Plonk”. The details are abstracted away from the circuits, but if you’d like to learn more, read about Plonk in -[Vitalik’s blog](https://vitalik.eth.limo/general/2019/09/22/plonk.html) or the -[Plonky2 paper](https://github.com/mir-protocol/plonky2/blob/main/plonky2/plonky2.pdf). - -More details of our proving system can be found in the [Redshift Paper](https://eprint.iacr.org/2019/1400.pdf). diff --git a/content/40.zk-stack/components/prover/run-the-prover.md b/content/40.zk-stack/components/prover/run-the-prover.md deleted file mode 100644 index e08b8245..00000000 --- a/content/40.zk-stack/components/prover/run-the-prover.md +++ /dev/null @@ -1,28 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Run the Prover | zkSync Docs ---- - -# Getting Started - -Our ZK code is spread across three repositories: - -[Boojum](https://github.com/matter-labs/era-boojum/tree/main) contains the low level ZK details. - -[zkevm_circuits](https://github.com/matter-labs/era-zkevm_circuits/tree/main) contains the code for the circuits. - -[zkevm_test_harness](https://github.com/matter-labs/era-zkevm_test_harness/tree/v1.4.0) contains the tests for the -circuits. - -To get started, run the basic_test from the era-zkevm_test_harness: - -```bash -rustup default nightly-2023-08-23 -cargo update -cargo test basic_test --release -- --nocapture - -``` - -This test may take several minutes to run, but you will see lot’s of information along the way! diff --git a/content/40.zk-stack/components/prover/zk-terminology.md b/content/40.zk-stack/components/prover/zk-terminology.md deleted file mode 100644 index 74040121..00000000 --- a/content/40.zk-stack/components/prover/zk-terminology.md +++ /dev/null @@ -1,110 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: ZK Terminology | zkSync Docs ---- - -# ZK Terminology - -## Arithmetization - -Arithmetization refers to a technique used in zero-knowledge proof systems, where computations are represented in such a -way that they can be efficiently verified by a prover and a verifier. In simpler terms, it is a way to convert -computations into polynomial equations so that they can be used in cryptographic proofs. - -## Builder - -The builder helps set up the constraint system. The builder knows the placement strategy for each gate, as well as the -geometry and other information needed for building the constraint system. - -## Circuit - -An arithmetic circuit is a mathematical construct used in cryptography to encode a computational problem. It is -comprised of gates, with each gate performing an arithmetic operation, for example, such as addition or multiplication. -These circuits are essential for encoding statements or computations that a prover wants to prove knowledge of without -revealing the actual information. - -## Constraint - -A constraint is a rule or restriction that a specific operation or set of operations must follow. zkSync uses -constraints to verify the validity of certain operations, and in the generation of proofs. Constraints can be missing, -causing bugs, or there could be too many constraints, leading to restricted operations. - -## Constraint degree - -The "constraint degree" of a constraint system refers to the maximum degree of the polynomial gates in the system. In -simpler terms, it’s the highest power of polynomial equations of the constraint system. At zkSync, we allow gates with -degree 8 or lower. - -## Constraint system - -Constraint system is a mathematical representation consisting of a set of equations or polynomial constraints that are -constructed to represent the statements being proved. The system is deemed satisfied if there exist specific assignments -to the variables that make all the equations or constraints true. Imagine it as a list of "placeholders" called -Variables. Then we add gates to the variables which enforce a specific constraint. The Witness represents a specific -assignment of values to these Variables, ensuring that the rules still hold true. - -## Geometry - -The geometry defines the number of rows and columns in the constraint system. As part of PLONK arithmetization, the -witness data is arranged into a grid, where each row defines a gate (or a few gates), and the columns are as long as -needed to hold all of the witness data. At zkSync, we have ~164 base witness columns. - -## Log - -We use the word “log” in the sense of a database log: a log stores a list of changes. - -## Lookup table - -Lookup table is a predefined table used to map input values to corresponding output values efficiently, assisting in -validating certain relations or computations without revealing any extra information about the inputs or the internal -computations. \***\*Lookup \*\***tables are particularly useful in ZK systems to optimize and reduce the complexity of -computations and validations, enabling the prover to construct proofs more efficiently and the verifier to validate -relationships or properties with minimal computational effort. For example, if you want to prove a certain number is -between 0 and 2^8, it is common to use a lookup table. - -## Proof - -A proof can refer generally to the entire proving process, or a proof can refer specifically to the data sent from the -prover to the verifier. - -## Prover - -In our zkSync zk-rollup context, the prover is used to process a set of transactions executing smart contracts in a -succinct and efficient manner. It computes proofs that all the transactions are correct and ensures a valid transition -from one state to another. The proof will be sent to a Verifier smart contract on Ethereum. At zkSync, we prove state -diffs of a block of transactions, in order to prove the new state root state is valid. - -## Satisfiable - -In the context of ZK, satisfiability refers to whether the witness passes - or “satisfies” - all of the constraints in a -circuit. - -## State Diffs - -State Diffs, or State Differentials, are the differences in accounts before and after processing transactions contained -in a block. For example, if my ETH Balance changes from 5 ETH to 6 ETH, then the state diff for my account is +1 ETH. - -## Variables - -Variables are placeholders in the constraint system until we know the specific witness data. The reason we would want -placeholders is because we might want to fill in which constraints we need, before knowing the actual input data. For -example, we might know we need to add two numbers and constrain the sum, before we know exactly which two numbers will -be in the witness. - -## Verifier - -The Verifier is a smart contract on Ethereum. It will receive a proof, check to make sure the proof is valid, and then -update the state root. - -## Witness - -Witness refers to the private, secret information or set of values that the prover possesses and aims to demonstrate -knowledge of, without revealing the actual information to the verifier. The witness is the input to the circuit. When we -have a circuit, the valid “witness” is the input that meets all the constraints and satisfies everything. - -## Worker - -A worker refers to our multi-threaded proving system. Proving may be “worked” in parallel, meaning that we can execute -some operations, like polynomial addition, in parallel threads. diff --git a/content/40.zk-stack/components/sequencer-server.md b/content/40.zk-stack/components/sequencer-server.md deleted file mode 100644 index 1148e9a2..00000000 --- a/content/40.zk-stack/components/sequencer-server.md +++ /dev/null @@ -1,54 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Sequencer / Server | zkSync Docs ---- - -# Sequencer / Server - -The zkSync Sequencer is actually a collection of services and functions acting in coordination to monitor L1, maintain -L2 state, and order incoming transactions. - -Its modules are [here](https://github.com/matter-labs/zksync-era) and are also described below: - -## RPC Services - -This is the main interface for users to interact with the server. - -It includes: - -- `HttpApi` - HTTP public Web3 API - -- `WsApi` - WebSocket Web3 API (including PubSub) - -## ETH Operator - -This module is responsible for interacting with the L1. It acts as both an observer and agent executing transactions. It -includes: - -- `EthWatcher` - Monitor the base layer for specific events, such as Deposits or System Upgrades. - -- `EthTxAggregator` - Aggregates batches to send to L1 and prepares the transaction to send it, requiring operations - such as `commit_blocks`, `prove_blocks` and `execute_blocks`. - -- `EthTxManager` - Signs and sends L1 transactions prepared by `EthTxAggregator`. It's responsible for monitoring and - resending transactions if they fail for any reason (for example, low gas price). - -## Sequencer - -Component that takes a list of incoming transactions on zkSync and packs them into blocks and batches. The sequencer -makes sure each transaction fits within the constraints required by our proving system. After a batch is collected, the -sequencer executes them on the zkEVM. - -It includes: - -- `Tree` and `TreeBackup` - Maintains a local RocksDB instance with the complete L2 storage tree, computing the latest - state root hash. - -- `StateKeeper` - Executes the transactions and saves sealed blocks to the local RocksDB instance. - -## Contract Verification API - -The service that receives smart contract verification requests, validates them and provides the code/ABIs for verified -contracts. diff --git a/content/40.zk-stack/components/shared-bridges.md b/content/40.zk-stack/components/shared-bridges.md deleted file mode 100644 index 5d83b53c..00000000 --- a/content/40.zk-stack/components/shared-bridges.md +++ /dev/null @@ -1,245 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Shared Bridge | zkSync Docs ---- - -# Shared Bridge - -Ethereum's future is rollup-centric. This means breaking with the current paradigm of isolated EVM chains to -infrastructure that is focused on an ecosystem of interconnected zkEVMs, which we call Hyperchains. This ecosystem will -be grounded on Ethereum with the appropriate L1 smart contracts. - -Here we outline our ZK Stack approach for these contracts, their interfaces, the needed changes to the existing -architecture, as well as future features to be implemented. - -If you want to know more about Hyperchains, check this -[blog post](https://blog.matter-labs.io/introduction-to-hyperchains-fdb33414ead7), or go through -[Hyperchains](../concepts/hyperchains-hyperscaling.md) in our docs. - -## High-level design - -We want to create a system where: - -- Hyperchains should be launched permissionlessly within the ecosystem. -- Hyperbridges should enable unified liquidity for assets across the ecosystem. -- Multi-chain smart contracts need to be easy to develop, which means easy access to traditional bridges, and other - supporting architecture. - -Hyperchains have specific trust requirements - they need to satisfy certain common standards so that they can trust each -other. This means a single set of L1 smart contracts has to manage the proof verification for all hyperchains, and if -the proof system is upgraded, all chains have to be upgraded together. New chains will be able to be launched -permissionlessly in the ecosystem according to this shared standard. - -To allow unified liquidity each L1 asset (ETH, ERC20, NFTs) will have a single bridge contract on L1 for the whole -ecosystem. These shared bridges will allow users to deposit, withdraw and transfer from any hyperchain in the ecosystem. -These shared bridges are also responsible for deploying and maintaining their counterparts on the hyperchains. The -counterparts will be asset contracts extended with bridging functionality. - -To enable the bridging functionality: - -- On the L1 we will add a Bridgehub contract which connects asset bridges to all the hyperchains. This will also be the - contract that holds the ETH for the ecosystem. -- On the Hyperchain side we will add special system contracts that enable these features. - -We want to make the ecosystem as modular as possible, giving developers the ability to modify the architecture as -needed; consensus mechanism, staking, and DA requirements. - -We also want the system to be forward-compatible, with future updates like L3s, proof aggregation, alternative State -Transition (ST) contracts, and ZK IP (which would allow unified liquidity between all STs). Those future features have -to be considered in this initial design, so it can evolve to support them (meaning, chains being launched now will still -be able to leverage them when available). - ---- - -## Architecture - -![Contracts](../../assets/images/contracts-external.png) - -## Components: Bridgehub - -- Acts as a hub for bridges, so that they have a single point of communication with all hyperchain contracts. This - allows L1 assets to be locked in the same contract for all hyperchains, including L3s and validiums. The `Bridgehub` - also implements the following: -- `Registry` This is where hyperchains can register, starting in a permissioned manner, but with the goal to be - permissionless in the future. This is where their `chainID` is determined. L3s will also register here. This - `Registry` is also where State Transition contracts should register. Each chain has to specify its desired ST when - registering (Initially, only one will be available). - - ``` - function newChain( - uint256 _chainId, - address _stateTransition - ) external returns (uint256 chainId); - - function newStateTransition(address _stateTransition) external; - ``` - -- `BridgehubMailbox` routes messages to the Diamond proxy’s Mailbox facet based on chainID - - - Same as the current zkEVM - [Mailbox](https://github.com/matter-labs/era-contracts/blob/main/system-contracts/contracts/interfaces/IMailbox.sol), - just with chainId, - - Ether needs to be deposited and withdrawn from here. - - This is where L2 transactions can be requested. - - ``` - function requestL2Transaction( - uint256 _chainId, - address _contractL2, - uint256 _l2Value, - bytes calldata _calldata, - uint256 _l2GasLimit, - uint256 _l2GasPerPubdataByteLimit, - bytes[] calldata _factoryDeps, - address _refundRecipient - ) public payable override returns (bytes32 canonicalTxHash) { - address proofChain = bridgeheadStorage.proofChain[_chainId]; - canonicalTxHash = IProofChain(proofChain).requestL2TransactionBridgehead( - _chainId, - msg.value, - msg.sender, - _contractL2, - _l2Value, - _calldata, - _l2GasLimit, - _l2GasPerPubdataByteLimit, - _factoryDeps, - _refundRecipient - ); - } - ``` - -- `Hypermailbox` - - This will allow general message passing (L2<>L2, L2<>L3, etc). This is where the `Mailbox` sends the `Hyperlogs`. - `Hyperlogs` are commitments to these messages sent from a single hyperchain. `Hyperlogs` are aggregated into a - `HyperRoot` in the `HyperMailbox`. - - This component has not been implemented yet - -### Main Asset Shared Bridges - -- Some assets have to be natively supported (ETH, WETH) and it also makes sense to support some generally accepted token - standards (ERC20 tokens), as this makes it easy to bridge those tokens (and ensures a single version of them exists on - the hyperchain). These canonical asset contracts are deployed from L1 by a bridge shared by all hyperchains. This is - where assets are locked on L1. These bridges use the Bridgehub to communicate with all hyperchains. Currently, these - bridges are the `WETH` and `ERC20` bridges. - - - The pair on L2 is deployed from L1. The hash of the factory dependencies is stored on L1, and when a hyperchain - wants to register, it can passes it in for deployment, it is verified, and the contract is deployed on L2. The - actual token contracts on L2 are deployed by the L2 bridge. - - ``` - function initializeChain( - uint256 _chainId, - bytes[] calldata _factoryDeps, - uint256 _deployBridgeImplementationFee, - uint256 _deployBridgeProxyFee - ) external payable { - .... - // Deploy L2 bridge proxy contract - l2Bridge[_chainId] = BridgeInitializationHelper.requestDeployTransaction( - _chainId, - bridgehead, - _deployBridgeProxyFee, - l2WethBridgeProxyBytecodeHash, - l2WethBridgeProxyConstructorData, - // No factory deps are needed for L2 bridge proxy, because it is already passed in the previous step - new bytes[](0) - ); - ``` - -## Components: State Transition - -- `StateTransition` A state transition manages proof verification and DA for multiple chains. It also implements the - following functionalities: - - `StateTransitionRegistry` The ST is shared for multiple chains, so initialization and upgrades have to be the same - for all chains. Registration is not permissionless but happens based on the registrations in the bridgehub’s - `Registry`. At registration a `DiamondProxy` is deployed and initialized with the appropriate `Facets` for each - Hyperchain. - - `Facets` and `Verifier` are shared across chains that relies on the same ST: `Base`, `Executor` , `Getters`, `Admin` - , `Mailbox.`The `Verifier` is the contract that actually verifies the proof, and is called by the `Executor`. - - Upgrade Mechanism The system requires all chains to be up-to-date with the latest implementation, so whenever an - update is needed, we have to “force” each chain to update, but due to decentralization, we have to give each chain a - time frame (more information in the - [Upgrade Mechanism](https://www.notion.so/ZK-Stack-shared-bridge-alpha-version-a37c4746f8b54fb899d67e474bfac3bb?pvs=21) - section). This is done in the update mechanism contract, this is where the bootloader and system contracts are - published, and the `ProposedUpgrade` is stored. Then each chain can call this upgrade for themselves as needed. - After the deadline is over, the not-updated chains are frozen, that is, cannot post new proofs. Frozen chains can - unfreeze by updating their proof system. -- Each chain has a `DiamondProxy`. - - The [Diamond Proxy](https://eips.ethereum.org/EIPS/eip-2535) is the proxy pattern that is used for the chain - contracts. A diamond proxy points to multiple implementation contracts called facets. Each selector is saved in the - proxy, and the correct facet is selected and called. - - In the future the DiamondProxy can be configured by picking alternative facets e.g. Validiums will have their own - `Executor` - -## Components: Chain Specific Contracts - -- A chain might implement its own specific consensus mechanism. This needs its own contracts. Only this contract will be - able to submit proofs to the State Transition contract. -- Currently, the `ValidatorTimelock` is an example of such a contract. - -### Components interactions - -In this section, we will present some diagrams showing the interaction of different components. - -#### New Chain - -A chain registers in the Bridgehub, this is where the chain ID is determined. The chain’s governor specifies the State -Transition that they plan to use. In the first version only a single State Transition contract will be available for -use, our with Boojum proof verification. - -At initialization we prepare the `StateTransitionChain` contract. We store the genesis batch hash in the ST contract, -all chains start out with the same state. A diamond proxy is deployed and initialised with this initial value, along -with predefined facets which are made available by the ST contract. These facets contain the proof verification and -other features required to process proofs. The chain ID is set in the VM in a special system transaction sent from L1. - -<!--![newChain.png](./img/newChain.png) Image outdated--> - -## Components: WETH Contract - -Ether, the native gas token is part of the core system contracts, so deploying it is not necessary. But WETH is just a -smart contract, it needs to be deployed and initialised. This happens from the L1 WETH bridge. This deploys on L2 the -corresponding bridge and ERC20 contract. This is deployed from L1, but the L2 address is known at deployment time. - -![deployWeth.png](../../assets/images/deploy-weth.png) - -## Components: Deposit WETH - -The user can deposit WETH into the ecosystem using the WETH bridge on L1. The destination chain ID has to be specified. -The Bridgehub unwraps the WETH, and keeps the ETH, and send a message to the destination L2 to mint WETH to the -specified address. - -![depositWeth.png](../../assets/images/deposit-weth.png) - ---- - -## Common Standards and Upgrades - -In this initial phase, Hyperchains have to follow some common standards, so that they can trust each other. This means -all chains start out with the same empty state, they have the same VM implementations and proof systems, asset contracts -can trust each on different chains, and the chains are upgraded together. We elaborate on the shared upgrade mechanism -here. - -### Upgrade mechanism - -Currently, there are three types of upgrades for zkEVM. Normal upgrades (used for new features) are initiated by the -Governor (a multisig) and are public for a certain timeframe before they can be applied. Shadow upgrades are similar to -normal upgrades, but the data is not known at the moment the upgrade is proposed, but only when executed (they can be -executed with the delay, or instantly if approved by the security council). Instant upgrades (used for security issues), -on the other hand happen quickly and need to be approved by the Security Council in addition to the Governor. For -hyperchains the difference is that upgrades now happen on multiple chains. This is only a problem for shadow upgrades - -in this case, the chains have to tightly coordinate to make all the upgrades happen in a short time frame, as the -content of the upgrade becomes public once the first chain is upgraded. The actual upgrade process is as follows: - -1. Prepare Upgrade for all chains: - - The new facets and upgrade contracts have to be deployed, - - The upgrade’ calldata (diamondCut, initCalldata with ProposedUpgrade) is hashed on L1 and the hash is saved. -2. Upgrade specific chain - - The upgrade has to be called on the specific chain. The upgrade calldata is passed in as calldata and verified. The - protocol version is updated. - - Ideally, the upgrade will be very similar for all chains. If it is not, a smart contract can calculate the - differences. If this is also not possible, we have to set the `diamondCut` for each chain by hand. -3. Freeze not upgraded chains - - After a certain time the chains that are not upgraded are frozen. diff --git a/content/40.zk-stack/components/smart-contracts/smart-contracts.md b/content/40.zk-stack/components/smart-contracts/smart-contracts.md deleted file mode 100644 index 66c5303a..00000000 --- a/content/40.zk-stack/components/smart-contracts/smart-contracts.md +++ /dev/null @@ -1,291 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Smart Contracts | zkSync Docs ---- - -# Smart Contracts - -Rollups inherit security and decentralization guarantees from Ethereum, on which they store information about changes in -their own state, providing validity proofs for state transition, implementing a communication mechanism, etc. In -practice, all this is achieved by Smart Contracts built on top of Ethereum. - -This document details the architecture of the L2 contracts on Ethereum (also called Layer 1 or L1). We also have -contracts that support the hyperchain ecosystem, we cover those in the [Shared Bridge](../shared-bridges.md) section. -The Shared Bridge relies on these individual contracts. - -## Diamond - -Technically, this L1 smart contract acts as a connector between Ethereum (L1) and a single L2. It checks the validity -proof and data availability, handles L2 <-> L1 communication, finalizes L2 state transition, and more. - -### DiamondProxy - -The main contract uses [EIP-2535](https://eips.ethereum.org/EIPS/eip-2535) diamond proxy pattern. It is an in-house -implementation that is inspired by the [mudgen reference implementation](https://github.com/mudgen/Diamond). It has no -external functions, only the fallback that delegates a call to one of the facets (target/implementation contract). So -even an upgrade system is a separate facet that can be replaced. - -One of the differences from the reference implementation is access freezability. Each of the facets has an associated -parameter that indicates if it is possible to freeze access to the facet. Privileged actors can freeze the **diamond** -(not a specific facet!) and all facets with the marker `isFreezable` should be inaccessible until the governor or admin -unfreezes the diamond. Note that it is a very dangerous thing since the diamond proxy can freeze the upgrade system and -then the diamond will be frozen forever. - -The diamond proxy pattern is very flexible and extendable. For now, it allows splitting implementation contracts by -their logical meaning, removes the limit of bytecode size per contract and implements security features such as -freezing. In the future, it can also be viewed as [EIP-6900](https://eips.ethereum.org/EIPS/eip-6900) for -[zkStack](https://blog.matter-labs.io/introducing-the-zk-stack-c24240c2532a), where each hyperchain can implement a -sub-set of allowed implementation contracts. - -### GettersFacet - -Separate facet, whose only function is providing `view` and `pure` methods. It also implements -[diamond loupe](https://eips.ethereum.org/EIPS/eip-2535#diamond-loupe) which makes managing facets easier. This contract -must never be frozen. - -### AdminFacet - -Controls changing the privileged addresses such as governor and validators or one of the system parameters (L2 -bootloader bytecode hash, verifier address, verifier parameters, etc), and it also manages the freezing/unfreezing and -execution of upgrades in the diamond proxy. - -The admin facet is controlled by two entities: - -- Governance - Separate smart contract that can perform critical changes to the system as protocol upgrades. This - contract controlled by two multisigs, one managed by Matter Labs team and another will be multisig with well-respected - contributors in the crypto space. Only together they can perform an instant upgrade, the Matter Labs team can only - schedule an upgrade with delay. -- Admin - Multisig smart contract managed by Matter Labs that can perform non-critical changes to the system such as - granting validator permissions. Note, that the Admin is the same multisig as the owner of the governance. - -### MailboxFacet - -The facet that handles L2 <-> L1 communication, an overview for which can be found in -[docs](../../../build/developer-reference/l1-l2-interop.md). - -The Mailbox performs three functions: - -- L1 <-> L2 communication. -- Bridging native Ether to the L2 (with the launch of the Shared Bridge this will be moved) -- Censorship resistance mechanism (in the research stage). - -L1 -> L2 communication is implemented as requesting an L2 transaction on L1 and executing it on L2. This means a user -can call the function on the L1 contract to save the data about the transaction in some queue. Later on, a validator can -process it on L2 and mark it as processed on the L1 priority queue. Currently, it is used for sending information from -L1 to L2 or implementing multi-layer protocols. - -_NOTE_: While user requests the transaction from L1, the initiated transaction on L2 will have such a `msg.sender`: - -```solidity - address sender = msg.sender; - if (sender != tx.origin) { - sender = AddressAliasHelper.applyL1ToL2Alias(msg.sender); - } -``` - -where - -```solidity -uint160 constant offset = uint160(0x1111000000000000000000000000000000001111); - -function applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) { - unchecked { - l2Address = address(uint160(l1Address) + offset); - } -} - -``` - -For most of the rollups the address aliasing needs to prevent cross-chain exploits that would otherwise be possible if -we simply reused the same L1 addresses as the L2 sender. In zkEVM address derivation rule is different from the -Ethereum, so cross-chain exploits are already impossible. However, the zkEVM may add full EVM support in the future, so -applying address aliasing leaves room for future EVM compatibility. - -The L1 -> L2 communication is also used for bridging ether. The user should include a `msg.value` when initiating a -transaction request on the L1 contract. Before executing a transaction on L2, the specified address will be credited -with the funds. To withdraw funds user should call `withdraw` function on the `L2EtherToken` system contracts. This will -burn the funds on L2, allowing the user to reclaim them through the `finalizeEthWithdrawal` function on the -`MailboxFacet`. - -More about L1->L2 operations can be found -[here](https://github.com/code-423n4/2023-10-zksync/blob/main/docs/Smart%20contract%20Section/Handling%20L1→L2%20ops%20on%20zkSync.md). - -L2 -> L1 communication, in contrast to L1 -> L2 communication, is based only on transferring the information, and not on -the transaction execution on L1. The full description of the mechanism for sending information from L2 to L1 can be -found -[here](https://github.com/code-423n4/2023-10-zksync/blob/main/docs/Smart%20contract%20Section/Handling%20pubdata%20in%20Boojum.md). - -### ExecutorFacet - -A contract that accepts L2 batches, enforces data availability and checks the validity of zk-proofs. - -The state transition is divided into three stages: - -- `commitBatches` - check L2 batch timestamp, process the L2 logs, save data for a batch, and prepare data for zk-proof. -- `proveBatches` - validate zk-proof. -- `executeBatches` - finalize the state, marking L1 -> L2 communication processing, and saving Merkle tree with L2 logs. - -Each L2 -> L1 system log will have a key that is part of the following: - -```solidity -enum SystemLogKey { - L2_TO_L1_LOGS_TREE_ROOT_KEY, - TOTAL_L2_TO_L1_PUBDATA_KEY, - STATE_DIFF_HASH_KEY, - PACKED_BATCH_AND_L2_BLOCK_TIMESTAMP_KEY, - PREV_BATCH_HASH_KEY, - CHAINED_PRIORITY_TXN_HASH_KEY, - NUMBER_OF_LAYER_1_TXS_KEY, - EXPECTED_SYSTEM_CONTRACT_UPGRADE_TX_HASH_KEY -} - -``` - -When a batch is committed, we process L2 -> L1 system logs. Here are the invariants that are expected there: - -- In a given batch there will be either 7 or 8 system logs. The 8th log is only required for a protocol upgrade. -- There will be a single log for each key that is contained within `SystemLogKey` -- Three logs from the `L2_TO_L1_MESSENGER` with keys: -- `L2_TO_L1_LOGS_TREE_ROOT_KEY` -- `TOTAL_L2_TO_L1_PUBDATA_KEY` -- `STATE_DIFF_HASH_KEY` -- Two logs from `L2_SYSTEM_CONTEXT_SYSTEM_CONTRACT_ADDR` with keys: - - `PACKED_BATCH_AND_L2_BLOCK_TIMESTAMP_KEY` - - `PREV_BATCH_HASH_KEY` -- Two or three logs from `L2_BOOTLOADER_ADDRESS` with keys: - - `CHAINED_PRIORITY_TXN_HASH_KEY` - - `NUMBER_OF_LAYER_1_TXS_KEY` - - `EXPECTED_SYSTEM_CONTRACT_UPGRADE_TX_HASH_KEY` -- None logs from other addresses (may be changed in the future). - -### DiamondInit - -It is a one-function contract that implements the logic of initializing a diamond proxy. It is called only once on the -diamond constructor and is not saved in the diamond as a facet. - -Implementation detail - function returns a magic value just like it is designed in -[EIP-1271](https://eips.ethereum.org/EIPS/eip-1271), but the magic value is 32 bytes in size. - -## Bridges - -Bridges are completely separate contracts from the Diamond. They are a wrapper for L1 <-> L2 communication on contracts -on both L1 and L2. Upon locking assets on L1, a request is sent to mint these bridged assets on L2. Upon burning assets -on L2, a request is sent to unlock them on L2. - -Unlike the native Ether bridging, all other assets can be bridged by the custom implementation relying on the trustless -L1 <-> L2 communication. - -### L1ERC20Bridge - -The "standard" implementation of the ERC20 token bridge. Works only with regular ERC20 tokens, i.e. not with -fee-on-transfer tokens or other custom logic for handling user balances. - -- `deposit` - lock funds inside the contract and send a request to mint bridged assets on L2. -- `claimFailedDeposit` - unlock funds if the deposit was initiated but then failed on L2. -- `finalizeWithdrawal` - unlock funds for the valid withdrawal request from L2. - -The owner of the L1ERC20Bridge is the Governance contract. - -### L2ERC20Bridge - -The L2 counterpart of the L1 ERC20 bridge. - -- `withdraw` - initiate a withdrawal by burning funds on the contract and sending a corresponding message to L1. -- `finalizeDeposit` - finalize the deposit and mint funds on L2. The function is only callable by L1 bridge. - -The owner of the L2ERC20Bridge and the contracts related to it is the Governance contract. - -### L1WethBridge - -The custom bridge exclusively handles transfers of WETH tokens between the two domains. It is designed to streamline and -enhance the user experience for bridging WETH tokens by minimizing the number of transactions required and reducing -liquidity fragmentation thus improving efficiency and user experience. - -This contract accepts WETH deposits on L1, unwraps them to ETH, and sends the ETH to the L2 WETH bridge contract, where -it is wrapped back into WETH and delivered to the L2 recipient. - -Thus, the deposit is made in one transaction, and the user receives L2 WETH that can be unwrapped to ETH. - -For withdrawals, the contract receives ETH from the L2 WETH bridge contract, wraps it into WETH, and sends the WETH to -the L1 recipient. - -The owner of the L1WethBridge contract is the Governance contract. - -### L2WethBridge - -The L2 counterpart of the L1 WETH bridge. - -The owner of the L2WethBridge and L2Weth contracts is the Governance contract. - -## Governance - -This contract manages calls for all governed zkEVM contracts on L1 and L2. Mostly, it is used for upgradability an -changing critical system parameters. The contract has minimum delay settings for the call execution. - -Each upgrade consists of two steps: - -- Scheduling - The owner can schedule upgrades in two different manners: - - Fully transparent data. All the targets, calldata, and upgrade conditions are known to the community before upgrade - execution. - - Shadow upgrade. The owner only shows the commitment to the upgrade. This upgrade type is mostly useful for fixing - critical issues in the production environment. -- Upgrade execution - the Owner or Security council can perform the upgrade with previously scheduled parameters. - - Upgrade with delay. Scheduled operations should elapse the delay period. Both the owner and Security Council can - execute this type of upgrade. - - Instant upgrade. Scheduled operations can be executed at any moment. Only the Security Council can perform this type - of upgrade. - -Please note, that both the Owner and Security council can cancel the upgrade before its execution. - -The diagram below outlines the complete journey from the initiation of an operation to its execution. - -## ValidatorTimelock - -An intermediate smart contract between the validator EOA account and the zkSync smart contract. Its primary purpose is -to provide a trustless means of delaying batch execution without modifying the main zkSync contract. zkSync actively -monitors the chain activity and reacts to any suspicious activity by freezing the chain. This allows time for -investigation and mitigation before resuming normal operations. - -It is a temporary solution to prevent any significant impact of the validator hot key leakage, while the network is in -the Alpha stage. - -This contract consists of four main functions `commitBatches`, `proveBatches`, `executeBatches`, and `revertBatches`, -which can be called only by the validator. - -When the validator calls `commitBatches`, the same calldata will be propagated to the zkSync contract (`DiamondProxy` -through `call` where it invokes the `ExecutorFacet` through `delegatecall`), and also a timestamp is assigned to these -batches to track the time these batches are committed by the validator to enforce a delay between committing and -execution of batches. Then, the validator can prove the already committed batches regardless of the mentioned timestamp, -and again the same calldata (related to the `proveBatches` function) will be propagated to the zkSync contract. After -the `delay` is elapsed, the validator is allowed to call `executeBatches` to propagate the same calldata to zkSync -contract. - -The owner of the ValidatorTimelock contract is the same as the owner of the Governance contract - Matter Labs multisig. - -## Allowlist - -The auxiliary contract controls the permission access list. It is used in bridges and diamond proxies to control which -addresses can interact with them in the Alpha release. Currently, it is supposed to set all permissions to public. - -The owner of the Allowlist contract is the Governance contract. - -## Deposit Limitation - -The amount of deposit can be limited. This limitation is applied on an account level and is not time-based. In other -words, each account cannot deposit more than the cap defined. The tokens and the cap can be set through governance -transactions. Moreover, there is an allow listing mechanism as well (only some allow listed accounts can call some -specific functions). So, the combination of deposit limitation and allow listing leads to limiting the deposit of the -allow listed account to be less than the defined cap. - -```solidity -struct Deposit { - bool depositLimitation; - uint256 depositCap; -} - -``` - -Currently, the limit is used only for blocking deposits of the specific token (turning on the limitation and setting the -limit to zero). And on the near future, this functionality will be completely removed. diff --git a/content/40.zk-stack/components/smart-contracts/system-contracts.md b/content/40.zk-stack/components/smart-contracts/system-contracts.md deleted file mode 100644 index 9ca52d5c..00000000 --- a/content/40.zk-stack/components/smart-contracts/system-contracts.md +++ /dev/null @@ -1,310 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: System Contracts | zkSync Docs ---- - -# System Contracts - -While most of the primitive EVM opcodes can be supported out of the box (i.e. zero-value calls, -addition/multiplication/memory/storage management, etc), some of the opcodes are not supported by the VM by default and -they are implemented via “system contracts” — these contracts are located in a special _kernel space,_ i.e. in the -address space in range `[0..2^16-1]`, and they have some special privileges, which users’ contracts don’t have. These -contracts are pre-deployed at the genesis and updating their code can be done only via system upgrade, managed from L1. - -The use of each system contract will be explained down below. - -Most of the details on the implementation and the requirements for the execution of system contracts can be found in the -doc-comments of their respective code bases. This chapter serves only as a high-level overview of such contracts. - -All the codes of system contracts (including `DefaultAccount`s) are part of the protocol and can only be change via a -system upgrade through L1. - -## SystemContext - -This contract is used to support various system parameters not included in the VM by default, i.e. `chainId`, `origin`, -`ergsPrice`, `blockErgsLimit`, `coinbase`, `difficulty`, `baseFee`, `blockhash`, `block.number`, `block.timestamp.` - -It is important to note that the constructor is **not** run for system contracts upon genesis, i.e. the constant context -values are set on genesis explicitly. Notably, if in the future we want to upgrade the contracts, we will do it via -`ContractDeployer` and so the constructor will be run. - -This contract is also responsible for ensuring validity and consistency of batches, L2 blocks and virtual blocks. The -implementation itself is rather straightforward, but to better understand this contract, please take a look at the -[page](https://github.com/code-423n4/2023-10-zksync/blob/main/docs/Smart%20contract%20Section/Batches%20&%20L2%20blocks%20on%20zkSync.md) -about the block processing on zkSync. - -## AccountCodeStorage - -The code hashes of accounts are stored inside the storage of this contract. Whenever a VM calls a contract with address -`address` it retrieves the value under storage slot `address` of this system contract, if this value is non-zero, it -uses this as the code hash of the account. - -Whenever a contract is called, the VM asks the operator to provide the preimage for the codehash of the account. That is -why data availability of the code hashes is paramount. - -### Constructing vs Non-Constructing Code Hash - -In order to prevent contracts from being able to call a contract during its construction, we set the marker (i.e. second -byte of the bytecode hash of the account) as `1`. This way, the VM will ensure that whenever a contract is called -without the `isConstructor` flag, the bytecode of the default account (i.e. EOA) will be substituted instead of the -original bytecode. - -## BootloaderUtilities - -This contract contains some of the methods which are needed purely for the bootloader functionality but were moved out -from the bootloader itself for the convenience of not writing this logic in Yul. - -## DefaultAccount - -Whenever a contract that does **not** both: - -- belong to kernel space -- have any code deployed on it (the value stored under the corresponding storage slot in `AccountCodeStorage` is zero) - -The code of the default account is used. The main purpose of this contract is to provide EOA-like experience for both -wallet users and contracts that call it, i.e. it should not be distinguishable (apart of spent gas) from EOA accounts on -Ethereum. - -## Ecrecover - -The implementation of the ecrecover precompile. It is expected to be used frequently, so written in pure yul with a -custom memory layout. - -The contract accepts the calldata in the same format as EVM precompile, i.e. the first 32 bytes are the hash, the next -32 bytes are the v, the next 32 bytes are the r, and the last 32 bytes are the s. - -It also validates the input by the same rules as the EVM precompile: - -- The v should be either 27 or 28, -- The r and s should be less than the curve order. - -After that, it makes a precompile call and returns empty bytes if the call failed, and the recovered address otherwise. - -## Empty contracts - -Some of the contracts are relied upon to have EOA-like behaviour, i.e. they can be always called and get the success -value in return. An example of such address is 0 address. We also require the bootloader to be callable so that the -users could transfer ETH to it. - -For these contracts, we insert the `EmptyContract` code upon genesis. It is basically a noop code, which does nothing -and returns `success=1`. - -## SHA256 & Keccak256 - -Note that, unlike Ethereum, keccak256 is a precompile (_not an opcode_) on zkSync. - -These system contracts act as wrappers for their respective crypto precompile implementations. They are expected to be -used frequently, especially keccak256, since Solidity computes storage slots for mapping and dynamic arrays with its -help. That's why we wrote contracts on pure yul with optimizing the short input case. - -The system contracts accept the input and transform it into the format that the zk-circuit expects. This way, some of -the work is shifted from the crypto to smart contracts, which are easier to audit and maintain. - -Both contracts should apply padding to the input according to their respective specifications, and then make a -precompile call with the padded data. All other hashing work will be done in the zk-circuit. It's important to note that -the crypto part of the precompiles expects to work with padded data. This means that a bug in applying padding may lead -to an unprovable transaction. - -## L2EthToken & MsgValueSimulator - -Unlike Ethereum, zkEVM does not have any notion of any special native token. That’s why we have to simulate operations -with Ether via two contracts: `L2EthToken` & `MsgValueSimulator`. - -`L2EthToken` is a contract that holds the balances of ETH for the users. This contract does NOT provide ERC20 interface. -The only method for transferring Ether is `transferFromTo`. It permits only some system contracts to transfer on behalf -of users. This is needed to ensure that the interface is as close to Ethereum as possible, i.e. the only way to transfer -ETH is by doing a call to a contract with some `msg.value`. This is what `MsgValueSimulator` system contract is for. - -Whenever anyone wants to do a non-zero value call, they need to call `MsgValueSimulator` with: - -- The calldata for the call equal to the original one. -- Pass `value` and whether the call should be marked with `isSystem` in the first extra abi params. -- Pass the address of the callee in the second extraAbiParam. - -## KnownCodeStorage - -This contract is used to store whether a certain code hash is “known”, i.e. can be used to deploy contracts. On zkSync, -the L2 stores the contract’s code _hashes_ and not the codes themselves. Therefore, it must be part of the protocol to -ensure that no contract with unknown bytecode (i.e. hash with an unknown preimage) is ever deployed. - -The factory dependencies field provided by the user for each transaction contains the list of the contract’s bytecode -hashes to be marked as known. We can not simply trust the operator to “know” these bytecodehashes as the operator might -be malicious and hide the preimage. We ensure the availability of the bytecode in the following way: - -- If the transaction comes from L1, i.e. all its factory dependencies have already been published on L1, we can simply - mark these dependencies as “known”. -- If the transaction comes from L2, i.e. (the factory dependencies are yet to publish on L1), we make the user pays by - burning ergs proportional to the bytecode’s length. After that, we send the L2→L1 log with the bytecode hash of the - contract. It is the responsibility of the L1 contracts to verify that the corresponding bytecode hash has been - published on L1. - -It is the responsibility of the `ContractDeployer` system contract to deploy only those code hashes that are known. - -The KnownCodesStorage contract is also responsible for ensuring that all the “known” bytecode hashes are also valid. - -## ContractDeployer & ImmutableSimulator - -`ContractDeployer` is a system contract responsible for deploying contracts on zkSync. It is better to understand how it -works in the context of how the contract deployment works on zkSync. Unlike Ethereum, where `create`/`create2` are -opcodes, on zkSync these are implemented by the compiler via calls to the ContractDeployer system contract. - -For additional security, we also distinguish the deployment of normal contracts and accounts. That’s why the main -methods that will be used by the user are `create`, `create2`, `createAccount`, `create2Account`, which simulate the -CREATE-like and CREATE2-like behavior for deploying normal and account contracts respectively. - -### **Address derivation** - -Each rollup that supports L1→L2 communications needs to make sure that the addresses of contracts on L1 and L2 do not -overlap during such communication (otherwise it would be possible that some evil proxy on L1 could mutate the state of -the L2 contract). Generally, rollups solve this issue in two ways: - -- XOR/ADD some kind of constant to addresses during L1→L2 communication. That’s how rollups closer to full - EVM-equivalence solve it, since it allows them to maintain the same derivation rules on L1 at the expense of contract - accounts on L1 having to redeploy on L2. -- Have different derivation rules from Ethereum. That is the path that zkSync has chosen, mainly because since we have - different bytecode than on EVM, CREATE2 address derivation would be different in practice anyway. - -You can see the rules for our address derivation in `getNewAddressCreate2`/ `getNewAddressCreate` methods in the -ContractDeployer. - -Note, that we still add a certain constant to the addresses during L1→L2 communication in order to allow ourselves some -way to support EVM bytecodes in the future. - -### **Deployment nonce** - -On Ethereum, the same nonce is used for CREATE for accounts and EOA wallets. On zkSync this is not the case, we use a -separate nonce called “deploymentNonce” to track the nonces for accounts. This was done mostly for consistency with -custom accounts and for having multicalls feature in the future. - -### **General process of deployment** - -- After incrementing the deployment nonce, the contract deployer must ensure that the bytecode that is being deployed is - available. -- After that, it puts the bytecode hash with a - [special constructing marker](#constructing-vs-non-constructing-code-hash) as code for the address of the - to-be-deployed contract. -- Then, if there is any value passed with the call, the contract deployer passes it to the deployed account and sets the - `msg.value` for the next as equal to this value. -- Then, it uses `mimic_call` for calling the constructor of the contract out of the name of the account. -- It parses the array of immutables returned by the constructor (we’ll talk about immutables in more details later). -- Calls `ImmutableSimulator` to set the immutables that are to be used for the deployed contract. - -Note how it is different from the EVM approach: on EVM when the contract is deployed, it executes the initCode and -returns the deployedCode. On zkSync, contracts only have the deployed code and can set immutables as storage variables -returned by the constructor. - -### **Constructor** - -On Ethereum, the constructor is only part of the initCode that gets executed during the deployment of the contract and -returns the deployment code of the contract. On zkSync, there is no separation between deployed code and constructor -code. The constructor is always a part of the deployment code of the contract. In order to protect it from being called, -the compiler-generated contracts invoke constructor only if the `isConstructor` flag provided (it is only available for -the system contracts). - -After execution, the constructor must return an array of: - -```solidity -struct ImmutableData { - uint256 index; - bytes32 value; -} - -``` - -basically denoting an array of immutables passed to the contract. - -### **Immutables** - -Immutables are stored in the `ImmutableSimulator` system contract. The way how `index` of each immutable is defined is -part of the compiler specification. This contract treats it simply as mapping from index to value for each particular -address. - -Whenever a contract needs to access a value of some immutable, they call the -`ImmutableSimulator.getImmutable(getCodeAddress(), index)`. Note that on zkSync it is possible to get the current -execution address. - -### **Return value of the deployment methods** - -If the call succeeded, the address of the deployed contract is returned. If the deploy fails, the error bubbles up. - -## DefaultAccount - -The implementation of the default account abstraction. This is the code that is used by default for all addresses that -are not in kernel space and have no contract deployed on them. This address: - -- Contains minimal implementation of our account abstraction protocol. Note that it supports the - [built-in paymaster flows](https://v2-docs.zksync.io/dev/developer-guides/aa.html#paymasters). -- When anyone (except bootloader) calls it, it behaves in the same way as a call to an EOA, i.e. it always returns - `success = 1, returndatasize = 0` for calls from anyone except for the bootloader. - -## L1Messenger - -A contract used for sending arbitrary length L2→L1 messages from zkSync to L1. While zkSync natively supports a rather -limited number of L1→L2 logs, which can transfer only roughly 64 bytes of data a time, we allowed sending -nearly-arbitrary length L2→L1 messages with the following trick: - -The L1 messenger receives a message, hashes it and sends only its hash as well as the original sender via L2→L1 log. -Then, it is the duty of the L1 smart contracts to make sure that the operator has provided full preimage of this hash in -the commitment of the batch. - -The `L1Messenger` is also responsible for validating the total pubdata to be sent on L1. You can read more about it -[here](https://github.com/code-423n4/2023-10-zksync/blob/main/docs/Smart%20contract%20Section/Handling%20pubdata%20in%20Boojum.md). - -## NonceHolder - -Serves as storage for nonces for our accounts. Besides making it easier for operator to order transactions (i.e. by -reading the current nonces of account), it also serves a separate purpose: making sure that the pair (address, nonce) is -always unique. - -It provides a function `validateNonceUsage` which the bootloader uses to check whether the nonce has been used for a -certain account or not. Bootloader enforces that the nonce is marked as non-used before validation step of the -transaction and marked as used one afterwards. The contract ensures that once marked as used, the nonce can not be set -back to the “unused” state. - -Note that nonces do not necessarily have to be monotonic (this is needed to support more interesting applications of -account abstractions, e.g. protocols that can start transactions on their own, tornado-cash like protocols, etc). That’s -why there are two ways to set a certain nonce as “used”: - -- By incrementing the `minNonce` for the account (thus making all nonces that are lower than `minNonce` as used). -- By setting some non-zero value under the nonce via `setValueUnderNonce`. This way, this key will be marked as used and - will no longer be allowed to be used as nonce for accounts. This way it is also rather efficient, since these 32 bytes - could be used to store some valuable information. - -The accounts upon creation can also provide which type of nonce ordering do they want: Sequential (i.e. it should be -expected that the nonces grow one by one, just like EOA) or Arbitrary, the nonces may have any values. This ordering is -not enforced in any way by system contracts, but it is more of a suggestion to the operator on how it should order the -transactions in the mempool. - -## EventWriter - -A system contract responsible for emitting events. - -It accepts in its 0-th extra abi data param the number of topics. In the rest of the extraAbiParams he accepts topics -for the event to emit. Note, that in reality the event the first topic of the event contains the address of the account. -Generally, the users should not interact with this contract directly, but only through Solidity syntax of `emit`-ing new -events. - -## Compressor - -One of the most expensive resource for a rollup is data availability, so in order to reduce costs for the users we -compress the published pubdata in several ways: - -- We compress published bytecodes. -- We compress state diffs. - -This contract contains utility methods that are used to verify the correctness of either bytecode or state diff -compression. You can read more on how we compress state diffs and bytecodes in the corresponding -[document](https://github.com/code-423n4/2023-10-zksync/blob/main/docs/Smart%20contract%20Section/Handling%20L1%E2%86%92L2%20ops%20on%20zkSync.md). - -## Known issues to be resolved - -The protocol, while conceptually complete, contains some known issues which will be resolved in the short to middle -term. - -- Fee modeling is yet to be improved. More on it in the - [document](https://github.com/code-423n4/2023-10-zksync/blob/main/docs/Smart%20contract%20Section/zkSync%20fee%20model.md) - on the fee model. -- We may add some kind of default implementation for the contracts in the kernel space (i.e. if called, they wouldn’t - revert but behave like an EOA). diff --git a/content/40.zk-stack/components/zkEVM/bootloader.md b/content/40.zk-stack/components/zkEVM/bootloader.md deleted file mode 100644 index a0e00704..00000000 --- a/content/40.zk-stack/components/zkEVM/bootloader.md +++ /dev/null @@ -1,348 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Bootloader | zkSync Docs ---- - -# Bootloader - -On standard Ethereum clients, the workflow for executing blocks is the following: - -1. Pick a transaction, validate the transactions & charge the fee, execute it -2. Gather the state changes (if the transaction has not reverted), apply them to the state. -3. Go back to step (1) if the block gas limit has not been yet exceeded. - -However, having such flow on zkSync (i.e. processing transaction one-by-one) would be too inefficient, since we have to -run the entire proving workflow for each individual transaction. That’s why we need the _bootloader_: instead of running -N transactions separately, we run the entire batch (set of blocks, more can be found -[here](https://github.com/code-423n4/2023-10-zksync/blob/main/docs/Smart%20contract%20Section/Batches%20%26%20L2%20blocks%20on%20zkSync.md)) -as a single program that accepts the array of transactions as well as some other batch metadata and processes them -inside a single big “transaction”. The easiest way to think about bootloader is to think in terms of EntryPoint from -EIP4337: it also accepts the array of transactions and facilitates the Account Abstraction protocol. - -The hash of the code of the bootloader is stored on L1 and can only be changed as a part of a system upgrade. Note, that -unlike system contracts, the bootloader’s code is not stored anywhere on L2. That’s why we may sometimes refer to the -bootloader’s address as formal. It only exists for the sake of providing some value to `this` / `msg.sender`/etc. When -someone calls the bootloader address (e.g. to pay fees) the EmptyContract’s code is actually invoked. - -Bootloader is the program that accepts an array of transactions and executes the entire zkSync batch. This section will -expand on its invariants and methods. - -## Playground vs Proved Bootloader - -For convenience, we use the same implementation of the bootloader both in the mainnet batches and for emulating ethCalls -or other testing activities. Only _proved_ bootloader is ever used for batch-building and thus this document only -describes it. - -## Batch Start - -The state of the bootloader is equivalent to the state of a contract transaction with empty calldata. The only -difference is that it starts with all the possible memory pre-allocated (to avoid costs for memory expansion). - -For additional efficiency, the bootloader receives its parameters inside its memory. This is the only point of -non-determinism: the bootloader _starts with its memory pre-filled with any data the operator wants_. That’s why the -operator is responsible for validating the correctness of the bootloader. The operator should never rely on the initial -contents of the memory to be correct & valid. - -For instance, for each transaction, we check that it is -[properly ABI-encoded](https://github.com/code-423n4/2023-10-zksync/blob/ef99273a8fdb19f5912ca38ba46d6bd02071363d/code/system-contracts/bootloader/bootloader.yul#L3058) -and that the transactions -[go exactly one after another](https://github.com/code-423n4/2023-10-zksync/blob/ef99273a8fdb19f5912ca38ba46d6bd02071363d/code/system-contracts/bootloader/bootloader.yul#L3736). -We also ensure that transactions do not exceed the limits of the memory space allowed for transactions. - -## Transaction Types and Validation - -While the main transaction format is the internal []`Transaction` -format](<https://github.com/code-423n4/2023-10-zksync/blob/ef99273a8fdb19f5912ca38ba46d6bd02071363d/code/system-contracts/contracts/libraries/TransactionHelper.sol#L25>), -it is a struct that is used to represent various kinds of transactions types. It contains a lot of `reserved` fields -that could be used depending in the future types of transactions without need for AA to change the interfaces of their -contracts. - -The exact type of the transaction is marked by the `txType` field of the transaction type. There are 6 types currently -supported: - -- `txType`: 0. It means that this transaction is of legacy transaction type. The following restrictions are enforced: -- `maxFeePerErgs=getMaxPriorityFeePerErg` since it is pre-EIP-1559 tx type. -- `reserved1..reserved4` as well as `paymaster` are 0. `paymasterInput` is zero. -- Note, that unlike type 1 and type 2 transactions, `reserved0` field can be set to a non-zero value, denoting that this - legacy transaction is EIP-155-compatible and its RLP encoding (as well as signature) should contain the `chainId` of - the system. -- `txType`: 1. It means that the transaction is of type 1, i.e. transactions access list. zkSync does not support access - lists in any way, so no benefits of fulfilling this list will be provided. The access list is assumed to be empty. The - same restrictions as for type 0 are enforced, but also `reserved0` must be 0. -- `txType`: 2. It is EIP1559 transactions. The same restrictions as for type 1 apply, but now `maxFeePerErgs` may not be - equal to `getMaxPriorityFeePerErg`. -- `txType`: 113. It is zkSync transaction type. This transaction type is intended for AA support. The only restriction - that applies to this transaction type: fields `reserved0..reserved4` must be equal to 0. -- `txType`: 254. It is a transaction type that is used for upgrading the L2 system. This is the only type of transaction - is allowed to start a transaction out of the name of the contracts in kernel space. -- `txType`: 255. It is a transaction that comes from L1. There are almost no restrictions explicitly imposed upon this - type of transaction, since the bootloader at the end of its execution sends the rolling hash of the executed priority - transactions. The L1 contract ensures that the hash did indeed match the - [hashes of the priority transactions on L1](https://github.com/code-423n4/2023-10-zksync/blob/ef99273a8fdb19f5912ca38ba46d6bd02071363d/code/contracts/ethereum/contracts/zksync/facets/Executor.sol#L282). - -You can also read more on L1->L2 transactions and upgrade transactions -[here](https://github.com/code-423n4/2023-10-zksync/blob/main/docs/Smart%20contract%20Section/Handling%20L1%E2%86%92L2%20ops%20on%20zkSync.md). - -However, as already stated, the bootloader’s memory is not deterministic and the operator is free to put anything it -wants there. For all of the transaction types above the restrictions are imposed in the following -([method](https://github.com/code-423n4/2023-10-zksync/blob/ef99273a8fdb19f5912ca38ba46d6bd02071363d/code/system-contracts/bootloader/bootloader.yul#L2828)), -which is called before starting processing the transaction. - -## Bootloader Memory Structure - -The bootloader expects the following structure of the memory (here by word we denote 32-bytes, the same machine word as -on EVM): - -### Batch Information - -The first 8 words are reserved for the batch information provided by the operator. - -- `0` — The address of the operator (the beneficiary of the transactions). -- `1` — The hash of the previous batch. Its validation will be explained later on. -- `2` — The timestamp of the current batch. Its validation will be explained later on. -- `3` — The number of the new batch. -- `4` — The L1 gas price provided by the operator. -- `5` — The “fair” price for L2 gas, i.e. the price below which the `baseFee` of the batch should not fall. For now, it - is provided by the operator, but it in the future it may become hardcoded. -- `6` — The base fee for the batch that is expected by the operator. While the base fee is deterministic, it is still - provided to the bootloader just to make sure that the data that the operator has coincides with the data provided by - the bootloader. -- `7` — Reserved word. Unused on proved batch. - -The batch information slots -[are used at the beginning of the batch](https://github.com/code-423n4/2023-10-zksync/blob/ef99273a8fdb19f5912ca38ba46d6bd02071363d/code/system-contracts/bootloader/bootloader.yul#L3629). -Once read, these slots can be used for temporary data. - -### Temporary Data Descriptions - -(This temporary data are used for debug and transaction processing purposes.) - -- `[8..39]` – reserved slots for debugging purposes -- `[40..72]` – slots for holding the paymaster context data for the current transaction. The role of the paymaster - context is similar to the [EIP4337](https://eips.ethereum.org/EIPS/eip-4337)’s one. You can read more about it in the - account abstraction documentation. -- `[73..74]` – slots for signed and explorer transaction hash of the currently processed L2 transaction. -- `[75..110]` – 36 slots for the calldata for the KnownCodesContract call. -- `[111..1134]` – 1024 slots for the refunds for the transactions. -- `[1135..2158]` – 1024 slots for the overhead for batch for the transactions. This overhead is suggested by the - operator, i.e. the bootloader will still double-check that the operator does not overcharge the user. -- `[2159..3182]` – slots for the “trusted” gas limits by the operator. The user’s transaction will have at its disposal - `min(MAX_TX_GAS(), trustedGasLimit)`, where `MAX_TX_GAS` is a constant guaranteed by the system. Currently, it is - equal to 80 million gas. In the future, this feature will be removed. -- `[3183..7282]` – slots for storing L2 block info for each transaction. You can read more on the difference L2 blocks - and batches - [here](https://github.com/code-423n4/2023-10-zksync/blob/main/docs/Smart%20contract%20Section/Batches%20&%20L2%20blocks%20on%20zkSync.md). -- `[7283..40050]` – slots used for compressed bytecodes each in the following format: - - 32 bytecode hash - - 32 zeroes (but then it will be modified by the bootloader to contain 28 zeroes and then the 4-byte selector of the - `publishCompressedBytecode` function of the `BytecodeCompressor`) - - The calldata to the bytecode compressor (without the selector). -- `[40051..40052]` – slots where the hash and the number of current priority ops is stored. More on it in the priority - operations - [section](https://github.com/code-423n4/2023-10-zksync/blob/main/docs/Smart%20contract%20Section/Handling%20L1%E2%86%92L2%20ops%20on%20zkSync.md). - -### L1Messenger Pubdata - -- `[40053..248052]` – slots where the final batch pubdata is supplied to be verified by the L1Messenger. More on how the - L1Messenger system contracts handles the pubdata can be read - [here](https://github.com/code-423n4/2023-10-zksync/blob/main/docs/Smart%20contract%20Section/Handling%20pubdata%20in%20Boojum.md). - -This `[40053..248052]` space is used for the calldata to the L1Messenger’s `publishPubdataAndClearState` function, which -accepts: - -- List of the user L2→L1 logs, -- Published L2→L1 messages -- Bytecodes -- List of full state diff entries, which describe how each storage slot has changed as well as compressed state diffs. - -This method will then check the correctness of the provided data and publish the hash of the correct pubdata to L1. - -Note, that while the realistic number of pubdata that can be published in a batch is 120kb, the size of the calldata to -L1Messenger may be significantly larger due to the fact that this method also accepts the original, uncompressed state -diff entries. - -These will not be published to L1, but will be used to verify the correctness of the compression. In a worst-case -scenario, the number of bytes that may be needed for this scratch space is if all the pubdata consists of repeated -writes (i.e. we’ll need only 4 bytes to include key) that turn into 0 (i.e. they’ll need only 1 byte to describe it). - -However, each of these writes in the uncompressed form will be represented as 272 byte state diff entry and so we get -the number of diffs is `120k / 5 = 24k`. This means that they will have accoomdate `24k * 272 = 6528000` bytes of -calldata for the uncompressed state diffs. Adding 120k on top leaves us with roughly `6650000` bytes needed for -calldata. `207813` slots are needed to accommodate this amount of data. We round up to `208000` slots to give space for -constant-size factors for ABI-encoding, like offsets, lengths, etc. - -In theory, much more calldata could be used. For instance, if one byte is used for `enum`` index. It is the -responsibility of the operator to ensure that it can form the correct calldata for the L1Messenger. - -### Transaction Slot Descriptions - -- `[248053..250100]` words — 2048 slots for 1024 transaction’s meta descriptions (their structure is explained below). - -For internal reasons related to possible future integrations of zero-knowledge proofs about some of the contents of the -bootloader’s memory, the array of the transactions is not passed as the ABI-encoding of the array of transactions, but: - -- We have a constant maximum number of transactions. At the time of this writing, this number is 1024. -- Then, we have 1024 transaction descriptions, each ABI encoded as the following struct: - -```solidity -struct BootloaderTxDescription { - // The offset by which the ABI-encoded transaction's data is stored - uint256 txDataOffset; - // Auxiliary data on the transaction's execution. In our internal versions - // of the bootloader it may have some special meaning, but for the - // bootloader used on the mainnet it has only one meaning: whether to execute - // the transaction. If 0, no more transactions should be executed. If 1, then - // we should execute this transaction and possibly try to execute the next one. - uint256 txExecutionMeta; -} - -``` - -### **Reserved slots for the calldata for the paymaster’s postOp operation** - -- `[252149..252188]` words — 40 slots which could be used for encoding the calls for postOp methods of the paymaster. - -To avoid additional copying of transactions for calls for the account abstraction, we reserve some of the slots which -could be then used to form the calldata for the `postOp` call for the account abstraction without having to copy the -entire transaction’s data. - -### **The actual transaction’s descriptions** - -- `[252189..523261]` - -Starting from the 487312 word, the actual descriptions of the transactions start. (The struct can be found by this -[link](https://github.com/code-423n4/2023-10-zksync/blob/ef99273a8fdb19f5912ca38ba46d6bd02071363d/code/system-contracts/contracts/libraries/TransactionHelper.sol#L25)). -The bootloader enforces that: - -- They are correctly ABI encoded representations of the struct above. -- They are located without any gaps in memory (the first transaction starts at word 653 and each transaction goes right - after the next one). -- The contents of the currently processed transaction (and the ones that will be processed later on are untouched). - Note, that we do allow overriding data from the already processed transactions as it helps to preserve efficiency by - not having to copy the contents of the `Transaction` each time we need to encode a call to the account. - -### **VM Hook Pointers** - -- `[523261..523263]` - -These are memory slots that are used purely for debugging purposes (when the VM writes to these slots, the server side -can catch these calls and give important insight information for debugging issues). - -### **Result Pointer** - -- [523264..524287] - -These are memory slots that are used to track the success status of a transaction. If the transaction with number `i` -succeeded, the slot `2^19 - 1024 + i` will be marked as 1 and 0 otherwise. - -## Bootloader Execution Flow - -1. At the start of the batch it - [reads the initial batch information](https://github.com/code-423n4/2023-10-zksync/blob/ef99273a8fdb19f5912ca38ba46d6bd02071363d/code/system-contracts/bootloader/bootloader.yul#L3629) - and - [sends the information](https://github.com/code-423n4/2023-10-zksync/blob/ef99273a8fdb19f5912ca38ba46d6bd02071363d/code/system-contracts/bootloader/bootloader.yul#L3674) - about the current batch to the `SystemContext` system contract. -2. It goes through each of - [transaction’s descriptions](https://github.com/code-423n4/2023-10-zksync/blob/ef99273a8fdb19f5912ca38ba46d6bd02071363d/code/system-contracts/bootloader/bootloader.yul#L3715) - and checks whether the `execute` field is set. If not, it ends processing of the transactions and ends execution of - the batch. If the execute field is non-zero, the transaction will be executed and it goes to step 3. -3. Based on the transaction’s type it decides whether the transaction is an L1 or L2 transaction and processes them - accordingly. More on the processing of the L1 transactions can be read [here](#l1-l2-transactions). More on L2 - transactions can be read [here](#l2-transactions). - -## L2 Transactions - -On zkSync, every address is a contract. Users can start transactions from their EOA accounts, because every address that -does not have any contract deployed on it implicitly contains the code defined in the -[DefaultAccount.sol](https://github.com/code-423n4/2023-10-zksync/blob/main/code/system-contracts/contracts/DefaultAccount.sol) -file. Whenever anyone calls a contract that is not in kernel space (i.e. the address is ≥ 2^16) and does not have any -contract code deployed on it, the code for `DefaultAccount` will be used as the contract’s code. - -Note, that if you call an account that is in kernel space and does not have any code deployed there, right now, the -transaction will revert. - -We process the L2 transactions according to our account abstraction protocol: -[https://v2-docs.zksync.io/dev/tutorials/custom-aa-tutorial.html#prerequisite](https://v2-docs.zksync.io/dev/tutorials/custom-aa-tutorial.html#prerequisite). - -1. We - [deduct](https://github.com/code-423n4/2023-10-zksync/blob/ef99273a8fdb19f5912ca38ba46d6bd02071363d/code/system-contracts/bootloader/bootloader.yul#L1073) - the transaction’s upfront payment for the overhead for the block’s processing. You can read more on how that works in - the fee model - [description](https://github.com/code-423n4/2023-10-zksync/blob/main/docs/Smart%20contract%20Section/zkSync%20fee%20model.md). -2. Then we calculate the gasPrice for these transactions according to the EIP1559 rules. -3. We - [conduct the validation step](https://github.com/code-423n4/2023-10-zksync/blob/ef99273a8fdb19f5912ca38ba46d6bd02071363d/code/system-contracts/bootloader/bootloader.yul#L1180) - of the AA protocol: - -- We calculate the hash of the transaction. -- If enough gas has been provided, we near_call the validation function in the bootloader. It sets the tx.origin to the - address of the bootloader, sets the ergsPrice. It also marks the factory dependencies provided by the transaction as - marked and then invokes the validation method of the account and verifies the returned magic. -- Calls the accounts and, if needed, the paymaster to receive the payment for the transaction. Note, that accounts may - not use `block.baseFee` context variable, so they have no way to know what exact sum to pay. That’s why the accounts - typically firstly send `tx.maxFeePerErg * tx.ergsLimit` and the bootloader - [refunds](https://github.com/code-423n4/2023-10-zksync/blob/ef99273a8fdb19f5912ca38ba46d6bd02071363d/code/system-contracts/bootloader/bootloader.yul#L730) - for any excess funds sent. - -1. [We perform the execution of the transaction](https://github.com/code-423n4/2023-10-zksync/blob/ef99273a8fdb19f5912ca38ba46d6bd02071363d/code/system-contracts/bootloader/bootloader.yul#L1234). - Note, that if the sender is an EOA, tx.origin is set equal to the `from` the value of the transaction. During the - execution of the transaction, the publishing of the compressed bytecodes happens: for each factory dependency if it - has not been published yet and its hash is currently pointed to in the compressed bytecodes area of the bootloader, a - call to the bytecode compressor is done. Also, at the end the call to the KnownCodeStorage is done to ensure all the - bytecodes have indeed been published. -2. We - [refund](https://github.com/code-423n4/2023-10-zksync/blob/ef99273a8fdb19f5912ca38ba46d6bd02071363d/code/system-contracts/bootloader/bootloader.yul#L1401) - the user for any excess funds he spent on the transaction. The process is as follows: - -3. The `postTransaction` operation is called to the `paymaster`. -4. The Bootloader asks the operator to provide a refund. During the first VM run—without proofs—the operator directly - inserts the refunds in the memory of the bootloader. During the run for the proved batches, the operator already - knows which values have to be inserted. You can read more about the - [fee model here](https://github.com/code-423n4/2023-10-zksync/blob/main/docs/Smart%20contract%20Section/zkSync%20fee%20model.md) -5. The Bootloader refunds the user. -6. We notify the operator about the - [refund that was granted to the user.](https://github.com/code-423n4/2023-10-zksync/blob/ef99273a8fdb19f5912ca38ba46d6bd02071363d/code/system-contracts/bootloader/bootloader.yul#L1112). - It will be used to correctly display the gas used for the transaction in the block explorer. - -## L1->L2 Transactions - -L1->L2 transactions are transactions that were initiated on L1. We assume that `from` has already authorized the L1→L2 -transactions. It also has its L1 pubdata price as well as ergsPrice set on L1. - -Most of the steps from the execution of L2 transactions are omitted and we set `tx.origin` to the `from`, and -`ergsPrice` to the one provided by transaction. After that, we use -[mimicCall](https://matter-labs.github.io/eravm-spec/spec.html#FarCalls) to provide the operation itself from the name -of the sender account. - -Note, that for L1→L2 transactions, `reserved0` field denotes the amount of ETH that should be minted on L2 as a result -of this transaction. `reserved1` is the refund receiver address, i.e. the address that would receive the refund for the -transaction as well as the msg.value if the transaction fails. - -There are two kinds of L1->L2 transactions: - -1. Priority operations, initiated by users (they have type `255`). -2. Upgrade transactions, that can be initiated during system upgrade (they have type `254`). - -[You can read more about differences between the different L1->L2 transaction types here.](https://github.com/code-423n4/2023-10-zksync/blob/main/docs/Smart%20contract%20Section/Handling%20L1%E2%86%92L2%20ops%20on%20zkSync.md) - -## End of the Batch - -At the end of the batch we set `tx.origin` and `tx.gasprice` context variables to zero to both save L1 gas on `calldata` -and to send the entire Bootloader balance to the operator. This effectively sends all the fees collected by the -Bootloader to the operator. - -Also, we -[set](https://github.com/code-423n4/2023-10-zksync/blob/ef99273a8fdb19f5912ca38ba46d6bd02071363d/code/system-contracts/bootloader/bootloader.yul#L3812) -the fictive L2 block’s data. Then, we call the system context to ensure that it publishes the timestamp of the L2 block -as well as L1 batch. We also reset the `txNumberInBlock` counter to avoid its state diffs from being published on L1. -You can read more about block processing on zkSync -[here](https://github.com/code-423n4/2023-10-zksync/blob/main/docs/Smart%20contract%20Section/Batches%20&%20L2%20blocks%20on%20zkSync.md). - -After that, we publish the hash as well as the number of priority operations in this batch. More on it -[here](https://github.com/code-423n4/2023-10-zksync/blob/main/docs/Smart%20contract%20Section/Handling%20L1%E2%86%92L2%20ops%20on%20zkSync.md). - -Then, we call the L1Messenger system contract for it to compose the pubdata to be published on L1. You can read more -about the pubdata processing -[here](https://github.com/code-423n4/2023-10-zksync/blob/main/docs/Smart%20contract%20Section/Handling%20pubdata%20in%20Boojum.md). diff --git a/content/40.zk-stack/components/zkEVM/overview.md b/content/40.zk-stack/components/zkEVM/overview.md deleted file mode 100644 index febfd0a1..00000000 --- a/content/40.zk-stack/components/zkEVM/overview.md +++ /dev/null @@ -1,34 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: zkEVM | zkSync Docs ---- - -# zkEVM - -The zkEVM is used to execute transactions. It is similar in construction to the EVM, so it executes transactions -similarly, but it plays a fundamentally different role in the zkStack than the EVM does in Ethereum. The EVM is used to -execute smart contracts in Ethereum's state transition function. This STF needs a client to implement and run it. - -Rollups have a different set of requirements, they need to produce a proof that some client executed the STF correctly. -This client is the **zkEVM,** it is made to run the STF efficiently. The STF is the [Bootloader](./bootloader.md). - -The smart contracts are native zkEVM bytecode, zkEVM can execute these easily. In the future the ZK Stack will also -support EVM bytecode by running an efficient interpreter inside the zkEVM. - -The zkEVM has a lot of special features compared to the EVM that are needed for the rollup's STF, storage, gas metering, -precompiles etc. These functions are either built into the zkEVM, or there are special -[system contracts](../../components/smart-contracts/system-contracts.md) for them. The system contracts are deployed at -predefined addresses, they are called by the Bootloader, and they have special permissions compared to normal user -contracts. These are not to be confused with the precompiles, which are also predeloyed contracts with special support -from the zkEVM, but these contract do not have special permissions and are called by the users and not the Bootloader. - -The zkEVM also has user-facing features. For the best possible UX the ZK Stack supports native -[account abstraction](../../concepts/account-abstraction.md). This means users can fully customize how they pay the fees -needed to execute their transactions. - -All transactions need to pay fees. The requirements to run a rollup are different than the ones needed to run Ethereum, -so the ZK Stack has a different [fee model](../../concepts/fee-mechanism.md). The fee model is designed to consider all -the components that are needed to run the rollup: data and proof execution costs on L1, sequencer costs, and prover -costs. diff --git a/content/40.zk-stack/components/zkEVM/precompiles.md b/content/40.zk-stack/components/zkEVM/precompiles.md deleted file mode 100644 index ab0ffca5..00000000 --- a/content/40.zk-stack/components/zkEVM/precompiles.md +++ /dev/null @@ -1,183 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Precompiles | zkSync Docs ---- - -# Precompiles - -Precompiled contracts for elliptic curve operations are required in order to perform zkSNARK verification. - -The operations that you need to be able to perform are elliptic curve point addition, elliptic curve point scalar -multiplication, and elliptic curve pairing. - -This document explains the precompiles responsible for elliptic curve point addition and scalar multiplication and the -design decisions. You can read the specification [here](https://eips.ethereum.org/EIPS/eip-196). - -## Introduction - -On top of having a set of opcodes to choose from, the EVM also offers a set of more advanced functionalities through -precompiled contracts. These are a special kind of contracts that are bundled with the EVM at fixed addresses and can be -called with a determined gas cost. The addresses start from `1`, and increment for each contract. - -New hard forks may introduce new precompiled contracts. They are called from the opcodes like regular contracts, with -instructions like `CALL`. The gas cost mentioned here is purely the cost of the contract. It does not consider the cost -of the call itself nor the instructions to put the parameters in memory. - -For `Go-Ethereum`, the code being run is written in Go, and the gas costs are defined in each precompile spec. - -## Field Arithmetic - -The BN254 (also known as alt-BN128) is an elliptic curve defined by the equation $y^2 = x^3 + 3$ over the finite field -$\mathbb{F}_p$, being $p = 218882428718392752222464057452572750886963111572978236626890378946452262$08583. The modulus -is less than 256 bits, which is why every element in the field is represented as a `uint256`. - -The arithmetic is carried out with the field elements encoded in the Montgomery form. This is done not only because -operating in the Montgomery form speeds up the computation but also because the native modular multiplication, which is -carried out by Yul's `mulmod` opcode, is very inefficient. - -Instructions set on zkSync and EVM are different, so the performance of the same Yul/Solidity code can be efficient on -EVM, but not on zkEVM and opposite. - -One such very inefficient command is `mulmod`. On EVM there is a native opcode that makes modulo multiplication and it -costs only 8 gas, which compared to the other opcodes costs is only 2-3 times more expensive. On zkEVM we don’t have -native `mulmod` opcode, instead, the compiler does full-with multiplication (e.g. it multiplies two `uint256`s and gets -as a result an `uint512`). Then the compiler performs long division for reduction (but only the remainder is kept), in -the generic form it is an expensive operation and costs many opcode executions, which can’t be compared to the cost of -one opcode execution. The worst thing is that `mulmod` is used a lot for the modulo inversion, so optimizing this one -opcode gives a huge benefit to the precompiles. - -### Multiplication - -As said before, multiplication was carried out by implementing the Montgomery reduction, which works with general moduli -and provides a significant speedup compared to the naïve approach. - -The squaring operation is obtained by multiplying a number by itself. However, this operation can have an additional -speedup by implementing the SOS Montgomery squaring. - -### Inversion - -Inversion was performed using the extended binary Euclidean algorithm (also known as extended binary greatest common -divisor). This algorithm is a modification of Algorithm 3 `MontInvbEEA` from -[Montgomery inversion](https://cetinkayakoc.net/docs/j82.pdf). - -### Exponentiation - -The exponentiation was carried out using the square and multiply algorithm, which is a standard technique for this -operation. - -## Montgomery Form - -Let’s take a number `R`, such that `gcd(N, R) == 1` and `R` is a number by which we can efficiently divide and take -module over it (for example power of two or better machine word, aka 2^256). Then transform every number to the form of -`x * R mod N` / `y * R mod N` and then we get efficient modulo addition and multiplication. The only thing is that -before working with numbers we need to transform them to the form from `x mod N` to the `x * R mod N` and after -performing operations transform the form back. - -For the latter, we will assume that `N` is the module that we use in computations, and `R` is $2^{256}$, since we can -efficiently divide and take module over this number and it practically satisfies the property of `gcd(N, R) == 1`. - -### Montgomery Reduction Algorithm (REDC) - -> Reference: <https://en.wikipedia.org/wiki/Montgomery_modular_multiplication#The_REDC_algorithm> - -```solidity -/// @notice Implementation of the Montgomery reduction algorithm (a.k.a. REDC). -/// @dev See <https://en.wikipedia.org/wiki/Montgomery_modular_multiplication#The_REDC_algorithm> -/// @param lowestHalfOfT The lowest half of the value T. -/// @param higherHalfOfT The higher half of the value T. -/// @return S The result of the Montgomery reduction. -function REDC(lowestHalfOfT, higherHalfOfT) -> S { - let q := mul(lowestHalfOfT, N_PRIME()) - let aHi := add(higherHalfOfT, getHighestHalfOfMultiplication(q, P())) - let aLo, overflowed := overflowingAdd(lowestHalfOfT, mul(q, P())) - if overflowed { - aHi := add(aHi, 1) - } - S := aHi - if iszero(lt(aHi, P())) { - S := sub(aHi, P()) - } -} - -``` - -By choosing $R = 2^{256}$ we avoided 2 modulo operations and one division from the original algorithm. This is because -in Yul, native numbers are uint256 and the modulo operation is native, but for the division, as we work with a 512-bit -number split into two parts (high and low part) dividing by $R$ means shifting 256 bits to the right or what is the -same, discarding the low part. - -### Montgomery Addition/Subtraction - -Addition and subtraction in Montgomery form are the same as ordinary modular addition and subtraction because of the -distributive law - -$$ -\begin{align*} -aR+bR=(a+b)R,\\ -aR-bR=(a-b)R. -\end{align*} -$$ - -```solidity -/// @notice Computes the Montgomery addition. -/// @dev See <https://en.wikipedia.org/wiki/Montgomery_modular_multiplication#The_The_REDC_algorithm> for further details on the Montgomery multiplication. -/// @param augend The augend in Montgomery form. -/// @param addend The addend in Montgomery form. -/// @return ret The result of the Montgomery addition. -function montgomeryAdd(augend, addend) -> ret { - ret := add(augend, addend) - if iszero(lt(ret, P())) { - ret := sub(ret, P()) - } -} - -/// @notice Computes the Montgomery subtraction. -/// @dev See <https://en.wikipedia.org/wiki/Montgomery_modular_multiplication#The_The_REDC_algorithm> for further details on the Montgomery multiplication. -/// @param minuend The minuend in Montgomery form. -/// @param subtrahend The subtrahend in Montgomery form. -/// @return ret The result of the Montgomery addition. -function montgomerySub(minuend, subtrahend) -> ret { - ret := montgomeryAdd(minuend, sub(P(), subtrahend)) -} - -``` - -We do not use `addmod`. That's because in most cases the sum does not exceed the modulus. - -### Montgomery Multiplication - -The product of $aR \mod N$ and $bR \mod N$ is $REDC((aR \mod N)(bR \mod N))$. - -```solidity -/// @notice Computes the Montgomery multiplication using the Montgomery reduction algorithm (REDC). -/// @dev See <https://en.wikipedia.org/wiki/Montgomery_modular_multiplication#The_The_REDC_algorithm> for further details on the Montgomery multiplication. -/// @param multiplicand The multiplicand in Montgomery form. -/// @param multiplier The multiplier in Montgomery form. -/// @return ret The result of the Montgomery multiplication. -function montgomeryMul(multiplicand, multiplier) -> ret { - let hi := getHighestHalfOfMultiplication(multiplicand, multiplier) - let lo := mul(multiplicand, multiplier) - ret := REDC(lo, hi) -} - -``` - -### Montgomery Inversion - -```solidity -/// @notice Computes the Montgomery modular inverse skipping the Montgomery reduction step. -/// @dev The Montgomery reduction step is skipped because a modification in the binary extended Euclidean algorithm is used to compute the modular inverse. -/// @dev See the function `binaryExtendedEuclideanAlgorithm` for further details. -/// @param a The field element in Montgomery form to compute the modular inverse of. -/// @return invmod The result of the Montgomery modular inverse (in Montgomery form). -function montgomeryModularInverse(a) -> invmod { - invmod := binaryExtendedEuclideanAlgorithm(a) -} -``` - -As said before, we use a modified version of the bEE algorithm that lets us “skip” the Montgomery reduction step. - -The regular algorithm would be $REDC((aR \mod N)^{−1}(R^3 \mod N))$ which involves a regular inversion plus a -multiplication by a value that can be precomputed. diff --git a/content/40.zk-stack/components/zkEVM/vm-specification/formal-spec.md b/content/40.zk-stack/components/zkEVM/vm-specification/formal-spec.md deleted file mode 100644 index 3c85591c..00000000 --- a/content/40.zk-stack/components/zkEVM/vm-specification/formal-spec.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: VM Formal Specification | zkSync Docs ---- - -# VM Formal Specification - -This is the specification of the instruction set of EraVM 1.4.0, a language virtual machine for zkSync Era. It describes -the virtual machine's architecture, instruction syntax and semantics, and some elements of system protocol. - -[See the Formal Specification here.](https://matter-labs.github.io/eravm-spec/spec.html) diff --git a/content/40.zk-stack/components/zkEVM/vm-specification/vm-primer.md b/content/40.zk-stack/components/zkEVM/vm-specification/vm-primer.md deleted file mode 100644 index dae9ba5e..00000000 --- a/content/40.zk-stack/components/zkEVM/vm-specification/vm-primer.md +++ /dev/null @@ -1,639 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: ZkSync Virtual Machine Primer | zkSync Docs ---- - -# ZkSync Virtual Machine primer - -Unlike EVM, zkEVM is a register machine. EVM instructions operate on a stack. Instead, zkEVM operates primarily on -sixteen registers and memory like most modern computers. That simplifies zero-knowledge proofs, which largely rely on -building arithmetic circuits. - -This document describes zkEVM assembly language, then the aspects of VM related to smart-contracts. Its purpose is not -to be a complete reference, but to guide you through the main ideas. - -## VM architecture - -The native type for zkEVM is a 256-bits wide unsigned integer, we call it a _word_. - -Contracts are sequences of instructions. To support the execution of contracts, VM provides the following transient -state: - -- **registers**: 16 general-purpose registers: `r0`, `r1`, …, `r15`. - `r0` is a special constant register: reading it yields 0, storing to it is ignored. -- **flags**: three distinct boolean registers LT (less-than), EQ (equals, the result is zero) and GT (greater-than). - Instructions may set or clear flags depending on computation results. -- **data** **stack**: holds $2^{16}$ words, is free to use. -- **heap**: for data that we want to pass around between functions and contracts. Heap is bounded, accesses are only - free inside the bound, and we have to pay for growing the bound. -- **code memory**: stores code of currently running contracts. May also be used as a constant pool. - -VM is aware of two data types: - -- raw integers -- pointers (to fragments of other contracts’ heaps). - -Registers and data stack are tagged: VM keeps track of whether they hold pointers or raw integer values. Some -instructions will only accept operands tagged as pointers. - -Heap and storage are not tagged, so if we store a pointer to the heap, its tag is lost. - -Contracts have key-value storages, where keys and values are untagged 256-bit integers. Instructions can change -persistent contract storage. - -VM is capable of both near calls (to the code within the same contract) and far calls (to other contracts). - -Let us now gradually introduce the VM functionality guided by the instruction set. - -## Basic instructions - -Contract code consists of instructions, they are executed sequentially. - -Instructions usually operate with registers. For example, an instruction `add` may look like that: - -```asm -; this is a comment -add 5, r2, r8 ; store (5 + r2) to r8 -``` - -Or like that: - -```asm -add 5, r0, r8 ; store (5 + 0) to r8 -``` - -Notice that register `r0` is used to feed constant zero values to instructions; this allows to use `add X, r0, Y` to -copy a value `X` to `Y` . - -Commonly, instructions accept two inputs and one output operands, following the schema: - -<img src="../../../../assets/images/arithmetic_opcode.png" style="align:center"> - -The first operand can be taken from: - -- registers -- an immediate 16-bit value, like in the example above `add 5, r2, r8`. To use bigger numbers put them as constants in - the code memory, see section **Code Addressing**. -- directly from the code memory -- stack in various ways, e.g. `add stack=[2], r2, r8` takes the first element from the stack memory area, by an absolute - address 2. -- code memory - -Only registers can be the source of the second operand. - -```asm -add r0, 5, r8 ; error: 5 is an immediate value, - ; but only register is allowed as second operand -``` - -There is usually at most one output operand. Similarly, the first output operand can be stored to registers or stack. If -there is a second output operand, it can only be stored to a register. - -Instructions are executed one after another, and every instruction has a gas cost measured in _gas_. A program that runs -out of gas panics and none of its side effects are performed. - -Every contract may have at most $2^{16}$ instructions. - -### Arithmetic instructions - -Besides `add`, zkEVM implements `sub` for subtraction, `and`/ `or` / `xor` for bitwise logics, `shl`/ `shr` for logical -shifts, `rol`/ `ror` for circular shifts. These instructions follow the same format, e.g.: - -```asm -shl r1, r4, r3 ; right shift r1 by value of r4, store result in r3 -``` - -Instructions `mul` and `div` are particular: they have two output operands: - -- `mul r1, r2, r3, r4` stores the low 256 bits of r1_r2 in r3, high 256 bits of r1_r2 in r4 -- `div r1, r2, r3, r4` stores the quotient in `r3` and remainder in `r4`. - -### Modifiers - -Most instructions support modifiers that alter their behaviour. The modifiers are appended to the name of the -instruction, separated by a dot e.g. `sub.s` . Three basic modifier types are: `set_flags` , predicates, and `swap`. - -#### Set flags - -By default, most instructions preserve flags. - -```asm -sub r1, r2, r3 ; r3 <- (r1 - r2), no flags are affected -``` - -The instruction `sub` is implemented so that it sets `EQ` if the result is zero (that is, if `r1` == `r2`). But in this -case, even if `r1-r2` is zero, the EQ flag is not set, because we did not allow it explicitly. We allow instruction to -set flags by appending a “set flags” modifier to them, like that: - -```asm -sub! r1, r2, r3 ; r3 <- (r1 - r2); EQ = 1 -``` - -You can learn more in the [formal specification](./formal-spec.md). - -#### Predicates - -Another type of modifiers allows transforming any instruction into a _predicated_, conditional instruction. Predicated -instructions are only executed if flags satisfy their condition. - -Recall the three flags: LT, EQ and GT. - -For example, this `sub` instruction is only executed if EQ is set: - -```asm -sub.if_eq r1, r2, r5 -``` - -Here is how we can execute `jump` to a label `.label_if_equals` only if `r1 == r2` : - -```asm -sub! r1, r2, r3 ; r3 <- (r1 - r2); EQ = 1 if r1 == r2 -jump.if_eq .label_if_equals -``` - -If the condition is not satisfied, we skip the instruction, but still pay its basic cost in gas. - -Here is a full list of available predicates: - -- `if_gt` -- `if_eq` -- `if_lt` -- `if_ge` (short for “GT or EQ”) -- `if_le` (short for “LT or EQ”) -- `if_not_eq` -- `if_gt_or_eq` - -You can learn more in the [formal specification](./formal-spec.md). - -#### Swap - -Recall that instructions may only accept data from stack as their first operand. What if we need the second operand from -stack? For commutative operation, like `add` , `mul`, or `and`, the order of operands does not matter and we can just -write `add x,y,z` instead of `add y,x,z`. However, for operations like `sub` or `div` we implement a special “swap” -modifier which exchanges the operand values before executing the instruction. This is useful to work around the -restriction that the second source operand has to be a register. - -For example: - -```asm -sub r1, r2, r3 ; r3 <- r1 - r2 -sub.s r1, r2, r3 ; r3 <- r2 - r1 - -``` - -Finally, here is an example of an instruction adorned with all possible modifiers: - -```asm -sub.s.if_lt! r8, r4, r12 -``` - -Here is a breakdown of modifiers: - -- `.if_lt` : is only executed if the LT flag is set -- `.s` : computes `r4 - r8` instead of `r8 - r4` -- `!` : sets flags - -$$ -\begin{aligned} -LT &\leftarrow r_4 < r_8 \\ -EQ &\leftarrow r_4 - r_8 = 0 \\ -GT &\leftarrow r_4 > r_8 -\end{aligned} -$$ - -Other modifiers are instruction-specific. They are described in full in the instruction reference. - -## Calls and returns - -The `jump` instruction allows to continue execution from a different place, but it does not allow to return back. An -alternative is using calls; zkEVM supports calling code inside the contract itself (near calls) as well as calling other -contracts (far calls). - -### Far calls - -Far calls are the equivalent of calls in EVM. - -Each call gets its own stack, heap, code memories, and allocated gas. - -It is impossible to allocate more than 63/64 of the currently available gas to a far call. - -Calls can revert or panic (on executing an illegal instruction for example), which undoes all the changes to storage and -events emitted during the call, and burns all remaining gas allocated to this call. - -Suppose we far called a contract $C$. After the execution of $C$, the register `r1` holds a pointer to the return value, -allowing a read-only access to a fragment of $C$’s heap. Alternatively, `r1` can hold a pointer to the heap of some -other contract that $C$ called internally. More on that in Pointers section. - -**Delegate calls.** Beside normal `far_call`, there is a variant `far_call.delegate`. Delegate calls are a variation of -far calls allowing to call a contract with the current storage space. - -For example, suppose we have contracts A,B,C. Contract A calls B normally, then B delegates to C. Then C’s code is -executed in a context of B’s storage, as if contract A called contract C. If C returns normally, the execution will -proceed from the next instruction of B after delegate call. In case of `revert` or `panic` in C, all the usual rules -apply. - -**Mimic calls.** The last variant of far calls is `far_call.mimic`; it is inaccessible to users and only allowed in -system contracts. - -Any of far call variants can be additionally marked as `.static` to call a contract in static mode — see section -**Static Mode**. - -### Return, revert, panic - -There are three types of situations where control returns to the caller: - -- Return: a normal way of returning to the caller when no errors occurred. The instruction is `ret`. -- Revert: a recoverable error happened. Unspent gas is returned to the caller, which will execute the exception handler. - The instruction is `revert`. -- Panic: an irrecoverable error happened. Same as revert, but unspent gas is burned. The instruction is `ret.panic`. - -### Near calls - -Instruction `near_call reg, address` passes the control to a different address inside the same contract, like `jump`. -Additionally, it remembers the context of execution in a special _call stack_ (it is different from data stack and not -accessible to assembly programmers). - -Here is an example of calling function `f` . - -```asm -.text - -; here will be the code of exception handler -eh: - -; caller function -main: -near_call r2, @f, @eh ; refer to labels in code using '@' symbol - -; callee function -f: -ret - -``` - -Additional two arguments: - -- label `@eh` is the address of exception handler. Functions, like contracts, may revert or panic, which leads to the - execution of the exception handler. -- register `r2` holds how much gas we allocate to the function. - -As we see, zkEVM supports allocating ergs not only for far calls, but also for near calls. Passing zero will allocate -all available gas. Unlike in far calls, near calls do not limit the amount of gas passed to 63/64 of available gas. - -- On revert, unspent gas of the function is **returned** -- On panic, unspent gas of the function is **lost** - -All near calls inside the contract are sharing the same memory space (heap, stack), and do not roll back the changes to -this memory if they fail. They do, however, roll back the changes to storage and events. - -Near calls cannot be used from Solidity to their full extent. Compiler generates them, but makes sure that if functions -revert or panic, the whole contract reverts of panics. Explicit exception handlers and allocating just a portion of -available gas are reserved for low-level code. - -## Accessing data outside registers - -### Stack addressing - -As we already know, instructions may accept data not only in registers or as immediate 16-bit values, but also on stack. - -Data stack is a collection of $2^{16}$ words with a pointer SP. This pointer contains the next address after the topmost -stack element, so the topmost element has the address SP-1. Stack grows towards maximal address, i.e. pushing an element -to stack increases SP. - -On far call, SP starts in a new stack memory at 1024. - -#### Reading from stack - -There are several ways of accessing stack cells: - -```asm -.text -main: - -; r0 <- stack word by absolute index (r1+42), unrelated to SP -add stack=[r1+42], r0, r2 - -; r0 <- stack word by index (SP - (r1 + 42)) -add stack[r1+42], r0, r2 - -; r2 <- stack word by index (SP - (r1 + 42)); additionally, SP += (r1+42) -add stack-=[r1+42], r0, r2 -``` - -As we see there are three stack address modes for input operands; all of them use (register + offset). - -Currently, the last mode is only used in a `nop` instruction as a way to rewind stack: - -```asm -; effectively, SP -= reg+imm -nop stack-=[reg+imm] -``` - -#### Writing to stack - -Storing results on stack is also possible: - -```asm -.text -main: - -; r1 -> word by absolute index (r2 + 42) -add r1, r0, stack=[r2 + 42] - -; r1 -> word by absolute index SP - (r2 + 42) -add r1, r0, stack[r2 + 42] - -; r1 -> word by absolute index SP + (r2 + 42) -; additionally, SP += r2 + 42 -add r1, r0, stack+=[r2 + 42] -``` - -Currently, the last mode is only used in a `nop` instruction as a way to forward stack pointer: - -```asm -; effectively, SP += reg+imm -nop r0, r0, stack+=[reg+imm] -``` - -### Code addressing - -Sometimes we might need to work with larger chunks that do not fit into 16-bit. In this case we can use the (read-only) -code memory as a constant pool and read 256-bit constants from there. - -```asm -.rodata - -datavar: - .cell 42 - .cell 999 -.text -somelabel: - -; r2 <- word by index (r0+0) code memory -add @datavar[0], r0, r2 -add @datavar[r2], r0, r2 -``` - -Note: instructions are 64-bit wide, but when accessing data in code memory, this memory is treated as word-addressable. -Therefore, e.g. reading the 0-th 256-bit word from this memory will yield a binary representation of the four first -64-bit instructions in the contract. - -There is no distinction between static data and code: code can be read, data can be executed, but instructions that are -not correctly encoded will trigger panic. - -Contracts always need to be divisible by 32 bytes (4 instructions) because of this addressing mode. - -### Using heap - -Heap is a bounded memory region to store data between near calls, and to communicate data between contracts. - -#### Heap boundary growth - -Accessing an address beyond the heap bound leads to heap growth: the bound is adjusted to accommodate this address. The -difference between old and new bounds is paid in gas. - -#### Instructions to access heap - -Most instructions can not use heap directly. Instructions `ld.1` and `st.1` are used to load and store data on heap: - -```asm -; take a 32-bit number from r1, use it as an offset in heap, -; load the word from heap by this offset to r4 -ld.1 r1, r4 - -; take a 32-bit number from r3, use it as an offset in heap, -; store the word from r5 to heap by this offset -st.1 r3, r5 -``` - -Heap is byte-addressable, but reads and writes operate in words. To read two consecutive words in heap starting at an -address A, first, read from A, and then read from A+32. Reading any addresses in between is valid too. - -One of the modifiers allows to immediately form a new offset like that: - -```asm -; same as ld, but additionally r5 <- r1 + 32 -ld.1.inc r1, r4, r5 -``` - -This allows reading several consecutive words in a row: - -```asm -; reads four consecutive words from heap starting at address in r8 -; into registers r1, r2, r3, r4 -ld.1.inc r8, r1, r8 -ld.1.inc r8, r2, r8 -ld.1.inc r8, r3, r8 -ld.1.inc r8, r4, r8 -``` - -In theory, heap can hold nearly $2^{32}$ bytes, but growing a heap so large is not affordable: the maximum gas allocated -is $2^{32}-1$. - -The topmost 32 bytes of heap are considered forbidden addresses, trying to access them results in panic no matter how -much gas is available. - -#### Heap and Auxheap - -In zkEVM, there are two heaps; every far call allocates memory for both of them. - -Heaps are selected with modifiers `.1` or `.2` : - -- `ld.1` reads from heap; -- `ld.2` reads from auxheap. - -The reason why we need two heaps is technical. Heap contains calldata and returndata for calls to user contracts, while -auxheap contains calldata and returndata for calls to system contracts. This ensures better compatibility with EVM as -users should be able to call zkEVM-specific system contracts without them affecting calldata or returndata. - -## Fat pointers - -A fat pointer is the second type of values in zkEVM, beside raw integers. - -As we noted, registers and stacks are internally tagged by VM to keep track of the cells containing pointers in their -low 128 bits. Only cells with a set pointer tag are considered fat pointers. - -Fat pointers are used to pass read-only data between contracts. When choosing how to pass data to a contract (whether -when calling or returning from a call) we have a choice: - -- pass an existing fat pointer, or -- create a new fat pointer from a fragment of heap/auxheap. - -Fat pointers combine two aspects: - -- Delimit a fragment accessible to other contract. Accesses outside this fragment through a pointer yield zero. -- Provide an offset inside this fragment. This offset can be increased or decreased. - -The restrictions on fat pointers provide allows to pass data between contracts safely and without excessive copying. - -**Implementation note.** Internally, fat pointers hold four 32-bit values: - -- bits 0..31 : offset -- bits 32..63: internal memory page ID -- bits 64…95 : starting address of the fragment -- bits 96…127 : length of the fragment - -#### Instructions to manipulate fat pointers - -Only special instructions can manipulate fat pointers without automatically clearing its pointer tag. - -- `ptr.add`, `ptr.sub` modify the offset inside pointer -- `ptr.shrink` reduces the associates fragment, so if we get a fat pointer from contract A, we can then shrink it and - pass to another contract B up the call chain, again without copying data. -- `ptr.pack` allows putting data in the top 128 bit of the pointer value without clearing the pointer tag. - -Doing e.g. `add r1, 0, r2` on a pointer in `r1` clears its tag, and it is now considered as a raw integer. - -Instructions `ld` and `[ld.inc](http://ld.inc)` (without indices 1 or 2) allow loading data by fat pointers, possibly -incrementing the pointer. It is impossible to write by a fat pointer. - -## Contracts and storage - -All accounts are associated with contracts. There are $2^{160}$ valid account addresses. - -In zkEVM, contracts may have multiple **functions** in them; a contract may execute its functions by using `near_call` ; -it may call other contracts by using `far_call` or its variations `delegate_call` / `mimic_call` (mimic is reserved for -system contracts). - -Size of a contract should be divisible by 32 bytes (4 instructions). - -### Storage of contracts - -Every account has a storage. Storage maps $2^{256}$ keys to values; both keys and values are 256-bit untagged words. - -Contracts may write to their own storage by using `sstore key, value` and read from storage using `sload key, dest`. - -### Static mode - -Static mode prevents contracts from modifying their storage and emitting events. In static mode, executing an -instruction like `sstore` sends VM into panic. - -To execute a contract C in static mode, use a `static` modifier: `far_call.static`. All contracts, called by C -recursively, will also be executed in static mode. VM exits static mode automatically when C terminates. - -### System contracts - -Part of Era’s functionality is implemented through system contracts. These contracts have addresses from 0 to $2^{64}$ -and are executed in kernel mode, where they have access to privileged instructions. An example of such instruction is -mimic call, a variant of far call where the caller can pretend to be another contract. This is useful for hiding the -fact that something is implemented via a system contract but in the hands of users it would mean being able to steal -anyone’s tokens. - -System contracts implement contract deployment, extensions such as keccak256, decommitting code etc. - -## Server and VM environment - -### Decommitter - -Decommitter is a module external to zkEVM allowing accessing deployed code by its hash. - -![Overview of VM modules](../../../../assets/images/vm-mapping.png) - -The system contracts at the address $2^{15}+2$ , called Deployer, keeps hashes of code of each contract in its storage. -Far calls to a contract with address $C$ perform as follows: - -- VM internally accesses the storage of `Deployer` contract by key $C$. This storage yields the hash value $H$**.** -- then VM queries the decommitter, providing $H$. Decommitter answers with the contract code. - -If decommitter does not have the code for the requested hash, one of two things happen: - -- if C is a system contract (i.e. address of $C < 2^{16}$), the call will fail -- otherwise, VM will call the `DefaultAccount` contract. - -### Server - -The VM is controlled by a _server._ When the server needs to build a new batch, it starts an instance of zkEVM and feeds -the transactions to the [Bootloader](#bootloader). - -zkEVM accepts three parameters: - -1. Bootloader’s hash. It is used to fetch the bootloader code from decommitter. -2. Code hash of `DefaultAccount` contract code. It is used to fetch the default code from Decommitter in case of a far - call to a contract without any associated code. -3. A boolean flag `is_porter_available`, to determine the number of shards (two if zkPorter is available, one - otherwise). - -zkEVM retrieves the code of bootloader from Decommitter and proceeds with sequential execution of instructions on the -bootloader’s code page. - -#### Failures and rollbacks - -There are three types of behaviour triggered by execution failures. - -1. Skipping a malformed transaction. It is a mechanism implemented by the server, external to zkEVM. Server makes a - snapshot of zkEVM state after completing every transaction. If the bootloader encounters a malformed transaction, it - fails, and the server restarts zkEVM from the most recent snapshot, skipping this transaction. - - This behaviour is specific to server/bootloader; the contract code has no ways of invoking it. - -2. Revert is triggered by the contract code explicitly by executing `revert`. zkEVM saves its persistent state on every - near or far call. If the contract code identifies a recoverable error, it may execute `revert`; then zkEVM rolls the - storage and event queues back to the last checkpoint and executes the exception handler. -3. Panic is triggered either explicitly by executing `panic` or internally when some execution invariants are violated - e.g. attempt to use raw integer in `ptr.add` instruction. - - On panic, the persistent state of zkEVM is rolled back in the same way as on revert. - -### Bootloader - -Bootloader is a system contract in charge of block construction -(**[sources](https://github.com/matter-labs/era-contracts/blob/main/system-contracts/bootloader/bootloader.yul)**). - -Formally, bootloader is assigned an address BOOTLOADER_SYSTEM_CONTRACT_ADDRESS = $2^{15}+1$, but zkEVM decommits its -code directly by its hash. - -The heap of the bootloader is special: it acts as an interface between server and zkEVM. Server gradually fills the -bootloader’s heap with transaction data, formatted according to an implementation-defined convention. - -The bootloader then acts roughly as the following code (not an actual implementation): - -```solidity -contract Bootloader { - function executeBlock(address operatorAddress, Transaction[2] memory transactions) { - for (uint256 i = 0; i < transactions.length; i++) { - validateTransaction(transactions[i]); - chargeFee(operatorAddress, transactions[i]); - executeTransaction(transactions[i]); - } - } - - function validateTransaction(Transaction memory tx) { - // validation logic - } - - function chargeFee(address operatorAddress, Transaction memory tx) { - // charge fee - } - - function executeTransaction(Transaction memory tx) { - // execution logic - } -} - -``` - -The bootloader is therefore responsible for: - -- validating transactions; -- executing transactions to form a new block; -- setting some of the transaction- or block-wide transaction parameters (e.g. `blockhash`, `tx.origin`). - -Server makes a snapshot of zkEVM state after completing every transaction. When the bootloader encounters a malformed -transaction, it fails, and the server restarts zkEVM from the most recent snapshot, skipping this transaction. If a -transaction is well-formed, zkEVM may still panic while handling it outside the bootloader code. This is a normal -situation and is handled by zkEVM in a regular way, through panics. - -The exact code of the bootloader is a part of a protocol; its hash is included in the block header. - -### Context value - -A part of the zkEVM state is a 128-bit _context value_. It implements `msg.value` standing for the amount of wei sent in -a transaction. In assembly, it is used as follows: - -1. Execute `context.set_context_u128 reg` to set the value; -2. Perform a far call — it captures the context value; -3. In a called contract, access the context value through `context.get_context_u128 reg`. - -Context value can not be set in static mode. diff --git a/content/40.zk-stack/concepts/account-abstraction.md b/content/40.zk-stack/concepts/account-abstraction.md deleted file mode 100644 index bfab45d8..00000000 --- a/content/40.zk-stack/concepts/account-abstraction.md +++ /dev/null @@ -1,46 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Account Abstraction Specs | zkSync Docs ---- - -# Account abstraction - -One of the other important features of zkSync is the support of account abstraction. It is highly recommended to read -the documentation on our [AA protocol here](../../build/developer-reference/account-abstraction.md). - -### Account versioning - -Each account can also specify which version of the account abstraction protocol do they support. This is needed to allow -breaking changes of the protocol in the future. - -Currently, two versions are supported: `None` (i.e. it is a simple contract and it should never be used as `from` field -of a transaction), and `Version1`. - -### Nonce ordering - -Accounts can also signal to the operator which nonce ordering it should expect from these accounts: `Sequential` or -`Arbitrary`. - -`Sequential` means that the nonces should be ordered in the same way as in EOAs. This means, that, for instance, the -operator will always wait for a transaction with nonce `X` before processing a transaction with nonce `X+1`. - -`Arbitrary` means that the nonces can be ordered in arbitrary order. It is supported by the server right now, i.e. if -there is a contract with arbitrary nonce ordering, its transactions will likely either be rejected or get stuck in the -mempool due to nonce mismatch. - -Note, that this is not enforced by system contracts in any way. Some sanity checks may be present, but the accounts are -allowed to do however they like. It is more of a suggestion to the operator on how to manage the mempool. - -### Returned magic value - -Now, both accounts and paymasters are required to return a certain magic value upon validation. This magic value will be -enforced to be correct on the mainnet, but will be ignored during fee estimation. Unlike Ethereum, the signature -verification + fee charging/nonce increment are not included as part of the intrinsic costs of the transaction. These -are paid as part of the execution and so they need to be estimated as part of the estimation for the transaction’s -costs. - -Generally, the accounts are recommended to perform as many operations as during normal validation, but only return the -invalid magic in the end of the validation. This will allow to correctly (or at least as correctly as possible) estimate -the price for the validation of the account. diff --git a/content/40.zk-stack/concepts/blocks.md b/content/40.zk-stack/concepts/blocks.md deleted file mode 100644 index 380cb789..00000000 --- a/content/40.zk-stack/concepts/blocks.md +++ /dev/null @@ -1,219 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Blocks | zkSync Docs ---- - -# Blocks - -Here, we will explore the processing of transactions, how we group them into blocks, what it means to "seal" a block, -and why it is important to have rollbacks in our virtual machine (VM). - -At the basic level, we have [individual transactions](./transaction-lifecycle.md). However, to execute them more -efficiently, we group them together into blocks & batches. - -**L2 blocks**, or just "blocks", are the blocks created on the L2, that is on the zkSync Era network, and they are not -included on the Ethereum chain. - -On the other hand, L1 rollup blocks are **batches** of consecutive L2 blocks that contain all the transactions in the -same order, from the first block to the last block in the batch. - -L1 batches, as the name suggests, are submitted to Ethereum. The main reason to have these different notions is that a -block can contain a minimal number of transactions (see fictive blocks below), and thus be processed quickly, while in a -batch we would like to include many transactions to spread the cost of interacting with L1 across all transactions. - -## Batch vs Block vs Transaction - -To help visualize the concept, here are two images: - -![Block layout](../../assets/images/block-layout.png) - -You can refer to the Block layout image to see how the blocks are organized. It provides a graphical representation of -how transactions are arranged within the blocks and the arrangement of L2 blocks within L1 batches. - -![Explorer example](../../assets/images/explorer-example.png) - -## L2 Blocks (aka Miniblocks) - -Currently, the L2 blocks do not have a major role in the system, until we transition to a decentralized sequencer. We -introduced them mainly as a "compatibility feature" to accommodate various tools, such as Metamask, which expect a block -that changes frequently. This allows these tools to provide feedback to users, confirming that their transaction has -been added. - -As of now, an L2 block is created every 2 seconds (controlled by StateKeeper's config `miniblock_commit_deadline_ms`), -and it includes all the transactions received during that time period. This periodic creation of L2 blocks ensures that -transactions are processed and included in the blocks regularly. - -### Block Properties - -The following are the block properties returned when you use the `getBlock` method from the API using any of our SDKs. - -| Parameter | Description | -| ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | -| hash | The hash of the L2 block. null if pending | -| parentHash | It refers to the hash of the parent block in L2. | -| number | The number of the current L2 block. null if pending. | -| timestamp | The UNIX timestamp for when the L2 block was collated. | -| nonce | It's the most recent transaction based on the account's counter, which maintains track of how many transactions it does. null if pending. | -| difficulty | The current block difficulty returns 2500000000000000 (zkSync does not have proof of work consensus). | -| gasLimit | The maximum gas allowed in this block encoded as a hexadecimal, always returns `2^32-1`. | -| gasUsed | The actual amount of gas used in this block. | -| transactions | An array of transaction objects - please see [interface TransactionResponse](../../build/sdks/js/providers.md#gettransaction) for exact more info | -| baseFeePerGas | The EIP1559-like baseFee for this block. | - -::: info Block number and timestamp considerations - -An update in the protocol introduced changes on how certain block properties were implemented on zkSync Era. For details -on the changes performed visit the -[announcement on GitHub](https://github.com/zkSync-Community-Hub/zkync-developers/discussions/87). - -::: - -## L1 batches - -L1 batches play a crucial role because they serve as the fundamental unit for generating proofs. From the perspective of -the virtual machine (VM), each L1 batch represents the execution of a single program, specifically the Bootloader. The -Bootloader internally processes all the transactions belonging to that particular batch. Therefore, the L1 batch serves -as the container for executing the program and handling the transactions within it. - -### L1 Batch size and processing times - -Most blockchains use factors like time and gas usage to determine when a block should be closed or sealed. However, our -case is a bit more complex because we also need to consider prover capacity and limits related to publishing to L1. - -The decision of when to seal the batch is handled by the code in the -[conditional_sealer](https://github.com/matter-labs/zksync-era/blob/main/core/lib/zksync_core/src/state_keeper/seal_criteria/conditional_sealer.rs#20) -module. It maintains a list of `SealCriterion` and at the time of writing this article, -[we have 9 reasons to seal the batch](https://github.com/matter-labs/zksync-era/blob/main/core/lib/zksync_core/src/state_keeper/seal_criteria/mod.rs#L106), -which include: - -- Transaction slots limit (currently set to 750 transactions in `StateKeeper`'s config - `transaction_slots`). -- Gas limit (currently set to `MAX_L2_TX_GAS_LIMIT` = 80M). -- Published data limit (as each L1 batch must publish information about the changed slots to L1, so all the changes must - fit within the L1 transaction limit, currently set to `MAX_PUBDATA_PER_L1_BATCH`= 120k). -- zkEVM Geometry limits - For certain operations like merkle transformation, there is a maximum number of circuits that - can be included in a single L1 batch. If this limit is exceeded, we wouldn't be able to generate the proof. - -We also have a `TimeoutCriterion` - but it is not enabled. - -However, these sealing criteria pose a significant challenge because it is difficult to predict in advance whether -adding a given transaction to the current batch will exceed the limits or not. This unpredictability adds complexity to -the process of determining when to seal the block. - -### `ExcludeAndSeal` - -To handle situations where a transaction exceeds the limits of the currently active L1 batch, we employ a "try and -rollback" approach. This means that we attempt to add the transaction to the active L1 batch, and if we receive a -`ExcludeAndSeal` response indicating that it doesn't fit, we roll back the virtual machine (VM) to the state before the -transaction was attempted. - -Implementing this approach introduces a significant amount of complexity in the `oracles` (also known as interfaces) of -the VM. These oracles need to support snapshotting and rolling back operations to ensure consistency when handling -transactions that don't fit. - -## Retrieving block and batch numbers - -Accessing block numbers within zkSync API is similar to how you would do it on Ethereum. For example, `eth_blockNumber` -returns the number of the latest L2 block, and `eth_getBlockByNumber`, given a block number, returns the information -about the requested block. - -For L1 batches, to retrieve the latest batch number, use zkSync API method `zks_L1BatchNumber`. Additionally, by -querying on a block, you can see the batch number for the batch that includes the block. Within transaction receipts, -the field `l1BatchNumber` is the batch number that includes the transaction. The field `l1BatchTxIndex` returns the -transaction position among all of the transactions included in a batch. - -## Deeper dive - -### Initializing L1 batch - -At the start of the batch, the operator -[provides](https://github.com/code-423n4/2023-10-zksync/blob/ef99273a8fdb19f5912ca38ba46d6bd02071363d/code/system-contracts/bootloader/bootloader.yul#L3636) -the timestamp of the batch, its number and the hash of the previous batch.. The root hash of the Merkle tree serves as -the root hash of the batch. - -The SystemContext can immediately check whether the provided number is the correct batch number. It also immediately -sends the previous batch hash to L1, where it will be checked during the commit operation. Also, some general -consistency checks are performed. This logic can be found -[here](https://github.com/code-423n4/2023-10-zksync/blob/ef99273a8fdb19f5912ca38ba46d6bd02071363d/code/system-contracts/contracts/SystemContext.sol#L416). - -### L2 blocks processing and consistency checks - -#### `setL2Block` - -Before each transaction, we call `setL2Block` -[method](https://github.com/code-423n4/2023-10-zksync/blob/ef99273a8fdb19f5912ca38ba46d6bd02071363d/code/system-contracts/bootloader/bootloader.yul#L2605). -There we will provide some data about the L2 block that the transaction belongs to: - -- `_l2BlockNumber` The number of the new L2 block. -- `_l2BlockTimestamp` The timestamp of the new L2 block. -- `_expectedPrevL2BlockHash` The expected hash of the previous L2 block. -- `_isFirstInBatch` Whether this method is called for the first time in the batch. -- `_maxVirtualBlocksToCreate` The maximum number of virtual block to create with this L2 block. - -If two transactions belong to the same L2 block, only the first one may have non-zero `_maxVirtualBlocksToCreate`. The -rest of the data must be same. - -The `setL2Block` -[performs](https://github.com/code-423n4/2023-10-zksync/blob/ef99273a8fdb19f5912ca38ba46d6bd02071363d/code/system-contracts/contracts/SystemContext.sol#L312) -a lot of similar consistency checks to the ones for the L1 batch. - -### L2 blockhash calculation and storage - -Unlike L1 batch’s hash, the L2 blocks’ hashes can be checked on L2. - -The hash of an L2 block is -`keccak256(abi.encode(_blockNumber, _blockTimestamp, _prevL2BlockHash, _blockTxsRollingHash))`. Where -`_blockTxsRollingHash` is defined in the following way: - -`_blockTxsRollingHash = 0` for an empty block. - -`_blockTxsRollingHash = keccak(0, tx1_hash)` for a block with one tx. - -`_blockTxsRollingHash = keccak(keccak(0, tx1_hash), tx2_hash)` for a block with two txs, etc. - -To add a transaction hash to the current miniblock we use the `appendTransactionToCurrentL2Block` -[function](https://github.com/code-423n4/2023-10-zksync/blob/ef99273a8fdb19f5912ca38ba46d6bd02071363d/code/system-contracts/contracts/SystemContext.sol#L373). - -Since zkSync is a state-diff based rollup, there is no way to deduce the hashes of the L2 blocks based on the -transactions’ in the batch (because there is no access to the transaction’s hashes). At the same time, in order to -server `blockhash` method, the VM requires the knowledge of some of the previous L2 block hashes. In order to save up on -pubdata (by making sure that the same storage slots are reused, i.e. we only have repeated writes) we -[store](https://github.com/code-423n4/2023-10-zksync/blob/ef99273a8fdb19f5912ca38ba46d6bd02071363d/code/system-contracts/contracts/SystemContext.sol#L70) -only the last 257 block hashes. You can read more on what are the repeated writes and how the pubdata is processed -[here](https://github.com/code-423n4/2023-10-zksync/blob/main/docs/Smart%20contract%20Section/Handling%20L1%E2%86%92L2%20ops%20on%20zkSync.md). - -We store only the last 257 blocks, since the EVM requires only 256 previous ones and we use 257 as a safe margin. - -### Legacy blockhash - -When initializing L2 blocks that do not have their hashes stored on L2 (basically these are blocks before the migration -upgrade), we use the following formula for their hash: - -`keccak256(abi.encodePacked(uint32(_blockNumber)))` - -### Timing invariants - -While the timestamp of each L2 block is provided by the operator, there are some timing invariants that the system -preserves: - -- For each L2 block its timestamp should be > the timestamp of the previous L2 block -- For each L2 block its timestamp should be ≥ timestamp of the batch it belongs to -- Each batch must start with a new L2 block (i.e. an L2 block can not span across batches). -- The timestamp of a batch must be ≥ the timestamp of the latest L2 block which belonged to the previous batch. -- The timestamp of the last miniblock in batch can not go too far into the future. This is enforced by publishing an - L2→L1 log, with the timestamp which is then checked on L1. - -### Fictive L2 block & finalizing the batch - -At the end of the batch, -[the bootloader](https://github.com/code-423n4/2023-10-zksync/blob/ef99273a8fdb19f5912ca38ba46d6bd02071363d/code/system-contracts/bootloader/bootloader.yul#L3812) -calls the `setL2Block` one more time to allow the operator to create a new empty block. This is done purely for some of -the technical reasons inside the node, where each batch ends with an empty L2 block. - -We do not enforce that the last block is empty explicitly as it complicates the development process and testing, but in -practice, it is, and either way, it should be secure. - -Also, at the end of the batch we send the timestamps of the batch as well as the timestamp of the last miniblock in -order to check on L1 that both of these are realistic. Checking any other L2 block’s timestamp is not required since all -of them are enforced to be between those two. diff --git a/content/40.zk-stack/concepts/data-availability/overview.md b/content/40.zk-stack/concepts/data-availability/overview.md deleted file mode 100644 index e28a2a66..00000000 --- a/content/40.zk-stack/concepts/data-availability/overview.md +++ /dev/null @@ -1,83 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Data Availability | zkSync Docs ---- - -# Data Availability - -A major part of being a rollup is that the entirety of the L2 state can be reconstructed from the data that the zkSync -network (L2) submits to Ethereum (L1). - -Instead of submitting the data of each transaction, however, zkSync submits how the state of the blockchain changes, -this change is called the **state diff.** This approach allows the transactions that change the same storage slots to be -very cheap, since these transactions don't incur additional data costs. - -Besides the state diff we -also [post additional](https://github.com/matter-labs/zksync-era/blob/main/docs/specs/data_availability/pubdata.md) data -to L1, such as the L2->L1 messages, the L2->L1 logs, the bytecodes of the deployed smart contracts. - -We also [compress](https://github.com/matter-labs/zksync-era/blob/main/docs/specs/data_availability/compression.md) all -the data that we send to L1, to reduce the costs of posting it. - -By posting all the data to L1, we -can [reconstruct](https://github.com/matter-labs/zksync-era/blob/main/docs/specs/data_availability/reconstruction.md) the -state of the chain from the data on L1. This is a key security property of the rollup. - -:::info If the chain chooses not to post this data, it becomes a validium. This makes transactions there much cheaper, -but less secure. Because we use state diffs to post data, we can combine the rollup and validium features, by separating -storage slots that need to post data from the ones that don't. This construction combines the benefits of rollups and -validiums, and it is called -a [zkPorter](https://github.com/matter-labs/zksync-era/blob/main/docs/specs/data_availability/validium_zk_porter.md). -::: - -## Recreating L2 State From L1 Pubdata - -zkSync has developed a tool to help users validate L2 state data or “pubdata” submitted to L1. Here’s the basic flow of -the tool: - -## Basic Flow - -1. First, we need to filter all of the transactions to the L1 zkSync contract for only the `commitBlocks` transactions - where the proposed block has been referenced by a corresponding `executeBlocks` call (the reason for this is that a - committed or even proven block can be reverted but an executed one cannot). - -2. Once we have all the committed blocks that have been executed, we then will pull the transaction input and the - relevant fields - 1. Kinds of pubdata we’ll pull from transaction data: - - L2 to L1 Logs - - L2 to L1 Messages - - Published Bytecodes - - Compressed State Diffs - -The 2 main fields needed for state reconstruction are the **State Diffs** and **Contract Bytecodes**. - -## State Diffs - -State diffs are key value pairs that represent the 32 byte value stored at a particular storage slot for a particular -address. - -``` -naive way: ( storage_slot, address, value ) -actual: ( derived_key, value ) -compressed: ( derived_key or enumeration index, compressed_value ) -``` - -- `derived_key` is the `hash(storage_slot || address)` and -- `enumeration index` is the short hand ID that can be substituted for `derived_key` but only after its first write. The - deeper meaning is that an enumeration key is the leaf index in our storage Merkle tree. - -## Contract Bytecodes - -At a high level, contract bytecode is chunked into opcodes (which have a size of 8 bytes), assigned a 2 byte index, and -the newly formed byte sequence (indexes) are verified and sent to L1. - -This process is split into 2 different parts: (1) -[the server side operator](https://github.com/matter-labs/zksync-era/blob/main/core/lib/utils/src/bytecode.rs#L33) -handling the compression and (2) -[the system contract](https://github.com/matter-labs/era-contracts/blob/main/system-contracts/contracts/Compressor.sol#L42) -verifying that the compression is correct before sending to L1. - -The compressed bytecode makes it way up through `factoryDeps` and the hash of uncompressed bytecode is stored on -the `AccountStorage` contract so the hash of the uncompressed bytecode will be part of the state diffs diff --git a/content/40.zk-stack/concepts/data-availability/recreate-l2-state-from-l1-state-diffs.md b/content/40.zk-stack/concepts/data-availability/recreate-l2-state-from-l1-state-diffs.md deleted file mode 100644 index c0889441..00000000 --- a/content/40.zk-stack/concepts/data-availability/recreate-l2-state-from-l1-state-diffs.md +++ /dev/null @@ -1,52 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Recreating L2 state from L1 Pubdata | zkSync Docs ---- - -# Recreating L2 State from L1 Pubdata - -## Prerequisites - -> :warning: Note: Running the L1 pubdata tool will require approximately 500GB of memory and will take a few days to -> complete. - -This tool is written in nightly Rust; you can install Rust by following the official instructions -[here,](https://www.rust-lang.org/learn/get-started) and then running the following command to switch to the nightly -toolchain: - -```bash -rustup toolchain install nightly -``` - -1. Clone the [zksync-state-reconstruct](https://github.com/eqlabs/zksync-state-reconstruct) tool: - -```bash -git clone https://github.com/eqlabs/zksync-state-reconstruct -cd zksync-state-reconstruct -``` - -## Usage - -To start reconstructing the state, run the following command with any valid HTTP/HTTPS Ethereum JSON-RPC endpoint, for -example using <https://eth.llamarpc.com>. - -You can also use an Ethereum endpoint from [Alchemy,](https://www.alchemy.com/) [Infura](https://www.infura.io/) or any -other endpoint provider: - -```bash -cargo +nightly run -- reconstruct l1 --http-url https://eth.llamarpc.com -``` - -Here's what a successful start of the tool will look like in your terminal: - -![L2 state reconstruction start](../../../assets/images/l2-state-start.png) - -Here's what the tool will look like as it's running: - -![L2 state reconstruction running](../../../assets/images/l2-state-running.png) - -Once the tool has finished syncing, you will only be warned if the published L2 state is not the same as the -reconstructed L2 state. If the tool has finished syncing and you have not received any warnings, then the L2 state has -been successfully reconstructed. diff --git a/content/40.zk-stack/concepts/fee-mechanism.md b/content/40.zk-stack/concepts/fee-mechanism.md deleted file mode 100644 index 1883171a..00000000 --- a/content/40.zk-stack/concepts/fee-mechanism.md +++ /dev/null @@ -1,529 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Fee Mechanism | zkSync Docs ---- - -# zkSync Fee Mechanism - -This document will assume that you already know how gas & fees work on Ethereum. - -On Ethereum, all the computational, as well as storage costs, are represented via one unit: gas. Each operation costs a -certain amount of gas, which is generally constant (though it may change during -[upgrades](https://blog.ethereum.org/2021/03/08/ethereum-berlin-upgrade-announcement)). - -zkSync as well as other L2s have the issue which does not allow to adopt the same model as the one for Ethereum so -easily: the main reason is the requirement for publishing of the pubdata on Ethereum. This means that prices for L2 -transactions will depend on the volatile L1 gas prices and can not be simply hardcoded. - -## `gas_per_pubdata_limit` - -The transactions on zkSync depend on volatile L1 gas costs to publish the pubdata for batch, verify proofs, etc. For -this reason, zkSync-specific EIP712 transactions contain the `gas_per_pubdata_limit` field in them, denoting the maximum -price in _gas_ that the operator \_\_can charge from users for a single byte of pubdata. - -For Ethereum transactions which do not contain this field, it is enforced that the operator will not use a value larger -value than a certain constant. - -## Opcode Pricing - -Zero-knowledge proof operations tend to have different complexity compared to standard CPU terms. For instance, -`keccak256` is optimized for CPU performance but costs more to prove in zero-knowledge systems due to mathematical -constraints. - -This is why the zkSync operation prices may differ significantly from similar ones on Ethereum. - -## Intrinsic Costs - -Unlike Ethereum, where the intrinsic cost of transactions (`21000` gas) is used to cover the price of updating the -balances of the users, the nonce and signature verification, on zkSync these prices are _not_ included in the intrinsic -costs for transactions. - -This is due to the native support of account abstraction, where each account type may have their own transaction cost. -Some may also use more zk-friendly signature schemes or other kinds of optimizations to lower transaction costs for -their users. - -zkSync transactions costs are used mostly to cover these different, intrinsic zero-knowledge proving costs. These can -not be easily measured in code in real-time and are instead measured via testing and are hard coded. - -Let's look at some of these hard coded constants: - -## Batch Overhead - -In order to process the batch, the zkSync team has to pay the operational costs required by its proof. All of these -costs we call “batch overhead”. It consists of two parts: - -1. The L2 cost requirements for proving the circuits (denoted in L2 gas). -2. The L1 cost requirements for the proof verification as well as general batch processing (denoted in L1 gas). - -The protocol aggregates as many transactions as possible into a single batch. Each transaction proportionally pays for -the batch overhead in terms of how close the transaction brings the overall batch to being _sealed,_ i.e. closed and -prepared for proof verification and submission on L1. - -In the case of zkSync batches, here are the resources the protocol watches to decide when a batch is sealed: - -1. **Time.** The same as on Ethereum, the batch should generally not take too much time to be closed in order to provide - better UX. To represent the time needed we use a batch gas limit, note that it is higher than the gas limit for a - single transaction. -2. **Slots for transactions.** The bootloader has a limited number of slots for transactions, i.e. it can not take more - than a certain transactions per batch. -3. **The memory of the bootloader.** The bootloader needs to store the transaction’s ABI encoding in its memory & this - fills it up. In practical terms, it serves as a penalty for having transactions with large calldata/signatures in - case of custom accounts. -4. **Pubdata bytes.** In order to fully appreciate the gains from the storage diffs, i.e. the fact that changes in a - single slot happening in the same batch need to be published only once, we need to publish all the batch’s public - data only after the transaction has been processed. Right now, we publish all the data with the storage diffs as well - as L2→L1 messages, etc in a single transaction at the end of the batch. Most nodes have limit of 128kb per - transaction and so this is the limit that each zkSync batch should adhere to. - -Each transaction spends the batch overhead proportionally to how much of these resources it requires. - -Note that before the transaction is executed, the system can not know how many of these limited system resources the -transaction will actually take. Therefore, we need to charge for the worst case and provide the [refund](#refunds) at -the end of the transaction. - -## `baseFee` - -Like Ethereum, in order to protect us from DDoS attacks zkSync sets a limited `MAX_TRANSACTION_GAS_LIMIT` per -transaction. - -Since the computation costs are relatively constant for us, we use a `baseFee` equal to the real costs for us to compute -the proof for the corresponding 1 erg. Note that `gas_per_pubdata_limit` should be then set high enough to cover the -fees for the L1 gas needed to send a single pubdata byte on Ethereum. Under large L1 gas demands, -`gas_per_pubdata_limit` would also need be large. That means that `MAX_TRANSACTION_GAS_LIMIT/gas_per_pubdata_limit` -could become too low to allow for enough pubdata for common use cases. - -Therefore, to make common transactions always executable, we must enforce that the users are always able to send at -least `GUARANTEED_PUBDATA_PER_TX` bytes of pubdata in their transaction. Because of that, the needed -`gas_per_pubdata_limit` for transactions should never grow beyond `MAX_TRANSACTION_GAS_LIMIT/GUARANTEED_PUBDATA_PER_TX`. - -Setting a hard bound on `gas_per_pubdata_limit` also means that with the growth of L1 gas prices, the L2 `baseFee` will -have to grow as well. This ensures that `base_fee * gas_per_pubdata_limit = L1_gas_price * l1_gas_per_pubdata`. - -This mainly only impacts for computationally intensive tasks. For these kinds of transactions, we need to conservatively -charge a big upfront payment. However, it is compensated with a refund at the end of the transaction for all the -overspent gas. - -## Trusted Gas Limit - -While it was mentioned above that the `MAX_TRANSACTION_GAS_LIMIT` is needed to protect the operator from users stalling -the state keeper by using too much computation, in case the users may need to use a lot of pubdata. For instance, to -publish the bytecode of a new contract. - -In this case, the required gasLimit may go beyond the `MAX_TRANSACTION_GAS_LIMIT` since the contracts can be tens of -kilobytes in size. - -Therefore, all the new published contracts are included as separate part of the pubdata: the factory dependencies field -of the transaction. This way the operator knows how much pubdata will have to published and how much gas they will have -to spend on it. - -That’s why, to provide the better UX for users, the operator may provide the -[trusted gas limit](https://github.com/code-423n4/2023-10-zksync/blob/ef99273a8fdb19f5912ca38ba46d6bd02071363d/code/system-contracts/bootloader/bootloader.yul#L1137), -i.e. the limit which exceeds `MAX_TRANSACTION_GAS_LIMIT` assuming that the operator is sure that the excess gas will be -spent on the pubdata. - -## Refunds - -Another distinctive feature of the fee model used on zkSync is the abundance of refunds. Refunds can be issued for: - -- Unused limited system resources. -- Overpaid computation. - -This is needed because of the relatively big upfront payments we discussed earlier required in zkSync to provide DDoS -security. - -## Formulas and Constants for Calculating Fees - -After determining price for each opcode in gas according to the model above, the following formulas are to be used for -calculating `baseFee` and `gasPerPubdata` for a batch. - -### System-Wide Constants - -These constants are to be hardcoded and can only be changed via either system contracts/bootloader or VM upgrade. - -`BATCH_OVERHEAD_L1_GAS` (_L_1_O_)— The L1 gas overhead for a batch (proof verification, etc). - -`L1_GAS_PER_PUBDATA_BYTE` (_L_1_PUB_) — The number of L1 gas needed for a single pubdata byte. It is slightly higher -than 16 gas needed for publishing a non-zero byte of pubdata on-chain (currently the value of 17 is used). - -`BATCH_OVERHEAD_L2_GAS` (_EO_)— The constant overhead denominated in gas. This overhead is created to cover the -amortized costs of proving. - -`BLOCK_GAS_LIMIT` (_B_) — The maximum number of computation gas per batch. This is the maximal number of gas that can be -spent within a batch. This constant is rather arbitrary and is needed to prevent transactions from taking too much time -from the state keeper. It can not be larger than the hard limit of 2^32 of gas for VM. - -`MAX_TRANSACTION_GAS_LIMIT` (_TM_) — The maximal transaction gas limit. For _i_-th single instance circuit, the price of -each of its units is $SC_i = \lceil \frac{T_M}{CC_i} \rceil$ to ensure that no transaction can run out of these single -instance circuits. - -`MAX_TRANSACTIONS_IN_BATCH` (_TXM_) — The maximum number of transactions per batch. A constant in bootloader. Can -contain almost any arbitrary value depending on the capacity of batch that we want to have. - -`BOOTLOADER_MEMORY_FOR_TXS` (_BM_) — The size of the bootloader memory that is used for transaction encoding (i.e. -excluding the constant space, preallocated for other purposes). - -`GUARANTEED_PUBDATA_PER_TX` (_PG_) — The guaranteed number of pubdata that should be possible to pay for in one zkSync -batch. This is a number that should be enough for most reasonable cases. - -### Derived Constants - -Some of the constants are derived from the system constants above: - -`MAX_GAS_PER_PUBDATA` (_EPMax_) — the `gas_price_per_pubdata` that should always be enough to cover for publishing a -pubdata byte: - -$$ -EP_{Max} = \lfloor \frac{T_M}{P_G} \rfloor -$$ - -### Externally-Provided Batch Parameters - -`L1_GAS_PRICE` (_L_1_P_) — The price for L1 gas in ETH. - -`FAIR_GAS_PRICE` (_Ef_) — The “fair” gas price in ETH, that is, the price of proving one circuit (in Ether) divided by -the number we chose as one circuit price in gas. - -$$ -E_f = \frac{Price_C}{E_C} -$$ - -where _PriceC_ is the price for proving a circuit in ETH. Even though this price will generally be volatile (due to the -volatility of ETH price), the operator is discouraged to change it often, because it would volatile both volatile gas -price and (most importantly) the required `gas_price_per_pubdata` for transactions. - -Both of the values above are currently provided by the operator. Later on, some decentralized/deterministic way to -provide these prices will be utilized. - -### Determining `base_fee` - -When the batch opens, we can calculate the `FAIR_GAS_PER_PUBDATA_BYTE` (_EPf_) — “fair” gas per pubdata byte: - -$$ -EP_f = \lceil \frac{L1_p * L1_{PUB}}{E_f} \rceil -$$ - -There are now two situations that can be observed: - -I. - -$$ - EP_f > EP_{Max} -$$ - -This means that the L1 gas price is so high that if we treated all the prices fairly, then the number of gas required to -publish guaranteed pubdata is too high, i.e. allowing at least _PG_ pubdata bytes per transaction would mean that we -would to support _tx_._gasLimit_ greater that the maximum gas per transaction _TM_, allowing to run out of other finite -resources. - -If $EP_f > EP_{Max}$, then the user needs to artificially increase the provided _Ef_ to bring the needed -_tx_._gasPerPubdataByte_ to _EPmax_ - -In this case we set the EIP1559 `baseFee` (_Base_): - -$$ -Base = max(E_f, \lceil \frac{L1_P * L1_{PUB}}{EP_{max}} \rceil) -$$ - -Only transactions that have at least this high gasPrice will be allowed into the batch. - -II. - -Otherwise, we keep $Base* = E_f$ - -Note, that both cases are covered with the formula in case (1), i.e.: - -$$ -Base = max(E_f, \lceil \frac{L1_P * L1_{PUB}}{EP_{max}} \rceil) -$$ - -This is the base fee that will be always returned from the API via `eth_gasGasPrice`. - -### Overhead for a Transaction - -Let’s define by _tx_._actualGasLimit_ as the actual gasLimit that is to be used for processing of the transaction -(including the intrinsic costs). In this case, we will use the following formulas for calculating the upfront payment -for the overhead: - -$$ -S_O = 1/TX_M -$$ - -$$ -M_O(tx) = encLen(tx) / B_M -$$ - -$$ -E_{AO}(tx) = tx.actualGasLimit / T_M -$$ - -$$ -O(tx) = max(S_O, M_O(tx), E_O(tx)) -$$ - -where: - -_SO_ — is the overhead for taking up 1 slot for a transaction - -_MO_(_tx_) — is the overhead for taking up the memory of the bootloader - -_encLen_(_tx_) — the length of the ABI encoding of the transaction’s struct. - -_EAO_(_tx_) — is the overhead for potentially taking up the gas for single instance circuits. - -_O_(_tx_) — is the total share of the overhead that the transaction should pay for. - -Then we can calculate the overhead that the transaction should pay as the following one: - -$$ -L1_O(tx) = \lceil \frac{L1_O}{L1_{PUB}} \rceil * O(tx) \\ -E_O(tx) = E_O * O(tx) -$$ - -Where - -_L_1_O_(_tx_) — the number of L1 gas overhead (in pubdata equivalent) the transaction should compensate for gas. - -_EO_(_tx_) — the number of L2 gas overhead the transaction should compensate for. - -Then: - -_overhead_\__gas_(_tx_) = _EO_(_tx_) + _tx_._gasPerPubdata_ ⋅ _L_1_O_(_tx_) - -When a transaction is being estimated, the server returns the following gasLimit: - -_tx_._gasLimit_ = _tx_._actualGasLimit_ + _overhead_\__gas_(_tx_) - -Note, that when the operator receives the transaction, it knows only _tx_._gasLimit_. The operator could derive the -_overhead\_\_\_gas_(_tx_) and provide the bootloader with it. The bootloader will then derive _tx_._actualGasLimit_ = -_tx_._gasLimit_ − _overhead_\_\_gas*(\_tx*) and use the formulas above to derive the overhead that the user should’ve -paid under the derived _tx_._actualGasLimit_ to ensure that the operator does not overcharge the user. - -### _overhead_(_tx_) - -For the ease of integer calculation, we will use the following formulas to derive the _overhead_(_tx_): - -$B_O(tx) = E_O + tx.gasPerPubdataByte \cdot \lfloor \frac{L1_O}{L1_{PUB}} \rfloor$ - -$B_O$ denotes the overhead for batch in gas that the transaction would have to pay if it consumed the resources for -entire batch. - -Then, _overhead_\__gas_(_tx_) is the maximum of the following expressions: - -1. $S_O = \lceil \frac{B_O}{TX_M} \rceil$ -2. $M_O(tx) = \lceil \frac{B_O \cdot encodingLen(tx)}{B_M} \rceil$ -3. $E_O(tx) = \lceil \frac{B_O \cdot tx.gasBodyLimit}{T_M} \rceil$ - -### Deriving `overhead_gas(tx)` from `tx.gasLimit` - -The task that the operator needs to do is the following: - -Given the tx.gasLimit, it should find the maximal `overhead_gas(tx)`, such that the bootloader will accept such -transaction, that is, if we denote by _Oop_ the overhead proposed by the operator, the following equation should hold: - -$$ -O_{op} ≤ overhead_gas(tx) -$$ - -for the $tx.bodyGasLimit$ we use the $tx.bodyGasLimit$ = $tx.gasLimit − O_{op}$. - -There are a few approaches that could be taken here: - -- Binary search. However, we need to be able to use this formula for the L1 transactions too, which would mean that - binary search is too costly. -- The analytical way. This is the way that we will use and it will allow us to find such an overhead in O(1), which is - acceptable for L1->L2 transactions. - -Let’s rewrite the formula above the following way: - -$$ -O_{op} ≤ max(SO, MO(tx), EO(tx)) -$$ - -So we need to find the maximal $O_{op}$, such that $O_{op} ≤ max(S_O, M_O(tx), E_O(tx))$. Note, that it means ensuring -that at least one of the following is true: - -1. $O_{op} ≤ S_O$ -2. $O_{op} ≤ M_O(tx)$ -3. $O_{op} ≤ E_O(tx)$ - -So let’s find the largest _Oop_ for each of these and select the maximum one. - -- Solving for (1) - -$$ -O_{op} = \lceil \frac{B_O}{TX_M} \rceil -$$ - -- Solving for (2) - -$$ -O_{op} = \lceil \frac{encLen(tx) \cdot B_O}{B_M} \rceil -$$ - -- Solving for (3) - -This one is somewhat harder than the previous ones. We need to find the largest _O\_{op}_, such that: - -$$ -O_{op} \le \lceil \frac{tx.actualErgsLimit \cdot B_O}{T_M} \rceil \\ -$$ - -$$ -O_{op} \le \lceil \frac{(tx.ergsLimit - O_{op}) \cdot B_O}{T_M} \rceil \\ -$$ - -$$ -O_{op} ≤ \lceil \frac{B_O \cdot (tx.ergsLimit - O_{op})}{T_M} \rceil -$$ - -Note, that all numbers here are integers, so we can use the following substitution: - -$$ -O_{op} -1 \lt \frac{(tx.ergsLimit - O_{op}) \cdot B_O}{T_M} \\ -$$ - -$$ -(O_{op} -1)T_M \lt (tx.ergsLimit - O_{op}) \cdot B_O \\ -$$ - -$$ -O_{op} T_M + O_{op} B_O \lt tx.ergsLimit \cdot B_O + T_M \\ -$$ - -$$ -O_{op} \lt \frac{tx.ergsLimit \cdot B_O + T_M}{B_O + T_M} \\ -$$ - -Meaning, in other words: - -$$ -O_{op} = \lfloor \frac{tx.ergsLimit \cdot B_O + T_M - 1}{B_O + T_M} \rfloor -$$ - -Then, the operator can safely choose the largest one. - -### Discounts by the operator - -It is important to note that the formulas provided above are to withstand the worst-case scenario and these are the -formulas used for L1->L2 transactions (since these are forced to be processed by the operator). However, in reality, the -operator typically would want to reduce the overhead for users whenever it is possible. For instance, in the server, we -underestimate the maximal potential `MAX_GAS_PER_TRANSACTION`, since usually the batches are closed because of either -the pubdata limit or the transactions’ slots limit. For this reason, the operator also provides the operator’s proposed -overhead. The only thing that the bootloader checks is that this overhead is _not larger_ than the maximal required one. -But the operator is allowed to provide a lower overhead. - -### Refunds - -As you could see above, this fee model introduces quite some places where users may overpay for transactions: - -- For the pubdata when L1 gas price is too low -- For the computation when L1 gas price is too high -- The overhead, since the transaction may not use the entire batch resources they could. - -To compensate users for this, we will provide refunds for users. For all of the refunds to be provable, the counter -counts the number of gas that was spent on pubdata (or the number of pubdata bytes published). We will denote this -number by _pubdataused_. For now, this value can be provided by the operator. - -The fair price for a transaction is - -$$ -FairFee = E_f \cdot tx.computationalGas + EP_f \cdot pubdataused -$$ - -We can derive $tx.computationalGas = gasspent − pubdataused \cdot tx.gasPricePerPubdata$, where _gasspent_ is the number -of gas spent for the transaction (can be trivially fetched in Solidity). - -Also, the _FairFee_ will include the actual overhead for batch that the users should pay for. - -The fee that the user has actually spent is: - -$$ -ActualFee = gasspent \cdot gasPrice -$$ - -So we can derive the overpay as - -$$ -ActualFee − FairFee -$$ - -In order to keep the invariant of $gasUsed \cdot gasPrice = fee$ , we will formally refund -$\frac{ActualFee - FairFee}{Base}$ gas. - -At the moment, this counter is not accessible within the VM and so the operator is free to provide any refund it wishes -(as long as it is greater than or equal to the actual amount of gasLeft after the transaction execution). - -#### Refunds for repeated writes - -zkEVM is a statediff-based rollup, i.e. the pubdata is published not for transactions, but for storage changes. This -means that whenever a user writes into a storage slot, he incurs certain amount of pubdata. However, not all writes are -equal: - -- If a slot has been already written to in one of the previous batches, the slot has received a short id, which allows - it to require less pubdata in the state diff. -- Depending on the `value` written into a slot, various compression optimizations could be used and so we should reflect - that too. -- Maybe the slot has been already written to in this batch and so we don’t to charge anything for it. - -You can read more about how we treat the pubdata -[here](https://github.com/code-423n4/2023-10-zksync/blob/main/docs/Smart%20contract%20Section/Handling%20pubdata%20in%20Boojum.md). - -The important part here is that while such refunds are inlined (i.e. unlike the refunds for overhead they happen -in-place during execution and not after the whole transaction has been processed), they are enforced by the operator. -Right now, the operator is the one that decides what refund to provide. - -## Improvements in the upcoming releases - -The fee model explained above, while fully functional, has some known issues. These will be tackled with the following -upgrades. - -### The quadratic overhead for pubdata - -Note, that the computational overhead is proportional to the `tx.gasLimit` and the amount of funds the user will have to -pay is proportional to the L1 gas price (recall the formula of `B_O`). We can roughly express the transaction overhead -from computation as `tx.gasLimit * L1_GAS_PRICE * C` where `C` is just some constant. Note, that since a transaction -typically contains some storage writes, and its -`tx.gasLimit = gasSpentOnCompute + pubdataPublished * gasPricePerPubdata`, `tx.gasLimit` is roughly proportional to -`gasPricePerPubdata` and so it is also proportional to `L1_GAS_PRICE`. - -This means that formula `tx.gasLimit * L1_GAS_PRICE * C` becomes _quadratic_ to the `L1_GAS_PRICE`. - -### `gasUsed` depends to `gasLimit` - -While in general it shouldn’t be the case assuming the correct implementation of [refunds](#refunds), in practice it -turned out that the formulas above, while robust, estimate for the worst case which can be very difference from the -average one. In order to improve the UX and reduce the overhead, the operator charges less for the execution overhead. -However, as a compensation for the risk, it does not fully refund for it. - -### L1->L2 transactions do not pay for their execution on L1 - -The `executeBatches` operation on L1 is executed in `O(N)` where N is the number of priority ops that we have in the -batch. Each executed priority operation will be popped and so it incurs cost for storage modifications. As of now, we do -not charge for it. - -## zkEVM Fee Components (Revenue & Costs) - -- On-Chain L1 Costs - - L1 Commit Batches - - The commit batches transaction submits pubdata (which is the list of updated storage slots) to L1. The cost of a - commit transaction is calculated as `constant overhead + price of pubdata`. The `constant overhead` cost is evenly - distributed among L2 transactions in the L1 commit transaction, but only at higher transaction loads. As for the - `price of pubdata`, it is known how much pubdata each L2 transaction consumed, therefore, they are charged - directly for that. Multiple L1 batches can be included in a single commit transaction. - - L1 Prove Batches - - Once the off-chain proof is generated, it is submitted to L1 to make the rollup batch final. Currently, each proof - contains only one L1 batch. - - L1 Execute Batches - - The execute batches transaction processes L2 -> L1 messages and marks executed priority operations as such. - Multiple L1 batches can be included in a single execute transaction. - - L1 Finalize Withdrawals - - While not strictly part of the L1 fees, the cost to finalize L2 → L1 withdrawals are covered by Matter Labs. The - finalize withdrawals transaction processes user token withdrawals from zkEVM to Ethereum. Multiple L2 withdrawal - transactions are included in each finalize withdrawal transaction. -- On-Chain L2 Revenue - - L2 Transaction Fee - - This fee is what the user pays to complete a transaction on zkEVM. It is calculated as - `gasLimit x baseFeePerGas - refundedGas x baseFeePerGas`, or more simply, `gasUsed x baseFeePerGas`. -- Profit = L2 Revenue - L1 Costs - Off Chain Infrastructure Costs diff --git a/content/40.zk-stack/concepts/finality.md b/content/40.zk-stack/concepts/finality.md deleted file mode 100644 index e455e95b..00000000 --- a/content/40.zk-stack/concepts/finality.md +++ /dev/null @@ -1,42 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Finality | zkSync Docs ---- - -# Finality - -## Finality on Ethereum - -Finality in blockchain systems refers to the time taken from sending a transaction to when the transaction can be -considered settled; and therefore cannot be altered, reversed, or canceled. At the time of writing, finality on the -Ethereum layer is considered to occur after 2 [epochs](https://info.etherscan.com/epoch-in-ethereum/) or ~13 minutes. - -## Finality on zkSync Era - -As with other L2 rollup systems, finality and security on zkSync Era is tied to the finality and security of the -underlying L1 Ethereum chain. Finality on zkSync Era is the time taken from sending a transaction to when the L1 smart -contract updates the L2 state. The process has a few steps: - -- Fill a batch with transactions (usually takes a few minutes). -- Commit the batch to Ethereum. -- Generate a proof for the whole batch (usually takes around an hour). -- Submit the proof for verification by the Ethereum smart contract. -- Finalize the batch on Ethereum (delayed by ~21 hours as a security measure during the alpha phase). - -When this process is complete, around ~24 hours in total, the batch is as final as any Ethereum transaction included in -the same Ethereum block. - -:::info Research into validity proofs have seen tremendous advances in recent years. As the field evolves, we expect to -see further improvements in proof generation, which will likely result in lower finality times. ::: - -## Instant confirmations - -Even though zkSync Era finality is usually around 24 hours, users may consider transactions submitted to zkSync Era as -having instant confirmation. Transaction details are instantly displayed in the UI and API (although they are marked as -unconfirmed), and the transferred assets can be used immediately to make further transfers (which might even end up in -the same zkSync Era batch). - -More cautious users may prefer to wait for full finality, or for any of the intermediate steps described above, before -considering the assets as received. diff --git a/content/40.zk-stack/concepts/hyperchains-hyperscaling.md b/content/40.zk-stack/concepts/hyperchains-hyperscaling.md deleted file mode 100644 index 9ef509ce..00000000 --- a/content/40.zk-stack/concepts/hyperchains-hyperscaling.md +++ /dev/null @@ -1,334 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Hyperchains/Hyperscaling | zkSync Docs ---- - -# Hyperchains/Hyperscaling - -## Scaling Blockchains - -Ethereum, currently processing around 12 transactions per second, must scale to handle millions of transactions for a -future of global on-chain financial activities. Achieving this in a decentralized structure poses significant -challenges. Various solutions, including Polkadot, Cosmos, Near, and Eth 2.0, have been explored with multi-chain or -shard architectures, but full trust remains an issue. The widely accepted solution for these challenges lies in -zero-knowledge proofs, offering cryptographic security. Combined with the DA layer and ZK Rollups, these can create a -secure, scalable ecosystem, making Ethereum accessible to all. - -## What are Hyperchains? - -Hyperchains are fractal-like instances of zkEVM running in parallel and with the common settlement on the L1 mainnet. -The name Hyperbridge comes from the traditional web, where users can navigate websites using hyperlinks. Similarly, our -rollups will be connected with Hyperbridges. - -<div align="center"> - -![hyperbridges](../../assets/images/hyperbridges.png) Gray lines show proofs, orange lines the hyperbridges, which -automatically connect all blue chains. - -</div> - -Using Hyperchains with a shared bridge contract on L1, and native Hyperbridges between the rollups solves a lot of -problems in other architectures. - -1. Rollups have validating bridges that are trustless. -2. Hyperbridges can easily burn and mint assets for transfers between members of the ecosystem. -3. The L1 serves as a single source of truth, so the rollups cannot hard fork. -4. The ecosystem can coordinate a hard fork together in case a vulnerability is found using a governance framework on - L1, similar to how the L1 would react to a vulnerability. - -Hyperchains can be developed and permissionlessly deployed by anyone. However, to remain trusted and fully -interoperable, each Hyperchain must be powered by the same zkEVM engine available on the ZK Stack (and currently -powering the first hyperchain, zkSync Era). All the ZKP circuits will thus remain 100% identical, letting Hyperchains -fully inherit their security from L1, no matter who deployed them. This ensures zero additional trust/security -assumptions. - -Hyperchains will be implemented following the modular approach – using the ZK Stack developers can individually pick -different components of their blockchains or implement their own ones (except the zkEVM core, for the reasons explained -above). See [Modularity: Hyperchain Customization](#modularity-hyperchain-customization) below for more details. - -### How Hyperbridges work - -The Hyperbridge itself will be a set of smart contracts, verifying Merkle proofs of the transactions happening on other -chains. The original asset is locked in the shared bridge contract on L1. This means liquidity is unified across the -ecosystem. - -Hyperbridging will consist of 7 steps. - -1. A Hyperchain initiates the cross-hyperchain transaction. -2. The sending Hyperchain settles its proof onto L1. -3. As the proof is settled, it updates the Transaction Root. This Root is a commitment to all the Hyperbridge - transactions happening inside the ecosystem. -4. The receiving Hyperchain imports this Transaction Root via its consensus mechanism, similarly to how L1→L2 messages - are imported today. -5. A relayer sends the transaction and a Merkle Proof connecting it to the Transaction Root to the receiving Hyperchain. -6. The transaction and Merkle proof are verified against the Transaction Root. If the proof is correct, the transaction - is executed and the relayer is rewarded. -7. The receiving Hyperchain settles its proof, where the imported Transaction Root is also verified. - -<div align="center"> - -![hyperscaling](../../assets/images/hyperscalingBridgingFull.png) - -</div> - -There are three types of bridges in this ecosystem. The enshrined L1-L2 bridge, the -[zkPorter](https://blog.matter-labs.io/zkporter-a-breakthrough-in-l2-scaling-ed5e48842fbf) shard bridges, and the -hyperbridges will all operate with a similar set of interfaces. - -ZkPorter bridges will only appear for developers, as they connect the shards of the zkPorter VM they are atomic and -asynchronous. Users will not notice them, it will be like using any other chain. - -Hyperbridges technically will be similar to L2→L1 bridges, they will be asynchronous and not atomic. However, with the -help of Account Abstraction, external relayers, and lower fees on rollups, the users will not have to initiate the call -on the destination chain. This means the user experience will feel like an L1 → L2 bridge. - -Besides cross-hyperchain calls, it will be also possible to execute cross-hyperchain views inside transactions, -accessing arbitrary data from other chains in the ecosystem. - -### Hyperchain User Experience - -As we aim to onboard billions of users to Web3, user experience has to be a priority. Users will have wallets on -different chains, unified by cross-hyperchain wallet management. This is still a hot research topic, as seen in -Vitalik's [post](https://vitalik.eth.limo/general/2023/06/20/deeperdive.html). These solutions will be integrated into -Account Abstractions, which are natively supported on ZK Stack powered chains. - -The users' wallets will show all of their assets, and relayers will handle bridging, burning, and minting assets to be -used at the destination. Hyperchains will have unique identifiers that, when paired with ENS, will make recipient -addresses look like email addresses. Of course, the default will be the use of traditional Ethereum addresses together -with the Hyperchain identifiers. - -Bridging will be part of the protocol, so it will be built into the wallet alongside transfers. Bridging time will be -the proof settlement time, which will be 1-15 minutes, depending on the Hyperchain. Due to the fact that only relayers -will be required as external infrastructure, the cost of the bridging will be minimal, comparable to the gas fees. - -**Imagine a cross-hyperchain Uniswap transaction.** You want to swap Ethereum for DAI. You start the transaction with -your wallet. Then the relayer delivers 1 ETH to a Uniswap chain, and the ETH is swapped for DAI. Finally, a relayer -transfers the DAI back to your original chain. All three steps are part of the same transaction. All of this in a matter -of minutes and feels as if you have not left your original chain (except for a somewhat longer confirmation time). - -<div align="center"> - -![hyperscalingUniswap](../../assets/images/hyperscalingUniswap.png) - -</div> - -When setting up wallets on cheaper chains ([validiums](https://ethereum.org/en/developers/docs/scaling/validium/)), they -will have to trust the hosting organization to not lose their funds. Unlike centralized exchanges, these funds cannot be -stolen, only frozen, which hurts the hosting organization as well! The risks will be made clear in the wallet. - -## Proof Aggregation - -Validity proofs provide the basic scalability to the ecosystem. Having a single blockchain is like running a single CPU. -Having multiple Hyperchains run simultaneously provides parallelization. The proof aggregator is the mechanism that -gives the ecosystem its hyperscalability. If every Hyperchain wanted to settle their proofs to L1 independently, the -total load on the L1 would still be proportional to the total number of Hyperchains. So the proofs of the Hyperchains -are aggregated, settling all of them together on L1 in a single proof. There are multiple options for this. - -### Simple Proof Aggregation - -Simple proof aggregation treats the proofs of different Hyperchains as independent statements that can be verified -together on L1. Unfortunately, the simple aggregation mechanism does not allow fast messaging as proofs are settled -infrequently on L1 to save gas fees. - -<div align="center"> - -![HyperscalingAggregation](../../assets/images/hyperscalingAggregation.png) - -</div> - -### L3s - -Another alternative for aggregation is layering. Hyperchains can settle their proof on an L2 Hyperchain, becoming L3s. -L3s settling on the same L2 will have faster messaging between each other and will have cheap atomicity via transactions -forced through the L2, and interoperability will be preserved with the wider ecosystem. This is a particularly good -solution for Validiums, as they don’t send data to the L1. The only downside is that there is a higher chance of -reversion if the L2 reverts. - -Here proof aggregation happens via the L2, as the proofs of different L2 blocks are aggregated when settling on L1. This -method is ultimately not scalable, as the L2's VM will be a bottleneck for proof verification. The L2's VM will also -require a full consensus mechanism, meaning long-term storage, transaction verification, etc. - -<div align="center"> - -![hyperscalingL3Fast2Blocks](../../assets/images/hyperscalingL3Fast2Blocks.png) - -</div> - -### Layered Aggregation - -Layered Aggregation combines the benefits of L3s with the benefits of simple aggregation. The L2's VM is replaced by the -minimal program required to run L3 with messaging, and this is proven in a specialized proof that allows aggregation. -This program tracks the State Root of the participating rollups, as well as the Transaction Root. The Transaction Root -will be imported from and settled inside this specialized proof. Compared to the L2's VM this solution is more scalable, -and will only need a lightweight consensus mechanism. - -<div align="center"> - -![hyperscalingLayeredAggregation](../../assets/images/hyperscalingLayeredAggregation.png) - -</div> - -### Economic Guarantees - -To hyperbridge trustlessly the proof containing the message has to be settled, and this can only happen after the proof -is generated (which will take up to a few minutes). For some chains, faster interoperability will be needed, and this is -possible with economic guarantees. The transaction root can be calculated outside the proof and then imported. This is -not as secure as importing the transaction root from a proof - even a single invalid transaction means that all of the -participating rollups will have to revert, as valid proofs cannot be generated. So we are building this solution as an -optional add-on, and not part of the core protocol. - -For these rollups proof generation and settlement still happens as usual. This means the transaction root will have to -be calculated inside the L2 or specialized proof. This means this add-on can only work for L3s or for the Layered -Aggregator. - -<div align="center"> - -![hyperscalingFastEconomic](../../assets/images/hyperscalingFastEconomic.png) - -</div> - -### Sovereignty - -All Hyperchains will be sovereign in the ecosystem. This means two things. - -1. Proof aggregation will be optional, Hyperchains can choose to not participate. In this case, they can settle their - proofs directly to Ethereum for a much larger fee. Aggregation will also be decentralized and widely accessible, - meaning the hardware requirements to run a prover will be as low as possible. - -<div align="center"> - -![hyperscalingSovereignty](../../assets/images/hyperscalingSovereignty.png) - -</div> - -2. In addition, Hyperchains will be able to permissionlessly join and exit the ecosystem, adding or removing all their - assets to the common pool in the Shared Bridge. Joining is self-explanatory, everyone will have the right to boot up - new Hyperchains and join the ecosystem in a Chain Factory contract. - -Exiting will usually not be a similarly wise decision, as interoperability will be lost with other Hyperchains. However, -the ecosystem could sometimes upgrade due to governance, and in this case, it is imperative that each Hyperchain have -the right to rage quit. In this case, there will be a mandatory upgrade period during which the Hyperchains that -disagree with the upgrade can exit alone, or together in a coordinated fashion. - -### Feature comparison - -We look at the comparisons that different aggregator mechanisms enable. - -<div align="center"> - -| | Aggregation | L3s | Layered Aggregation | -| ------------------------ | ----------- | ----------------- | --------------------- | -| Fast Messaging | No | Yes | Yes | -| Scales | Yes | No | Yes | -| Consensus Mechanism | None | L2 Full Consensus | Lightweight Consensus | -| Instant Messaging Add-on | No | Yes | Yes | -| Sovereign | Yes | Yes | Yes | - -</div> - -## Modularity: Hyperchain Customization - -The main customization options to be provided by -[ZK Stack](https://blog.matter-labs.io/introducing-the-zk-stack-c24240c2532a) are explained below. Developers are of -course free to implement their own components and customizations. - -### Sequencing transactions - -- **Centralized sequencer** - In this mode, there will be a single centralized operator with a conventional REST API to - accept transactions from users. The operator must be trusted to maintain liveness, not to abuse MEV, and not to allow - reorgs of unfinalized transactions, so the operator’s reputation will play a big role. The biggest advantage of this - option is that it can provide the lowest possible latency to confirm transactions (<100ms), which is critical for use - cases such as HFT. ZkSync Era will run in this mode until it is fully decentralized, so we will have battle-tested - server code available for developers early on. -- **Decentralized sequencer** - In this mode, a Hyperchain will coordinate on what transactions are included in a block - using a consensus algorithm. It can be any algorithm, so developers can reuse existing implementations (e.g. - Tendermint or HotStuff with permissionless dPoS). But we can also take advantage of the fact that finality checkpoints - are guaranteed by the underlying L1, and implement an algorithm that is simpler and boasts higher performance. ZkSync - Era will switch to this option as soon as the consensus implementation is ready and will make its code available to - the Hyperchain developers. -- **Priority queue** - This simply means the absence of any sequencer: all transactions can be submitted in batches via - the priority queue from an underlying L2 or even L1 chain, taking advantage of their stronger censorship resistance. - It might be especially interesting for special-purpose governance protocols (e.g. on-chain voting). It’s worth noting - that the priority queue will always be available as an escape-hatch mechanism (even if a centralized or decentralized - sequencer is employed), to protect users against censorship by a malicious sequencer. -- **External protocol** - The sequencing of the Hyperchain is freely customizable, so external protocols such as Shared - Sequencers and Shared Builders can also be used. - -### Hyperchains and Data Availability (DA) - -Each Hyperchain can manage its data availability (DA) policy using a smart contract interface. It can use one of the -options described below or some more complex logic. For example, to combine zkPorter and validium, the DA will require -both a quorum of the signatures from the guardians and a number of signatures from the data availability committee. - -- **zk-Rollup** - This is our default recommendation policy: the values of every changed storage slot at the end of the - block must be published as calldata on L1. Note that repeated changes (or back-and-forth changes that result in no net - difference) are not posted. It means if a batch contains 100 ETH/DAI swaps on the same DEX then pubdata costs will be - partially amortized over all such swaps. A Hyperchain working in this mode strictly inherits full security and - censorship-resistance properties from Ethereum. The implementation of zkRollup in output mode is already available in - zkSync Era and the ZK Stack. -- **zkPorter** - it's explained in detail in - **[this post](https://blog.matter-labs.io/zkporter-a-breakthrough-in-l2-scaling-ed5e48842fbf)**. We already have a - working zkPorter guardian testnet, which we are preparing to open source. We expect zkPorter to be popular with users - willing to take higher security risks in exchange for really cheap transactions, which will be extremely useful until - Danksharding is implemented, and even afterward for specialized use cases. Hyperchain developers will be able to - either tap into the DA from zkSync main zkPorter implementation or bootstrap their own guardian network (which could - be interesting for large existing online communities such as Reddit or Twitter), or use external DA solutions (e.g. - EigenDA). -- **Validium** - Being true to our **[values](https://github.com/zksync/credo)**, we generally - **[discourage](https://blog.matter-labs.io/zkrollup-vs-validium-starkex-5614e38bc263)** mainstream users from trusting - validium-based solutions. However, there are use cases where using validium is fully justified, e.g. enterprise chains - that require both auditability and privacy (since the data availability in such cases is controlled by a central - party, it is trivial to keep such a Hyperchain private by simply withholding data). Since validium is essentially a - simpler case of a zkPorter, developers can easily deploy Hyperchains based on this policy. -- **Based zkRollup** - This policy will require publishing full transaction inputs instead of final storage updates. - Trustless state reconstruction and the DA costs in this case will be 100% identical to optimistic rollups (but with - all the benefits of a zkRollup of course, including better security and faster exits). The implementation of this - option is easily derived from the implementation of the normal zkRollup. It can be explored by application-specific - chains where tx inputs are short but might lead to a lot of changes in data (for example, performing financial - simulations). -- **zkRollup (self-hosted)** - An extremely interesting option! In this mode, users self-host the data for all the - accounts they own. To enforce this, user confirmation signatures are required to make any changes – which means, you - cannot send funds directly to another user. Instead, you will burn the funds and create a proof of this burn, which - you can provide to your recipient via an off-chain channel. The recipient will then redeem them to their account. This - might sound complicated, but it’s easy to construct a nice UI that will abstract away the technical complexities, - making it practically indistinguishable from sending and receiving funds on Ethereum (it will automatically redeem all - received assets the moment the user intends to spend funds, requiring no extra clicks). But here comes a miracle: a - self-hosted zkRollup can be happy with as little as 5 bytes per user interaction that includes a batch of arbitrary - many transactions! This makes sharded Ethereum infinitely scalable for any practical purposes in the zkRollup mode - (i.e. 100% secure and censorship-resistant). This is a way to onboard every single person on Earth to Ethereum with - zero security compromise. A great thing about this approach is also that it’s fully compatible with our zkEVM - implementation, but can nonetheless offer privacy to the users. The implementation is non-trivial, so we expect it to - come last among all the other options. At the same time, it’s simpler and much more powerful than alternative - approaches like Adamantium. - -### Logical state partitions in ZK Porters - -Each Hyperchain can have one or more logical partitions that are part of the same state but live in separate subtrees -and enforce different data availability policies, which can however interoperate synchronously. - -Synchronicity is important as it enables atomic transactions between partitions, unlocking several unique use cases: - -- Transparently reading the state of another partition. -- Using flash loans between the partitions. - -One prominent example of this is a combination of -**[zkRollup + zkPorter](https://blog.matter-labs.io/zkporter-a-breakthrough-in-l2-scaling-ed5e48842fbf)** (which will be -part of the zkSync Era): - -![hyperscalingZKPorter](../../assets/images/hyperscalingZKPorter.png) - -### Privacy - -Hyperchains can add privacy in a number of ways: - -1. **Validium**. For a Hyperchain running in the validium mode, privacy to the outer world is achieved out of the box as - long as the operator keeps the block data secret. This might be an interesting option for enterprise users. -2. **Privacy protocols**. To implement user-level privacy, a specialized L3 protocol is required. Projects such as Aztec - or Tornado can be implemented either directly on zkSync Era (taking advantage of account abstraction and cheap - recursive ZKP verification on zkSync), or they can opt into standalone special-purpose Hyperchains for more - flexibility. -3. **[Self-hosted Rollups](https://ethresear.ch/t/account-based-anonymous-rollup/6657),** based on user-maintained data - availability and self-proved off-chain state transitions, will offer ultimate privacy and unlimited scalability in - the long term. diff --git a/content/40.zk-stack/concepts/l1_l2_communication.md b/content/40.zk-stack/concepts/l1_l2_communication.md deleted file mode 100644 index 217436ca..00000000 --- a/content/40.zk-stack/concepts/l1_l2_communication.md +++ /dev/null @@ -1,266 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: L1 <-> L2 Communication | zkSync Docs ---- - -# L1 <-> L2 Communication - -## Deposits and Withdrawals - -The zkEVM supports general message passing for L1<->L2 communication. Proofs are settled on L1, so core of this process -is the [L2->L1] message passing process. [L1->L2] messages are recorded on L1 inside a priority queue, the sequencer -picks it up from here and executes it in the zkEVM. The zkEVM sends an L2->L1 message of the L1 transactions that it -processed, and the rollup's proof is only valid if the processed transactions were exactly right. - -There is an asymmetry in the two directions however, in the L1->L2 direction we support starting message calls by having -a special transaction type called L1 transactions. In the L2->L1 direction we only support message passing. - -In particular, deposits and withdrawals of ether also use the above methods. For deposits the L1->L2 transaction is sent -with empty calldata, the recipients address and the deposited value. When withdrawing, an L2->L1 message is sent. This -is then processed by the smart contract holding the ether on L1, which releases the funds. - -## L2→L1 communication - -The L2→L1 communication is more fundamental than the L1→L2 communication, as the second relies on the first. L2→L1 -communication happens by the L1 smart contract verifying messages alongside the proofs. The only “provable” part of the -communication from L2 to L1 are native L2→L1 logs emitted by VM. These can be emitted by the `to_l1` -[opcode](https://github.com/code-423n4/2023-10-zksync/blob/main/docs/Smart%20contract%20Section/System%20contracts%20bootloader%20description.md). -Each log consists of the following fields: - -```solidity -struct L2Log { - uint8 l2ShardId; - bool isService; - uint16 txNumberInBatch; - address sender; - bytes32 key; - bytes32 value; -} - -``` - -Where: - -- `l2ShardId` is the id of the shard the opcode was called (it is currently always 0). -- `isService` a boolean flag that is not used right now -- `txNumberInBatch` the number of the transaction in the batch where the log has happened. This number is taken from the - internal counter which is incremented each time the `increment_tx_counter` is - [called](https://github.com/code-423n4/2023-10-zksync/blob/main/docs/Smart%20contract%20Section/System%20contracts%20bootloader%20description.md). -- `sender` is the value of `this` in the frame where the L2→L1 log was emitted. -- `key` and `value` are just two 32-byte values that could be used to carry some data with the log. - -The hashed array of these opcodes is then included into the -[batch commitment](https://github.com/matter-labs/era-contracts/blob/f06a58360a2b8e7129f64413998767ac169d1efd/ethereum/contracts/zksync/facets/Executor.sol#L493). -Because of that we know that if the proof verifies, then the L2→L1 logs provided by the operator were correct, so we can -use that fact to produce more complex structures. Before Boojum such logs were also Merklized within the circuits and so -the Merkle tree’s root hash was included into the batch commitment also. - -### Important system values - -Two `key` and `value` fields are enough for a lot of system-related use-cases, such as sending timestamp of the batch, -previous batch hash, etc. They were and are used -[used](https://github.com/code-423n4/2023-10-zksync/blob/ef99273a8fdb19f5912ca38ba46d6bd02071363d/code/system-contracts/contracts/SystemContext.sol#L438) -to verify the correctness of the batch's timestamps and hashes. You can read more about block processing -[here](https://github.com/code-423n4/2023-10-zksync/blob/main/docs/Smart%20contract%20Section/Batches%20&%20L2%20blocks%20on%20zkSync.md). - -### Long L2→L1 messages & bytecodes - -However, sometimes users want to send long messages beyond 64 bytes which `key` and `value` allow us. But as already -said, these L2→L1 logs are the only ways that the L2 can communicate with the outside world. How do we provide long -messages? - -Let’s add an `sendToL1` method in L1Messenger, where the main idea is the following: - -- Let’s submit an L2→L1 log with `key = msg.sender` (the actual sender of the long message) and - `value = keccak256(message)`. -- Now, during batch commitment the operator will have to provide an array of such long L2→L1 messages and it will be - checked on L1 that indeed for each such log the correct preimage was provided. - -A very similar idea is used to publish uncompressed bytecodes on L1 (the compressed bytecodes were sent via the long -L1→L2 messages mechanism as explained above). - -Note, however, that whenever someone wants to prove that a certain message was present, they need to compose the L2→L1 -log and prove its presence. - -## Priority operations - -Also, for each priority operation, we would send its hash and it status via an L2→L1 log. On L1 we would then -reconstruct the rolling hash of the processed priority transactions, allowing to correctly verify during the -`executeBatches` method that indeed the batch contained the correct priority operations. - -Importantly, the fact that both hash and status were sent, it made it possible to -[prove](https://github.com/code-423n4/2023-10-zksync/blob/ef99273a8fdb19f5912ca38ba46d6bd02071363d/code/contracts/ethereum/contracts/bridge/L1ERC20Bridge.sol#L255) -that the L2 part of a deposit has failed and ask the bridge to release funds. - -## L1→L2 Messaging - -The transactions on zkSync can be initiated not only on L2, but also on L1. There are two types of transactions that can -be initiated on L1: - -- Priority operations. These are the kind of operations that any user can create. -- Upgrade transactions. These can be created only during upgrades. - -### Prerequisites - -Please read the full -[article](https://github.com/code-423n4/2023-10-zksync/blob/main/docs/Smart%20contract%20Section/System%20contracts%20bootloader%20description.md) -on the general system contracts / bootloader structure as well as the pubdata structure with Boojum system to understand -[the difference](https://github.com/code-423n4/2023-10-zksync/blob/main/docs/Smart%20contract%20Section/Handling%20pubdata%20in%20Boojum.md) -between system and user logs. - -## Priority operations - -### Initiation - -A new priority operation can be appended by calling the -[requestL2Transaction](https://github.com/code-423n4/2023-10-zksync/blob/ef99273a8fdb19f5912ca38ba46d6bd02071363d/code/contracts/ethereum/contracts/zksync/facets/Mailbox.sol#L236) -method on L1. This method will perform several checks for the transaction, making sure that it is processable and -provides enough fee to compensate the operator for this transaction. Then, this transaction will be -[appended](https://github.com/code-423n4/2023-10-zksync/blob/ef99273a8fdb19f5912ca38ba46d6bd02071363d/code/contracts/ethereum/contracts/zksync/facets/Mailbox.sol#L369C1-L369C1) -to the priority queue. - -### Bootloader - -Whenever an operator sees a priority operation, it can include the transaction into the batch. While for normal L2 -transaction the account abstraction protocol will ensure that the `msg.sender` has indeed agreed to start a transaction -out of this name, for L1→L2 transactions there is no signature verification. In order to verify that the operator -includes only transactions that were indeed requested on L1, the bootloader -[maintains](https://github.com/code-423n4/2023-10-zksync/blob/ef99273a8fdb19f5912ca38ba46d6bd02071363d/code/system-contracts/bootloader/bootloader.yul#L970) -two variables: - -- `numberOfPriorityTransactions` (maintained at `PRIORITY_TXS_L1_DATA_BEGIN_BYTE` of bootloader memory) -- `priorityOperationsRollingHash` (maintained at `PRIORITY_TXS_L1_DATA_BEGIN_BYTE + 32` of the bootloader memory) - -Whenever a priority transaction is processed, the `numberOfPriorityTransactions` gets incremented by 1, while -`priorityOperationsRollingHash` is assigned to `keccak256(priorityOperationsRollingHash, processedPriorityOpHash)`, -where `processedPriorityOpHash` is the hash of the priority operations that has been just processed. - -Also, for each priority transaction, we -[emit](https://github.com/code-423n4/2023-10-zksync/blob/ef99273a8fdb19f5912ca38ba46d6bd02071363d/code/system-contracts/bootloader/bootloader.yul#L966) -a user L2→L1 log with its hash and result, which basically means that it will get Merklized and users will be able to -prove on L1 that a certain priority transaction has succeeded or failed (which can be helpful to reclaim your funds from -bridges if the L2 part of the deposit has failed). - -Then, at the end of the batch, we -[submit](https://github.com/code-423n4/2023-10-zksync/blob/ef99273a8fdb19f5912ca38ba46d6bd02071363d/code/system-contracts/bootloader/bootloader.yul#L3819) -and 2 L2→L1 log system log with these values. - -### Batch commit - -During block commit, the contract will remember those values, but not validate them in any way. - -### Batch execution - -During batch execution, we would pop `numberOfPriorityTransactions` from the top of priority queue and -[verify](https://github.com/code-423n4/2023-10-zksync/blob/ef99273a8fdb19f5912ca38ba46d6bd02071363d/code/contracts/ethereum/contracts/zksync/facets/Executor.sol#L282) -that their rolling hash does indeed equal to `priorityOperationsRollingHash`. - -## Upgrade transactions - -### Initiation - -Upgrade transactions can only be created during a system upgrade. It is done if the `DiamondProxy` delegatecalls to the -implementation that manually puts this transaction into the storage of the DiamondProxy. Note, that since it happens -during the upgrade, there is no “real” checks on the structure of this transaction. We do have -[some validation](https://github.com/code-423n4/2023-10-zksync/blob/ef99273a8fdb19f5912ca38ba46d6bd02071363d/code/contracts/ethereum/contracts/upgrades/BaseZkSyncUpgrade.sol#L175), -but it is purely on the side of the implementation which the `DiamondProxy` delegatecalls to and so may be lifted if the -implementation is changed. - -The hash of the currently required upgrade transaction is -[stored](https://github.com/code-423n4/2023-10-zksync/blob/ef99273a8fdb19f5912ca38ba46d6bd02071363d/code/contracts/ethereum/contracts/zksync/Storage.sol#L138) -under `l2SystemContractsUpgradeTxHash`. - -We will also track the batch where the upgrade has been committed in the `l2SystemContractsUpgradeBatchNumber` -[variable](https://github.com/code-423n4/2023-10-zksync/blob/ef99273a8fdb19f5912ca38ba46d6bd02071363d/code/contracts/ethereum/contracts/zksync/Storage.sol#L141). - -We can not support multiple upgrades in parallel, i.e. the next upgrade should start only after the previous one has -been complete. - -### Bootloader - -The upgrade transactions are processed just like with priority transactions, with only the following differences: - -- We can have only one upgrade transaction per batch & this transaction must be the first transaction in the batch. -- The system contracts upgrade transaction is not appended to `priorityOperationsRollingHash` and doesn't increment - `numberOfPriorityTransactions`. Instead, its hash is calculated via a system L2→L1 log _before_ it gets executed. - Note, that it is an important property. More on it [below](#security-considerations). - -### Commit - -After an upgrade has been initiated, it will be required that the next commit batches operation already contains the -system upgrade transaction. It is -[checked](https://github.com/code-423n4/2023-10-zksync/blob/ef99273a8fdb19f5912ca38ba46d6bd02071363d/code/contracts/ethereum/contracts/zksync/facets/Executor.sol#L157) -by verifying the corresponding L2→L1 log. - -We also remember that the upgrade transaction has been processed in this batch (by amending the -`l2SystemContractsUpgradeBatchNumber` variable). - -### Revert - -In a very rare event when the team needs to revert the batch with the upgrade on zkSync, the -`l2SystemContractsUpgradeBatchNumber` is -[reset](https://github.com/code-423n4/2023-10-zksync/blob/ef99273a8fdb19f5912ca38ba46d6bd02071363d/code/contracts/ethereum/contracts/zksync/facets/Executor.sol#L412). - -Note, however, that we do not “remember” that certain batches had a version before the upgrade, i.e. if the reverted -batches will have to be reexecuted, the upgrade transaction must still be present there, even if some of the deleted -batches were committed before the upgrade and thus didn’t contain the transaction. - -### Execute - -Once batch with the upgrade transaction has been executed, we -[delete](https://github.com/code-423n4/2023-10-zksync/blob/ef99273a8fdb19f5912ca38ba46d6bd02071363d/code/contracts/ethereum/contracts/zksync/facets/Executor.sol#L304) -them from storage for efficiency to signify that the upgrade has been fully processed and that a new upgrade can be -initiated. - -## Security considerations - -Since the operator can put any data into the bootloader memory and for L1→L2 transactions the bootloader has to blindly -trust it and rely on L1 contracts to validate it, it may be a very powerful tool for a malicious operator. Note, that -while the governance mechanism is generally trusted, we try to limit our trust for the operator as much as possible, -since in the future anyone would be able to become an operator. - -Some time ago, we _used to_ have a system where the upgrades could be done via L1→L2 transactions, i.e. the -implementation of the `DiamondProxy` upgrade would -[include](https://github.com/matter-labs/era-contracts/blob/f06a58360a2b8e7129f64413998767ac169d1efd/ethereum/contracts/zksync/upgrade-initializers/DIamondUpgradeInit2.sol#L27) -a priority transaction (with `from` equal to for instance `FORCE_DEPLOYER`) with all the upgrade params. - -In the Boojum though having such logic would be dangerous and would allow for the following attack: - -- Let’s say that we have at least 1 priority operations in the priority queue. This can be any operation, initiated by - anyone. -- The operator puts a malicious priority operation with an upgrade into the bootloader memory. This operation was never - included in the priority operations queue / and it is not an upgrade transaction. However, as already mentioned above - the bootloader has no idea what priority / upgrade transactions are correct and so this transaction will be processed. - -The most important caveat of this malicious upgrade is that it may change implementation of the `Keccak256` precompile -to return any values that the operator needs. - -- When the`priorityOperationsRollingHash` will be updated, instead of the “correct” rolling hash of the priority - transactions, the one which would appear with the correct topmost priority operation is returned. The operator can’t - amend the behaviour of `numberOfPriorityTransactions`, but it won’t help much, since the - the`priorityOperationsRollingHash` will match on L1 on the execution step. - -That’s why the concept of the upgrade transaction is needed: this is the only transaction that can initiate transactions -out of the kernel space and thus change bytecodes of system contracts. That’s why it must be the first one and that’s -why -[emit](https://github.com/code-423n4/2023-10-zksync/blob/ef99273a8fdb19f5912ca38ba46d6bd02071363d/code/system-contracts/bootloader/bootloader.yul#L587) -its hash via a system L2→L1 log before actually processing it. - -### Why it doesn’t break on the previous version of the system - -This section is not required for Boojum understanding but for those willing to analyze the production system that is -deployed at the time of this writing. - -Note that the hash of the transaction is calculated before the transaction is executed: -[https://github.com/matter-labs/era-contracts/blob/main/system-contracts/bootloader/bootloader.yul#L1055](https://github.com/matter-labs/era-contracts/blob/main/system-contracts/bootloader/bootloader.yul#L1055) - -And then we publish its hash on L1 via a _system_ L2→L1 log: -[https://github.com/matter-labs/era-contracts/blob/main/system-contracts/bootloader/bootloader.yul#L1133](https://github.com/matter-labs/era-contracts/blob/main/system-contracts/bootloader/bootloader.yul#L1133) - -In the new upgrade system, the `priorityOperationsRollingHash` is calculated on L2 and so if something in the middle -changes the implementation of `Keccak256`, it may lead to the full `priorityOperationsRollingHash` be maliciously -crafted. In the pre-Boojum system, we publish all the hashes of the priority transactions via system L2→L1 and then the -rolling hash is calculated on L1. This means that if at least one of the hash is incorrect, then the entire rolling hash -will not match also. diff --git a/content/40.zk-stack/concepts/overview.md b/content/40.zk-stack/concepts/overview.md deleted file mode 100644 index 406a1c22..00000000 --- a/content/40.zk-stack/concepts/overview.md +++ /dev/null @@ -1,26 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Overview | ZK Stack Docs ---- - -# Concepts - -The goal of the ZK Stack is to power the internet of value. Value needs to be secured, and only blockchains are able -provide the level of security that the internet needs. The ZK Stack can be used to launch zero-knowledge rollups, which -are extra secure blockchains. - -ZK Rollups use advanced mathematics called zero-knowledge proofs to show that the execution of the rollup was done -correctly. They also send ("roll up") their data to another chain, in our case this is Ethereum. The ZK Stack uses the -zkEVM to execute transactions, making it Ethereum compatible. - -These two techniques allow the rollup to be verified externally. Unlike traditional blockchains, where you have to run a -node to verify all transactions, the state of the rollup can be easily checked by external participants by validating -the proof. - -These external validators of a rollup can be other rollups. This means we can connect rollups trustlessly, and create a -network of rollups. This network is called the hyperchain. - -These specs will provide a high level overview of the zkEVM and a full specification of its more technical components, -such as the prover, compiler, and the VM itself. We also specify the foundations of the hyperchain ecosystem. diff --git a/content/40.zk-stack/concepts/system-upgrades.md b/content/40.zk-stack/concepts/system-upgrades.md deleted file mode 100644 index 47801dca..00000000 --- a/content/40.zk-stack/concepts/system-upgrades.md +++ /dev/null @@ -1,44 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: System Upgrades | zkSync Docs ---- - -# System Upgrades - -## Update Process - -[System contracts](https://github.com/matter-labs/era-contracts) handle core functionalities and play a critical role in -maintaining the integrity of our protocol. To ensure the highest level of security and reliability, these system -contracts undergo an audit before any release. - -Here is an overview of the release process of the system contracts which is aimed to preserve agility and clarity on the -order of the upgrades: - -### `main` branch - -[The `main` branch](https://github.com/matter-labs/era-contracts/blob/main/README.md) contains the latest code that is -ready to be deployed into production. It reflects the most stable and audited version of the protocol. - -### `dev` branch - -[The `dev` branch](https://github.com/matter-labs/era-contracts/blob/dev/README.md) is for active development & the -latest code changes. Whenever a new PR with system contract changes is created it should be based on the `dev` branch. - -### Creating a new release - -Whenever a new release is planned, a new branch named `release-vX-<name>` should be created off the `dev` branch, where -`X` represents the release version, and `<name>` is a short descriptive name for the release. The PR with the new -release should point to either the `main` branch or to the release branch with a lower version (in case the previous -branch has not been merged into `main` for some reason). - -Once the audit for the release branch is complete and all the fixes from the audit are applied, we need to merge the new -changes into the `dev` branch. Once the release is final and merged into the `main` branch, the `main` branch should be -merged back into the `dev` branch to keep it up-to-date. - -### Updating Unaudited Code - -Since scripts, READMEs, etc., are code that is not subject to audits, these are to be merged directly into the `main` -branch. The rest of the release branches as well as the `dev` branch should merge `main` to synchronize with these -changes. diff --git a/content/40.zk-stack/concepts/transaction-lifecycle.md b/content/40.zk-stack/concepts/transaction-lifecycle.md deleted file mode 100644 index 7a18d6a1..00000000 --- a/content/40.zk-stack/concepts/transaction-lifecycle.md +++ /dev/null @@ -1,189 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Transaction Lifecycle | zkSync Docs ---- - -# Transaction Lifecycle - -## Overview - -As stated in the introduction, the ZK Stack can be used to launch rollups. These rollups have some operators that are -needed to run it, these are the sequencer and the prover, they create blocks and proofs, and submit them to the L1 -contract. - -:::info Transactions are cryptographically signed instructions from accounts. An account will initiate a transaction to -update the state of the Ethereum network. The simplest transaction is transferring ETH from one account to another. -[Ethereum.org](https://ethereum.org/en/developers/docs/transactions/) ::: - -A user submits their transaction to the sequencer. The job of the sequencer is to collect transactions and execute them -using the zkEVM, and to provide a soft confirmation to the user that their transaction was executed. If the user chooses -they can force the sequencer to include their transaction by submitting it via L1. After the sequencer executes the -block, it sends it over to the prover, who creates a cryptographic proof of the block's execution. This proof is then -sent to the L1 contract alongside the necessary data. On the L1 a smart contract verifies that the proof is valid and -all the data has been submitted, and the rollup's state is also updated in the contract. - -![Components](../../assets/images/l2-components.png) - -The core of this mechanism was the execution of transactions. The ZK Stack uses the zkEVM for this, which is similar to -the EVM, but its role is different than the EVM's role in Ethereum. - -Transactions can also be submitted via L1. This happens via the same process that allows L1<>L2 communication. This -method provides the rollup with censorship resistance, and allows trustless bridges to the L1. - -The sequencer collects transactions into blocks, similarly to Ethereum. To provide the best UX the protocol has small -blocks with quick soft confirmations for the users. Unlike Ethereum, -[the zkEVM does not just have blocks, but also batches](./blocks.md#batch-vs-block-vs-transaction), which are just a -collection of blocks. A batch is the unit that the prover processes. - -Before we submit a proof we send the data to L1. Instead of submitting the data of each transaction, we submit how the -state of the blockchain changes, this change is called the state diff. This approach allows the transactions that change -the same storage slots to be very cheap, since these transactions don't incur additional data costs. - -Finally at the end of the process, we create the proofs and send them to L1. Our Boojum proof system provides excellent -performance, and can be run on just 16Gb of GPU RAM. This will enable the proof generation to be truly decentralized. - -Up to this point we have only talked about a single chain. We will connect these chains into a single ecosystem, called -the hyperchain. - -## Transaction data - -Transactions on zkSync Era are [similar to Ethereum transactions](https://ethereum.org/en/developers/docs/transactions/) -so you can use the same wallet as you use on Ethereum. There are some minor differences, mostly with regards to setting -the fees. - -For more information on fees in zkSync Era, read the [fee model documentation](./fee-mechanism). - -The following values are returned by any RPC call which outputs transaction details: - -- `is_l1_originated`: `bool` -- `status`: `TransactionStatus`, one of `Pending`, `Included`, `Verified`, or `Failed`. See - [Transaction statuses section](#transaction-statuses) below. -- `fee`: `U256`. See the [fee mechanism documentation](./fee-mechanism.md) for more information. -- `initiator_address`: `Address` -- `received_at`: `DateTime<Utc>` -- `eth_commit_tx_hash`: `Option<H256>` -- `eth_prove_tx_hash`: `Option<H256>` -- `eth_execute_tx_hash`: `Option<H256>` - -::: info Contract deployment transactions - -Contract deployment transactions are different on zkSync as they involve interacting with the `ContractDeployer` system -contract. Learn more about -[contract deployment transactions here](../../build/developer-reference/contract-deployment.md). - -::: - -## Transaction statuses - -Transactions are always in one of the following statuses: - -- `Pending`: In the mempool but not yet included in a block. -- `Included`: Included in a block but the batch containing the block has not yet been committed. -- `Verified`: Included in a block and verified. Verified means the transaction has been committed, proven, and executed - on the Ethereum L1 network. -- `Failed`: Unverified/failed transaction. - -:::info For more information on when a transaction is considered complete and unalterable, read the documentation on -[finality](./finality.md). ::: - -## Transaction types - -For compatibility, the majority of zkSync Era transaction types are similar to those on Ethereum. - -:::tip The transaction type hex value is output by any RPC method call which returns a transaction type, such as -[`eth_getTransactionByHash`](https://ethereum.github.io/execution-apis/api-documentation/) for example. ::: - -### Legacy: `0x0` - -The Ethereum transaction format used before the introduction of typed-transactions. - -### EIP-2930: `0x1` - -The Ethereum Improvement Proposal [EIP-2930: Optional access lists](https://eips.ethereum.org/EIPS/eip-2930) addressed -contract breakage risks introduced by EIP-2929. - -EIP-2930 transaction types contain everything from legacy transactions plus an `accessList` parameter containing an -array of addresses and storage keys. - -### EIP-1559: `0x2` - -The Ethereum Improvement Proposal -[EIP-1559: Fee market change for ETH 1.0 chain](https://eips.ethereum.org/EIPS/eip-1559) is an updated transaction type -introduced in Ethereum's London fork. It addressed network congestion and excessive fees coming from bids. EIP-1559 -transactions don't specify `gasPrice` and instead use a base fee which is adjusted by each block. - -EIP-1559 transaction types contain everything from EIP-2930 and legacy transactions (apart from removing the -`gasPrice`). - -Additional parameters added are the `maxPriorityFeePerGas` and `maxFeePerGas` where users can specify maximum fees -they're willing to pay to prioritize their transactions. - -- `maxPriorityFeePerGas`: Is the maximum fee users are willing to give to miners as an incentive. -- `maxFeePerGas`: Is the maximum fee users are willing to pay in total. This includes the `maxPriorityFeePerGas` and - network-determined base fee per gas. - -:::warning Important zkSync Era supports the EIP-1559 transaction-type format but does nothing with the max fee -parameters. ::: - -### EIP-712: `0x71` - -The Ethereum Improvement Proposal -[EIP-712: Typed structured data hashing and signing](https://eips.ethereum.org/EIPS/eip-712) introduced hashing and -signing of typed-structured data as well as bytestrings. - -EIP-712 transactions access zkSync-specific features such as -[account abstraction](../../build/developer-reference/account-abstraction.md) and -[paymasters](../../build/tutorials/smart-contract-development/paymasters/custom-paymaster-tutorial.md). Furthermore, -smart contracts must be deployed with the EIP-712 transaction type. - -You can specify the additional fields, such as the custom signature for custom accounts or to choose the paymaster with -EIP-712 transactions. These transactions have the same fields as standard Ethereum transactions, plus fields containing -additional L2-specific data (`paymaster`, etc). - -```json -"gasPerPubdata": "1212", -"customSignature": "0x...", -"paymasterParams": { - "paymaster": "0x...", - "paymasterInput": "0x..." -}, -"factoryDeps": ["0x..."] -``` - -- `gasPerPubdata`: A field denoting the maximum amount of gas the user is willing to pay for a single byte of pubdata. -- `customSignature`: A field with a custom signature for the cases in which the signer's account is not an EOA. -- `paymasterParams`: A field with parameters for configuring the custom paymaster for the transaction. Parameters - include the address of the paymaster and the encoded input. -- `factory_deps`: A non-empty array of `bytes`. For deployment transactions, it should contain the bytecode of the - contract being deployed. If the contract is a factory contract, i.e. it can deploy other contracts, the array should - also contain the bytecodes of the contracts which it can deploy. - -To ensure the server recognizes EIP-712 transactions, the `transaction_type` field is equal to `113`. The number `712` -cannot be used as it has to be one byte long. - -Instead of signing the RLP-encoded transaction, the user signs the following typed EIP-712 structure: - -| Field name | Type | -| ---------------------- | ----------- | -| txType | `uint256` | -| from | `uint256` | -| to | `uint256` | -| gasLimit | `uint256` | -| gasPerPubdataByteLimit | `uint256` | -| maxFeePerGas | `uint256 ` | -| maxPriorityFeePerGas | `uint256` | -| paymaster | `uint256` | -| nonce | `uint256` | -| value | `uint256` | -| data | `bytes` | -| factoryDeps | `bytes32[]` | -| paymasterInput | `bytes` | - -These fields are handled by our SDKs. - -### Priority: `0xff` - -Since Ethereum L1 has no concept of interacting with other layers, this is a zkSync Era specific transaction type -related to [L1 -> L2 transactions](../../build/tutorials/how-to/send-transaction-l1-l2.md). diff --git a/content/40.zk-stack/concepts/validiums.md b/content/40.zk-stack/concepts/validiums.md deleted file mode 100644 index a588e14b..00000000 --- a/content/40.zk-stack/concepts/validiums.md +++ /dev/null @@ -1,63 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Validiums | zkSync Docs ---- - -# Validiums - -### TLDR - -Validiums are defined by: - -- Leveraging data availability off-chain. -- Using off-chain computations to create validity proofs that are verified on Ethereum. - -This leads to advantages like: - -- Notably lower gas expenses (less data published to L1). -- Development of niche applications, particularly those focusing on privacy and enterprise. - -However, Validiums have certain drawbacks: - -- There's a risk of users being unable to access their funds if off-chain data needed for Merkle proofs become - unavailable. -- Their security model is dependent on trust and economic incentives, in contrast to zk-rollups which are based solely - on cryptographic security methods. - -### What is a Validium? - -More precisely, Validiums serve as scaling solutions utilizing off-chain data availability and computation to enhance -throughput through off-chain transaction processing. Their security is upheld by issuing validity proofs on Ethereum, -which guarantees accurate state transitions, thereby ensuring the overall integrity of the Validium chain. - -Unlike zk-rollups that rely on on-chain data availability, Validiums opt for an off-chain data availability strategy. -This difference not only influences their security profile but also their level of trustlessness. By striking a -distinctive balance between operational efficiency and data privacy, Validiums offer new use cases. Validiums allow -near-instant withdrawals, enabled by the verification of validity proofs on Ethereum and the provision of Merkle proofs -by users. - -However, one potential risk with Validiums is the withholding of off-chain data by data availability managers, which -could impact fund accessibility. - -## Potential Use Cases - -### Enterprise Solutions - -Validiums are ideal for enterprise chains requiring auditability and privacy. By controlling data availability, -enterprises can maintain private Hyperchains, making Validiums an attractive choice for these applications. - -### Privacy Benefits - -For Hyperchains operating in Validium mode, privacy is inherently enhanced as long as the block data remains -confidential. This feature is particularly beneficial for enterprise users seeking to protect sensitive information. - -## Further Resources - -For those interested in delving deeper into the world of Validiums and their applications in blockchain technology, the -following resources are invaluable: - -- [Ethereum.org - Validium](https://ethereum.org/en/developers/docs/scaling/validium/) -- [DeFi Pulse - Rollups, Validiums, and Volitions](https://www.defipulse.com/blog/rollups-validiums-and-volitions-learn-about-the-hottest-ethereum-scaling-solutions) -- [Coda - Web3 One Pager on Validium](https://coda.io/@enzo/web3-one-pager/validium-42) diff --git a/content/40.zk-stack/running-a-hyperchain/dependencies.md b/content/40.zk-stack/running-a-hyperchain/dependencies.md deleted file mode 100644 index 094ac5d0..00000000 --- a/content/40.zk-stack/running-a-hyperchain/dependencies.md +++ /dev/null @@ -1,294 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Dependencies | zkSync Docs ---- - -# Installing dependencies - -## TL;DR - -If you run on 'clean' Debian on GCP: - -```bash -# Rust -curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -# NVM -curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.5/install.sh | bash -# All necessary stuff -sudo apt-get install build-essential pkg-config cmake clang lldb lld libssl-dev postgresql docker-compose -# Docker -sudo usermod -aG docker YOUR_USER - -## You might need to re-connect (due to usermod change). - -# Node & yarn -nvm install node -npm install -g yarn -yarn set version 1.22.19 - -# SQL tools -cargo install sqlx-cli --version 0.5.13 -# Stop default postgres (as we'll use the docker one) -sudo systemctl stop postgresql -# Start docker. -sudo systemctl start docker -``` - -## Supported operating systems - -zkSync currently can be launched on any \*nix operating system (e.g. any linux distribution or MacOS). - -If you're using Windows, then make sure to use WSL 2, since WSL 1 is known to cause troubles. - -Additionally, if you are going to use WSL 2, make sure that your project is located in the _linux filesystem_, since -accessing NTFS partitions from inside of WSL is very slow. - -If you're using MacOS with an ARM processor (e.g. M1/M2), make sure that you are working in the _native_ environment -(e.g. your terminal and IDE don't run in Rosetta, and your toolchain is native). Trying to work with zkSync code via -Rosetta may cause problems that are hard to spot and debug, so make sure to check everything before you start. - -If you are a NixOS user or would like to have a reproducible environment, skip to the section about `nix`. - -## `Docker` - -Install `docker`. It is recommended to follow the instructions from the -[official site](https://docs.docker.com/install/). - -Note: currently official site proposes using Docker Desktop for Linux, which is a GUI tool with plenty of quirks. If you -want to only have CLI tool, you need the `docker-ce` package and you can follow -[this guide](https://www.digitalocean.com/community/tutorials/how-to-install-and-use-docker-on-ubuntu-20-04) for Ubuntu. - -Installing `docker` via `snap` or from the default repository can cause troubles. - -You need to install both `docker` and `docker-compose`. - -**Note:** `docker-compose` is installed automatically with `Docker Desktop`. - -**Note:** On linux you may encounter the following error when you’ll try to work with `zksync`: - -``` -ERROR: Couldn't connect to Docker daemon - you might need to run `docker-machine start default`. -``` - -If so, you **do not need** to install `docker-machine`. Most probably, it means that your user is not added to -the`docker` group. You can check it as follows: - -```bash -docker-compose up # Should raise the same error. -sudo docker-compose up # Should start doing things. -``` - -If the first command fails, but the second succeeds, then you need to add your user to the `docker` group: - -```bash -sudo usermod -a -G docker your_user_name -``` - -After that, you should logout and login again (user groups are refreshed after the login). The problem should be solved -at this step. - -If logging out does not help, restarting the computer should. - -## `Node` & `Yarn` - -1. Install `Node` (requires version `v18.18.0`). Since our team attempts to always use the latest LTS version of - `Node.js`, we suggest you to install [nvm](https://github.com/nvm-sh/nvm). It will allow you to update `Node.js` - version easily in the future (by running `nvm use` in the root of the repository) -2. Install `yarn` (make sure to get version 1.22.19 - you can change the version by running `yarn set version 1.22.19`). - Instructions can be found on the [official site](https://classic.yarnpkg.com/en/docs/install/). - Check if `yarn` is installed by running `yarn -v`. If you face any problems when installing `yarn`, it might be the - case that your package manager installed the wrong package.Make sure to thoroughly follow the instructions above on - the official website. It contains a lot of troubleshooting guides in it. - -## `Axel` - -Install `axel` for downloading keys: - -On mac: - -```bash -brew install axel -``` - -On debian-based linux: - -```bash -sudo apt-get install axel -``` - -Check the version of `axel` with the following command: - -``` -axel --version -``` - -Make sure the version is higher than `2.17.10`. - -## `clang` - -In order to compile RocksDB, you must have LLVM available. On debian-based linux it can be installed as follows: - -On linux: - -```bash -sudo apt-get install build-essential pkg-config cmake clang lldb lld -``` - -On mac: - -You need to have an up-to-date `Xcode`. You can install it directly from `App Store`. With Xcode command line tools, you -get the Clang compiler installed by default. Thus, having XCode you don't need to install `clang`. - -## `OpenSSL` - -Install OpenSSL: - -On mac: - -```bash -brew install openssl -``` - -On linux: - -```bash -sudo apt-get install libssl-dev -``` - -## `Rust` - -Install the latest `rust` version. - -Instructions can be found on the [official site](https://www.rust-lang.org/tools/install). - -Verify the `rust` installation: - -```bash -rustc --version -rustc 1.xx.y (xxxxxx 20xx-yy-zz) # Output may vary depending on actual version of rust -``` - -If you are using MacOS with ARM processor (e.g. M1/M2), make sure that you use an `aarch64` toolchain. For example, when -you run `rustup show`, you should see a similar input: - -```bash -rustup show -Default host: aarch64-apple-darwin -rustup home: /Users/user/.rustup - -installed toolchains --------------------- - -... - -active toolchain ----------------- - -1.67.1-aarch64-apple-darwin (overridden by '/Users/user/workspace/zksync-era/rust-toolchain') -``` - -If you see `x86_64` mentioned in the output, probably you're running (or used to run) your IDE/terminal in Rosetta. If -that's the case, you should probably change the way you run terminal, and/or reinstall your IDE, and then reinstall the -Rust toolchain as well. - -## Postgres - -Install the latest postgres: - -On mac: - -```bash -brew install postgresql@14 -``` - -On linux: - -```bash -sudo apt-get install postgresql -``` - -### Cargo nextest - -[cargo-nextest](https://nexte.st/) is the next-generation test runner for Rust projects. `zk test rust` uses -`cargo nextest` by default. - -```bash -cargo install cargo-nextest -``` - -### SQLx CLI - -SQLx is a Rust library we use to interact with Postgres, and its CLI is used to manage DB migrations and support several -features of the library. - -```bash -cargo install sqlx-cli --version 0.5.13 -``` - -## Solidity compiler `solc` - -Install the latest solidity compiler. - -```bash -brew install solidity -``` - -Alternatively, download a [precompiled version](https://github.com/ethereum/solc-bin) and add it to your PATH. - -## Python - -Most environments will have this preinstalled but if not, install Python. - -## Easier method using `nix` - -Nix is a tool that can fetch _exactly_ the right dependencies specified via hashes. The current config is Linux-only but -it is likely that it can be adapted to Mac. - -Install `nix`. Enable the nix command and flakes. - -Install docker, rustup and use rust to install SQLx CLI like described above. If you are on NixOS, you also need to -enable nix-ld. - -Go to the zksync folder and run `nix develop --impure`. After it finishes, you are in a shell that has all the -dependencies. - -## Environment - -Edit the lines below and add them to your shell profile file (e.g. `~/.bash_profile`, `~/.zshrc`): - -```bash -# Add path here: -export ZKSYNC_HOME=/path/to/zksync - -export PATH=$ZKSYNC_HOME/bin:$PATH - -# If you're like me, uncomment: -# cd $ZKSYNC_HOME -``` - -### Tip: `mold` - -Optionally, you may want to optimize the build time with the modern linker, [`mold`](https://github.com/rui314/mold). - -This linker will speed up the build times, which can be pretty big for Rust binaries. - -Follow the instructions in the repo in order to install it and enable for Rust. - -## Tip: Speeding up building `RocksDB` - -By default, each time you compile `rocksdb` crate, it will compile required C++ sources from scratch. It can be avoided -by using precompiled versions of library, and it will significantly improve your build times. - -In order to do so, you can put compiled libraries to some persistent location, and add the following to your shell -configuration file (e.g. `.zshrc` or `.bashrc`): - -``` -export ROCKSDB_LIB_DIR=<library location> -export SNAPPY_LIB_DIR=<library location> -``` - -Make sure that compiled libraries match the current version of RocksDB. One way to obtain them, is to compile the -project in the usual way once, and then take built libraries from -`target/{debug,release}/build/librocksdb-sys-{some random value}/out`. diff --git a/content/40.zk-stack/running-a-hyperchain/enabling-prover.md b/content/40.zk-stack/running-a-hyperchain/enabling-prover.md deleted file mode 100644 index 7880648f..00000000 --- a/content/40.zk-stack/running-a-hyperchain/enabling-prover.md +++ /dev/null @@ -1,36 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Enabling Prover | zkSync Docs ---- - -# Enabling Prover - -With the default configuration, your hyperchain is not running a prover, and has a `DummyExecutor` contract, which -mainly “accepts” that a batch is executed without proof. This enables you to test it with much lower hardware -requirements. - -To enable the prover, run the `zk stack prover-setup` command. It will guide through the necessary configuration. - -> :warning: Running a prover is not required for deploying a testnet. The requirements below are only necessary if you -> want to enable the prover. - -## Requirements for CPU Prover - -The docker compose file assumes you will be running all components in the same machine. The current minimum requirements -for a low TPS scenario are: - -- 32 Core CPU -- 128 GB of RAM -- 700 of Disk Space (SSD preferred) - -## Requirements for GPU Prover - -The docker compose file assumes you will be running all components in the same machine. The current minimum requirements -for a low TPS scenario are: - -- 16 GB VRAM NVIDIA GPU -- 16 Core CPU -- 64 GB of RAM -- 300 GB of Disk Space (SSD preferred) diff --git a/content/40.zk-stack/running-a-hyperchain/getting-started.md b/content/40.zk-stack/running-a-hyperchain/getting-started.md deleted file mode 100644 index 70ab1235..00000000 --- a/content/40.zk-stack/running-a-hyperchain/getting-started.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Running a Hyperchain | zkSync Docs ---- - -# Running a Hyperchain diff --git a/content/40.zk-stack/running-a-hyperchain/locally.md b/content/40.zk-stack/running-a-hyperchain/locally.md deleted file mode 100644 index af4eec44..00000000 --- a/content/40.zk-stack/running-a-hyperchain/locally.md +++ /dev/null @@ -1,256 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Deploying Locally | zkSync Docs ---- - -# Getting Started with ZK Stack - -:::warning - -ZK Stack is still under development. We advise you to only use for local and testnet deployments. ::: - -## Development dependencies - -Ensure you have followed -[these instructions](https://github.com/matter-labs/zksync-era/blob/main/docs/guides/setup-dev.md) to set up -dependencies on your machine (don't worry about the Environment section for now). - -## Deploying locally - -1. Clone the zksync-era repo (or pull the latest if you've already cloned it) and go to the root of it: - -```bash -git clone https://github.com/matter-labs/zksync-era -``` - -2. Add `ZKSYNC_HOME` to your path (e.g. `~/.bash_profile`, `~/.zshrc` ) - don't forget to source your profile file again - (or restart your terminal): - -```bash -export ZKSYNC_HOME=/path/to/zksync/repo/you/cloned -export PATH=$ZKSYNC_HOME/bin:$PATH -``` - -3. Build latest version of zk tools by just running `zk` on the root of the project. - -```bash -zk -``` - -4. Last, start the wizard and follow instructions to set up and deploy your new hyperchain by running `zk stack init` - - - Initially you want to `Configure new chain` - - - Give it a name and chain id. - - - Select localhost (default `matterlabs/geth`) and follow the wizard. - - - If you are doing this for the first time, several components need to be compiled/built, so do not worry if it - takes a few minutes. The console will show what is going on anyways. - - - If you don't want to configure any values for now and just want check the build process for a hyperchain, try out - the `zk stack demo` command. - -:::warning - -The commands above are not just running docker containers, but are actually building the code from the repo to spin up -your hyperchain. For this reason the process might take some time. If you just want to run docker containers to play -around with a zkSync chain, you can use `npx zksync-cli dev`. Learn more -[here](../../build/tooling/zksync-cli/getting-started.md). ::: - -### Your hyperchain is now deployed - -Your hyperchain is now deployed to the base chain (most likely a local geth docker container) and configured. You can -find all configuration in a new `.env` file created on `<project root>/etc/env/<your_chain_name_slug>.env`, and if you -deployed test tokens, their addresses will be available at `<project root>/etc/tokens/<the_l1_identifier>.json` - -1. The wizard allows you to run the server in the end. If you chose not to, you’re still able to run it by executing - -```bash -zk server --components "http_api,eth,state_keeper,housekeeper" -``` - -2. You can now run transactions and start playing with your hyperchain by using the RPC available at - <http://localhost:3050>. - - - Don't forget to deposit some ETH and fund your accounts on your hyperchain. To do so follow the instructions for - [Funding accounts](#funding-accounts). - -## Using your hyperchain - -### Funding accounts - -During the `zk stack init` configurator, you have a choice of what base layer to deploy the hyperchain onto: the local -geth node, or an Ethereum network (e.g., Sepolia). The first step to start interacting with your hyperchain is to fund -an account (or a few). This means you need some funds on the base layer. - -#### Base layer is the local geth node ([@matterlabs/geth:latest](https://hub.docker.com/r/matterlabs/geth)) - -- If you chose to deploy on local geth node, you will have a set of addresses that have 100 ETH each. You can find the - list [here](https://github.com/matter-labs/local-setup/blob/main/rich-wallets.json) and use these addresses to deposit - into your hyperchain via the bridge. - -#### Base layer is an Ethereum network (e.g., Sepolia) - -- If you chose to deploy on an Ethereum network (e.g., Sepolia), you need to have an account on the base layer with ETH. - You can use the deployer, governor, or operator wallets setup during the the deployment process, or any other one you - have funds, to deposit into your hyperchain via the bridge. - -Once you have the accounts with funds on the L1 base layer, you can do a deposit via the bridge to your hyperchain, and -any further interactions with your hyperchain. - -### Using your hyperchain RPC - -Your server contains both HTTPS as well as WebSocket (WS) services that are fully web3 compatible (and contain some -extra ZK Stack functionalities). Learn more about it [here](../../build/api.md). - -### Using [zksync-cli](https://github.com/matter-labs/zksync-cli) - -zkSync CLI allows you to easily interact and develop applications on your hyperchain. When executing any command with -zksync-cli, you can specify RPC urls for both L1 and L2. Your local server contains RPCs for both. An example deposit -command via the bridge would look like: - -```bash -npx zksync-cli bridge deposit --rpc=http://localhost:3050 --l1-rpc=http://localhost:8545 --zeek -``` - -### Using [Portal](https://github.com/matter-labs/dapp-portal) - -The dApp Portal module allows you to: - -- View balances, transfer and bridge tokens to your hyperchain. -- Add contacts for quick and easy access. - -You can run the Portal module locally, and point it to your hyperchain configuration. It comes with scripts that help -pulling the hyperchain configuration from your zksync-era repo and adapting to portal needs. Learn more -[here](https://github.com/matter-labs/dapp-portal). An example command would look like: - -```bash -npm run hyperchain:configure ../zksync-era -npm run dev:node:hyperchain -``` - -You can now navigate to the displayed Portal URL (typically <http://localhost:3000>). - -### Using [Block Explorer](https://github.com/matter-labs/block-explorer) - -A free open source block explorer is available for your hyperchain. Block explorer contains three components -[Worker](https://github.com/matter-labs/block-explorer/tree/main/packages/worker), -[API](https://github.com/matter-labs/block-explorer/tree/main/packages/api), and -[App](https://github.com/matter-labs/block-explorer/tree/main/packages/app), which you can run all together locally and -connect to your hyperchain. - -Make sure you have your [zksync-era](https://github.com/matter-labs/zksync-era) repo set up locally and the `zk server` -is running. The wizard in this guide allows you to run the server in the end. If you chose not to, you’re still able to -run it by executing: - -```bash -zk server --components "http_api,eth,state_keeper,housekeeper" -``` - -### Running block explorer locally - -#### Install block explorer - -Clone & install the block explorer repository: - -```bash -cd /path/to/where/you/clone/repos -git clone https://github.com/matter-labs/block-explorer.git -cd block-explorer -npm install -``` - -#### Setting up env variables - -Next you need to set up all the necessary environment and configuration files with your hyperchain settings. You can use -a script to set them up: - -```bash -npm run hyperchain:configure -``` - -#### Run block explorer - -Afterwards you can run the block explorer: - -```bash -# if you are running block explorer for the first time -npm run db:create -``` - -```bash -npm run dev -``` - -#### Verify block explorer is up and running - -By default, you can access front-end `App` at <http://localhost:3010> in your browser. `API` should be available at -<http://localhost:3020>, `Worker` at <http://localhost:3001> and `Data Fetcher` at <http://localhost:3040>. - -## Enabling Boojum prover - -With the default configuration, your hyperchain is not running a prover, and has a DummyExecutor contract, which mainly -“accepts” that a batch is executed without proof. This enables you to test it with much lower hardware requirements. - -To enable the prover, run the `zk stack prover-setup` command. It will guide through the necessary configuration. - -There are two options for running the Boojum prover: in GPU, or in CPU. - -:::warning - -<u>Running a prover is not required</u> for deploying a testnet. The requirements below are only necessary if you want -to enable the prover. ::: - -### Requirements for GPU Prover - -The docker compose file assumes you will be running all components in the same machine. The current minimum requirements -for a low TPS scenario are: - -- 6 GB VRAM NVIDIA GPU -- 16 Core CPU -- 64 GB of RAM -- 300 GB of Disk Space (SSD preferred) - -### Requirements for CPU Prover - -The docker compose file assumes you will be running all components in the same machine. The current minimum requirements -for a low TPS scenario are: - -- 32 Core CPU -- 128 GB of RAM -- 700 of Disk Space (SSD preferred) - -## Addendum - -- If you make changes to any contract, you can always deploy a new hyperchain to easily test those changes. - -- If you configure your hyperchain once, you don't need to do it again as the wizard allows you to use an existing - config file. - -- For now, it is only possible to deploy a hyperchain as an L2, but soon it will also work as L3s. - -- When running the default matterlabs/geth, you have a set of rich wallets available to you. You can check them - [here](https://github.com/matter-labs/local-setup/blob/main/rich-wallets.json). - -- If you face an issue compiling rust code (example `<jemalloc>: Error allocating TSD`) try removing the - `rust-toolchain` file from the repo. - -- If you want to have a custom local base chain, you must ensure you have a database for your hyperchain, as well as the - local RPC for your L1. - - - To run a Postgres 14 database for your hyperchain, execute the following: - -```bash -docker-compose -f docker-compose-zkstack-common.yml up -d postgres -``` - -In case you don't want to use the docker Postgres database above but another one you already have locally, make sure its -version is 14 and it is running and accepts connections at `postgres://postgres@localhost/zksync_local`. You can test -with: - -```bash -psql -h localhost -U postgres -d postgres -c 'SELECT 1;' -``` diff --git a/content/40.zk-stack/running-a-hyperchain/production.md b/content/40.zk-stack/running-a-hyperchain/production.md deleted file mode 100644 index db5c1e16..00000000 --- a/content/40.zk-stack/running-a-hyperchain/production.md +++ /dev/null @@ -1,24 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Deploying to a Non-Local Environment | zkSync Docs ---- - -# Deploying to a Non-Local Environment - -The process to deploy to a non local environment is pretty similar to the local one. The wizard allows you to set up -URLs to external services (database, RPCs, etc). - -## Database - -The wizard allows you to provide a custom database url connector. Make sure you provide it and that it accepts external -connections if your server is not running in the same private network. - -## Server (Sequencer) & Prover - -After configuring your hyperchain, you can generate docker images for your server and prover. To do that run -`zk stack docker-setup`. - -This command will guide you to properly name and tag your image. After building it, a docker compose file will be -available so you can run the images on whichever cloud environment you desire. diff --git a/content/40.zk-stack/running-a-hyperchain/using-hyperchain.md b/content/40.zk-stack/running-a-hyperchain/using-hyperchain.md deleted file mode 100644 index cdd31679..00000000 --- a/content/40.zk-stack/running-a-hyperchain/using-hyperchain.md +++ /dev/null @@ -1,83 +0,0 @@ ---- -head: - - - meta - - name: 'twitter:title' - content: Using Your Hyperchain RPC | zkSync Docs ---- - -# Using Your Hyperchain RPC - -Your server contains both HTTPS as well as WS services that are fully web3 compatible (and contain some extra ZK Stack -functionalities). - -By default your server is available at <http://localhost:3050> - but if you deployed the server into some cloud -provider, you will have a different URL to interact with. - -## Using zksync-cli - -When executing any command with zksync-cli, you can specify RPC urls for both L1 and L2 if you choose “localnet” as your -network. An example deposit command would look like: - -```bash -npx zksync-cli bridge deposit --rpc=http://localhost:3050 --l1-rpc=http://localhost:8545 --zeek -``` - -## Using dApp Portal - -You can run the Portal module locally, and point it to your hyperchain configuration. It comes with scripts that help -pulling the hyperchain configuration from your zksync-era repo and adapting to portal needs. Learn more here. An example -command would look like: - -```bash -npm run hyperchain:migrate ../zksync-era -npm run dev:node:hyperchain -``` - -## Using Block Explorer - -Block explorer contains three components (Worker, API, and App), which you can run all together locally and connect to -your hyperchain. For that, you need to set up all the necessary environment and configuration files with your hyperchain -settings. You can use a script to build them. See setting up env variables. - -Once you have your zksync-era repo set up locally, you can run the following command to build environment and -configuration files for block explorer based on your **[zksync-era](https://github.com/matter-labs/zksync-era)** repo -configuration: - -```bash -npm run hyperchain:configure -``` - -The script generates all the necessary configuration files for block-explorer, which you can edit if you need any -changes. - -# Addendum - -- If you make changes to any contract, you can always deploy a new hyperchain to easily test those changes. - -- If you configure your hyperchain once, you don't need to do it again as the wizard allows you to use an existing - config file. - -- For now, it is only possible to deploy a hyperchain as an L2, but soon it will also work as L3s. - -- When running the default matterlabs/geth, you have a set of rich wallets available to you. You can check them - [here.](https://github.com/matter-labs/local-setup/blob/main/rich-wallets.json) - -- If you want to have a custom local base chain, you must ensure you have a database for your hyperchain, as well as the - local RPC for your L1. - -- To run a Postgres 14 database for your hyperchain, execute the following: - -```bash -docker-compose -f docker-compose-zkstack-common.yml up -d postgres -``` - -In case you don't want to use the docker Postgres database above but another one you already have locally, make sure its -version is 14 and it is running and accepts connections at postgres://postgres@localhost/zksync_local. You can test -with: - -```bash -psql -h localhost -U postgres -d postgres -c 'SELECT 1;' -``` - -If you face an issue compiling rust code (example `<jemalloc>: Error allocating TSD`) try removing the `rust-toolchain` -file from the repo.