diff --git a/contracts/gateway/linea/LineaL2Governance.sol b/contracts/gateway/linea/LineaL2Governance.sol new file mode 100644 index 0000000..429cd8d --- /dev/null +++ b/contracts/gateway/linea/LineaL2Governance.sol @@ -0,0 +1,52 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 + +pragma solidity ^0.8.0; + +import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; +import {Address} from "@openzeppelin/contracts/utils/Address.sol"; +import {IMessageService} from "../../interfaces/linea/IMessageService.sol"; + +contract LineaL2Governance is Ownable { + /// @notice Linea message service on local chain + IMessageService public immutable MESSAGE_SERVICE; + + /// @dev Represents a call to be made during an operation. + /// @param target The address to which the call will be made. + /// @param value The amount of Ether (in wei) to be sent along with the call. + /// @param data The calldata to be executed on the `target` address. + struct Call { + address target; + uint256 value; + bytes data; + } + + constructor(IMessageService _messageService, address _owner) { + MESSAGE_SERVICE = _messageService; + _transferOwnership(_owner); + } + + /** + * @dev Throws if the sender is not the Governance on Ethereum. + */ + function _checkOwner() internal view override { + require( + _msgSender() == address(MESSAGE_SERVICE) && owner() == MESSAGE_SERVICE.sender(), + "Ownable: caller is not the owner" + ); + } + + /// @notice Executes the operation's calls from the Governance contract on Ethereum. + /// @param _calls The array of calls to be executed. + function execute(Call[] calldata _calls) external payable onlyOwner { + for (uint256 i = 0; i < _calls.length; ++i) { + Call memory _call = _calls[i]; + // No use of return value + Address.functionCallWithValue(_call.target, _call.data, _call.value); + } + } + + /// @dev Contract might receive/hold ETH as part of the maintenance process. + receive() external payable { + // nothing to do here + } +} diff --git a/contracts/zksync/l1-contracts/governance/Governance.sol b/contracts/zksync/l1-contracts/governance/Governance.sol new file mode 100644 index 0000000..b1702d3 --- /dev/null +++ b/contracts/zksync/l1-contracts/governance/Governance.sol @@ -0,0 +1,263 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import {Ownable2Step} from "@openzeppelin/contracts/access/Ownable2Step.sol"; +import {IGovernance} from "./IGovernance.sol"; + +/// @author Matter Labs +/// @custom:security-contact security@matterlabs.dev +/// @dev Contract design is inspired by OpenZeppelin TimelockController and in-house Diamond Proxy upgrade mechanism. +/// @notice This contract manages operations (calls with preconditions) for governance tasks. +/// The contract allows for operations to be scheduled, executed, and canceled with +/// appropriate permissions and delays. It is used for managing and coordinating upgrades +/// and changes in all zkSync Era governed contracts. +/// +/// Operations can be proposed as either fully transparent upgrades with on-chain data, +/// or "shadow" upgrades where upgrade data is not published on-chain before execution. Proposed operations +/// are subject to a delay before they can be executed, but they can be executed instantly +/// with the security council’s permission. +contract Governance is IGovernance, Ownable2Step { + /// @notice A constant representing the timestamp for completed operations. + uint256 internal constant EXECUTED_PROPOSAL_TIMESTAMP = uint256(1); + + /// @notice The address of the security council. + /// @dev It is supposed to be multisig contract. + address public securityCouncil; + + /// @notice A mapping to store timestamps when each operation will be ready for execution. + /// @dev - 0 means the operation is not created. + /// @dev - 1 (EXECUTED_PROPOSAL_TIMESTAMP) means the operation is already executed. + /// @dev - any other value means timestamp in seconds when the operation will be ready for execution. + mapping(bytes32 operationId => uint256 executionTimestamp) public timestamps; + + /// @notice The minimum delay in seconds for operations to be ready for execution. + uint256 public minDelay; + + /// @notice Initializes the contract with the admin address, security council address, and minimum delay. + /// @param _admin The address to be assigned as the admin of the contract. + /// @param _securityCouncil The address to be assigned as the security council of the contract. + /// @param _minDelay The initial minimum delay (in seconds) to be set for operations. + constructor(address _admin, address _securityCouncil, uint256 _minDelay) { + require(_admin != address(0), "Admin should be non zero address"); + + _transferOwnership(_admin); + + securityCouncil = _securityCouncil; + emit ChangeSecurityCouncil(address(0), _securityCouncil); + + minDelay = _minDelay; + emit ChangeMinDelay(0, _minDelay); + } + + /*////////////////////////////////////////////////////////////// + MODIFIERS + //////////////////////////////////////////////////////////////*/ + + /// @notice Checks that the message sender is contract itself. + modifier onlySelf() { + require(msg.sender == address(this), "Only governance contract itself is allowed to call this function"); + _; + } + + /// @notice Checks that the message sender is an active security council. + modifier onlySecurityCouncil() { + require(msg.sender == securityCouncil, "Only security council is allowed to call this function"); + _; + } + + /// @notice Checks that the message sender is an active owner or an active security council. + modifier onlyOwnerOrSecurityCouncil() { + require( + msg.sender == owner() || msg.sender == securityCouncil, + "Only the owner and security council are allowed to call this function" + ); + _; + } + + /*////////////////////////////////////////////////////////////// + OPERATION GETTERS + //////////////////////////////////////////////////////////////*/ + + /// @dev Returns whether an id corresponds to a registered operation. This + /// includes both Waiting, Ready, and Done operations. + function isOperation(bytes32 _id) public view returns (bool) { + return getOperationState(_id) != OperationState.Unset; + } + + /// @dev Returns whether an operation is pending or not. Note that a "pending" operation may also be "ready". + function isOperationPending(bytes32 _id) public view returns (bool) { + OperationState state = getOperationState(_id); + return state == OperationState.Waiting || state == OperationState.Ready; + } + + /// @dev Returns whether an operation is ready for execution. Note that a "ready" operation is also "pending". + function isOperationReady(bytes32 _id) public view returns (bool) { + return getOperationState(_id) == OperationState.Ready; + } + + /// @dev Returns whether an operation is done or not. + function isOperationDone(bytes32 _id) public view returns (bool) { + return getOperationState(_id) == OperationState.Done; + } + + /// @dev Returns operation state. + function getOperationState(bytes32 _id) public view returns (OperationState) { + uint256 timestamp = timestamps[_id]; + if (timestamp == 0) { + return OperationState.Unset; + } else if (timestamp == EXECUTED_PROPOSAL_TIMESTAMP) { + return OperationState.Done; + } else if (timestamp > block.timestamp) { + return OperationState.Waiting; + } else { + return OperationState.Ready; + } + } + + /*////////////////////////////////////////////////////////////// + SCHEDULING CALLS + //////////////////////////////////////////////////////////////*/ + + /// @notice Propose a fully transparent upgrade, providing upgrade data on-chain. + /// @notice The owner will be able to execute the proposal either: + /// - With a `delay` timelock on its own. + /// - With security council instantly. + /// @dev Only the current owner can propose an upgrade. + /// @param _operation The operation parameters will be executed with the upgrade. + /// @param _delay The delay time (in seconds) after which the proposed upgrade can be executed by the owner. + function scheduleTransparent(Operation calldata _operation, uint256 _delay) external onlyOwner { + bytes32 id = hashOperation(_operation); + _schedule(id, _delay); + emit TransparentOperationScheduled(id, _delay, _operation); + } + + /// @notice Propose "shadow" upgrade, upgrade data is not publishing on-chain. + /// @notice The owner will be able to execute the proposal either: + /// - With a `delay` timelock on its own. + /// - With security council instantly. + /// @dev Only the current owner can propose an upgrade. + /// @param _id The operation hash (see `hashOperation` function) + /// @param _delay The delay time (in seconds) after which the proposed upgrade may be executed by the owner. + function scheduleShadow(bytes32 _id, uint256 _delay) external onlyOwner { + _schedule(_id, _delay); + emit ShadowOperationScheduled(_id, _delay); + } + + /*////////////////////////////////////////////////////////////// + CANCELING CALLS + //////////////////////////////////////////////////////////////*/ + + /// @dev Cancel the scheduled operation. + /// @dev Only owner can call this function. + /// @param _id Proposal id value (see `hashOperation`) + function cancel(bytes32 _id) external onlyOwner { + require(isOperationPending(_id), "Operation must be pending"); + delete timestamps[_id]; + emit OperationCancelled(_id); + } + + /*////////////////////////////////////////////////////////////// + EXECUTING CALLS + //////////////////////////////////////////////////////////////*/ + + /// @notice Executes the scheduled operation after the delay passed. + /// @dev Both the owner and security council may execute delayed operations. + /// @param _operation The operation parameters will be executed with the upgrade. + function execute(Operation calldata _operation) external payable onlyOwnerOrSecurityCouncil { + bytes32 id = hashOperation(_operation); + // Check if the predecessor operation is completed. + _checkPredecessorDone(_operation.predecessor); + // Ensure that the operation is ready to proceed. + require(isOperationReady(id), "Operation must be ready before execution"); + // Execute operation. + _execute(_operation.calls); + // Reconfirming that the operation is still ready after execution. + // This is needed to avoid unexpected reentrancy attacks of re-executing the same operation. + require(isOperationReady(id), "Operation must be ready after execution"); + // Set operation to be done + timestamps[id] = EXECUTED_PROPOSAL_TIMESTAMP; + emit OperationExecuted(id); + } + + /// @notice Executes the scheduled operation with the security council instantly. + /// @dev Only the security council may execute an operation instantly. + /// @param _operation The operation parameters will be executed with the upgrade. + function executeInstant(Operation calldata _operation) external payable onlySecurityCouncil { + bytes32 id = hashOperation(_operation); + // Check if the predecessor operation is completed. + _checkPredecessorDone(_operation.predecessor); + // Ensure that the operation is in a pending state before proceeding. + require(isOperationPending(id), "Operation must be pending before execution"); + // Execute operation. + _execute(_operation.calls); + // Reconfirming that the operation is still pending before execution. + // This is needed to avoid unexpected reentrancy attacks of re-executing the same operation. + require(isOperationPending(id), "Operation must be pending after execution"); + // Set operation to be done + timestamps[id] = EXECUTED_PROPOSAL_TIMESTAMP; + emit OperationExecuted(id); + } + + /// @dev Returns the identifier of an operation. + /// @param _operation The operation object to compute the identifier for. + function hashOperation(Operation calldata _operation) public pure returns (bytes32) { + return keccak256(abi.encode(_operation)); + } + + /*////////////////////////////////////////////////////////////// + HELPERS + //////////////////////////////////////////////////////////////*/ + + /// @dev Schedule an operation that is to become valid after a given delay. + /// @param _id The operation hash (see `hashOperation` function) + /// @param _delay The delay time (in seconds) after which the proposed upgrade can be executed by the owner. + function _schedule(bytes32 _id, uint256 _delay) internal { + require(!isOperation(_id), "Operation with this proposal id already exists"); + require(_delay >= minDelay, "Proposed delay is less than minimum delay"); + + timestamps[_id] = block.timestamp + _delay; + } + + /// @dev Execute an operation's calls. + /// @param _calls The array of calls to be executed. + function _execute(Call[] calldata _calls) internal { + for (uint256 i = 0; i < _calls.length; ++i) { + (bool success, bytes memory returnData) = _calls[i].target.call{value: _calls[i].value}(_calls[i].data); + if (!success) { + // Propagate an error if the call fails. + assembly { + revert(add(returnData, 0x20), mload(returnData)) + } + } + } + } + + /// @notice Verifies if the predecessor operation is completed. + /// @param _predecessorId The hash of the operation that should be completed. + /// @dev Doesn't check the operation to be complete if the input is zero. + function _checkPredecessorDone(bytes32 _predecessorId) internal view { + require(_predecessorId == bytes32(0) || isOperationDone(_predecessorId), "Predecessor operation not completed"); + } + + /*////////////////////////////////////////////////////////////// + SELF UPGRADES + //////////////////////////////////////////////////////////////*/ + + /// @dev Changes the minimum timelock duration for future operations. + /// @param _newDelay The new minimum delay time (in seconds) for future operations. + function updateDelay(uint256 _newDelay) external onlySelf { + emit ChangeMinDelay(minDelay, _newDelay); + minDelay = _newDelay; + } + + /// @dev Updates the address of the security council. + /// @param _newSecurityCouncil The address of the new security council. + function updateSecurityCouncil(address _newSecurityCouncil) external onlySelf { + emit ChangeSecurityCouncil(securityCouncil, _newSecurityCouncil); + securityCouncil = _newSecurityCouncil; + } + + /// @dev Contract might receive/hold ETH as part of the maintenance process. + receive() external payable {} +} diff --git a/contracts/zksync/l1-contracts/governance/IGovernance.sol b/contracts/zksync/l1-contracts/governance/IGovernance.sol new file mode 100644 index 0000000..2c2180a --- /dev/null +++ b/contracts/zksync/l1-contracts/governance/IGovernance.sol @@ -0,0 +1,84 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +/// @title Governance contract interface +/// @author Matter Labs +/// @custom:security-contact security@matterlabs.dev +interface IGovernance { + /// @dev This enumeration includes the following states: + /// @param Unset Default state, indicating the operation has not been set. + /// @param Waiting The operation is scheduled but not yet ready to be executed. + /// @param Ready The operation is ready to be executed. + /// @param Done The operation has been successfully executed. + enum OperationState { + Unset, + Waiting, + Ready, + Done + } + + /// @dev Represents a call to be made during an operation. + /// @param target The address to which the call will be made. + /// @param value The amount of Ether (in wei) to be sent along with the call. + /// @param data The calldata to be executed on the `target` address. + struct Call { + address target; + uint256 value; + bytes data; + } + + /// @dev Defines the structure of an operation that Governance executes. + /// @param calls An array of `Call` structs, each representing a call to be made during the operation. + /// @param predecessor The hash of the predecessor operation, that should be executed before this operation. + /// @param salt A bytes32 value used for creating unique operation hashes. + struct Operation { + Call[] calls; + bytes32 predecessor; + bytes32 salt; + } + + function isOperation(bytes32 _id) external view returns (bool); + + function isOperationPending(bytes32 _id) external view returns (bool); + + function isOperationReady(bytes32 _id) external view returns (bool); + + function isOperationDone(bytes32 _id) external view returns (bool); + + function getOperationState(bytes32 _id) external view returns (OperationState); + + function scheduleTransparent(Operation calldata _operation, uint256 _delay) external; + + function scheduleShadow(bytes32 _id, uint256 _delay) external; + + function cancel(bytes32 _id) external; + + function execute(Operation calldata _operation) external payable; + + function executeInstant(Operation calldata _operation) external payable; + + function hashOperation(Operation calldata _operation) external pure returns (bytes32); + + function updateDelay(uint256 _newDelay) external; + + function updateSecurityCouncil(address _newSecurityCouncil) external; + + /// @notice Emitted when transparent operation is scheduled. + event TransparentOperationScheduled(bytes32 indexed _id, uint256 delay, Operation _operation); + + /// @notice Emitted when shadow operation is scheduled. + event ShadowOperationScheduled(bytes32 indexed _id, uint256 delay); + + /// @notice Emitted when the operation is executed with delay or instantly. + event OperationExecuted(bytes32 indexed _id); + + /// @notice Emitted when the security council address is changed. + event ChangeSecurityCouncil(address _securityCouncilBefore, address _securityCouncilAfter); + + /// @notice Emitted when the minimum delay for future operations is modified. + event ChangeMinDelay(uint256 _delayBefore, uint256 _delayAfter); + + /// @notice Emitted when the operation with specified id is cancelled. + event OperationCancelled(bytes32 indexed _id); +} diff --git a/examples/arbitrum/hardhat.config.js b/examples/arbitrum/hardhat.config.js index 004d226..1265b47 100644 --- a/examples/arbitrum/hardhat.config.js +++ b/examples/arbitrum/hardhat.config.js @@ -4,6 +4,7 @@ require('./scripts/syncBatchRoot'); require('./scripts/changeFeeParams'); require('./scripts/setValidator'); require('./scripts/setSecondaryGateway'); +require('./scripts/governance'); const BaseConfig = require('../../hardhat.base.config'); diff --git a/examples/arbitrum/scripts/governance.js b/examples/arbitrum/scripts/governance.js new file mode 100644 index 0000000..8f0611a --- /dev/null +++ b/examples/arbitrum/scripts/governance.js @@ -0,0 +1,130 @@ +const { providers } = require('ethers'); +const { readDeployContract } = require('../../../script/utils'); +const logName = require('../../../script/deploy_log_name'); +const { L1ToL2MessageGasEstimator } = require('@arbitrum/sdk/dist/lib/message/L1ToL2MessageGasEstimator'); +const { getBaseFee } = require('@arbitrum/sdk/dist/lib/utils/lib'); +const { task, types } = require('hardhat/config'); +const { zkLinkConfig } = require('../../../script/zklink_config'); +const { L1TransactionReceipt, L1ToL2MessageStatus } = require('@arbitrum/sdk'); + +require('dotenv').config(); + +task('encodeL1ToL2Calldata', 'Encode call data for l1 to l2') + .addParam('to', 'The l2 target address', undefined, types.string) + .addParam('l2CallData', 'The l2 call data to target address', undefined, types.string) + .addParam('l2CallValue', 'The l2 call value to target address', undefined, types.int) + .addParam( + 'refundAddress', + 'The excess fee and value refund address(should be an EOA address)', + undefined, + types.string, + ) + .setAction(async (taskArgs, hre) => { + const l2ToContractAddress = taskArgs.to; + const l2CallData = taskArgs.l2CallData; + const l2CallValue = taskArgs.l2CallValue; + const refundAddress = taskArgs.refundAddress; + console.log(`The l2 target contract address: ${l2ToContractAddress}`); + console.log(`The l2 call data to target address: ${l2CallData}`); + console.log(`The l2 call value to target address: ${l2CallValue}`); + console.log(`The refund address: ${refundAddress}`); + + const l1Provider = new providers.JsonRpcProvider(process.env.L1RPC); + const l2Provider = new providers.JsonRpcProvider(process.env.L2RPC); + const arbitrumName = process.env.ARBITRUM; + const ethereumName = process.env.ETHEREUM; + + const l2ChainInfo = zkLinkConfig[arbitrumName]; + if (l2ChainInfo === undefined) { + console.log('The l2 chain info not exist'); + return; + } + const inboxAddr = l2ChainInfo['l1Gateway']['constructParams'][0]; + if (inboxAddr === undefined) { + console.log('The arbitrum inbox address not exist'); + return; + } + console.log(`The inbox address: ${inboxAddr}`); + + const l1GovernanceAddr = readDeployContract( + logName.DEPLOY_GOVERNANCE_LOG_PREFIX, + logName.DEPLOY_LOG_GOVERNANCE, + ethereumName, + ); + if (l1GovernanceAddr === undefined) { + console.log('governance address not exist'); + return; + } + console.log(`The l1 governance address: ${l1GovernanceAddr}`); + /** + * Now we can query the required gas params using the estimateAll method in Arbitrum SDK + */ + const l1ToL2MessageGasEstimate = new L1ToL2MessageGasEstimator(l2Provider); + + /** + * The estimateAll method gives us the following values for sending an L1->L2 message + * (1) maxSubmissionCost: The maximum cost to be paid for submitting the transaction + * (2) gasLimit: The L2 gas limit + * (3) deposit: The total amount to deposit on L1 to cover L2 gas and L2 call value + */ + const l1BaseFee = await getBaseFee(l1Provider); + console.log(`Current base fee on L1 is: ${l1BaseFee}`); + const L1ToL2MessageGasParams = await l1ToL2MessageGasEstimate.estimateAll( + { + from: l1GovernanceAddr, + to: l2ToContractAddress, + l2CallValue: l2CallValue, + excessFeeRefundAddress: refundAddress, + callValueRefundAddress: refundAddress, + data: l2CallData, + }, + l1BaseFee, + l1Provider, + ); + console.log(`Current retryable base submission price is: ${L1ToL2MessageGasParams.maxSubmissionCost.toString()}`); + console.log(`Estimate gasLimit on L2 is: ${L1ToL2MessageGasParams.gasLimit.toString()}`); + console.log(`Estimate maxFeePerGas on L2 is: ${L1ToL2MessageGasParams.maxFeePerGas.toString()}`); + console.log(`Estimate fee to pay on L1 is: ${L1ToL2MessageGasParams.deposit.toString()}`); + + const inbox = await hre.ethers.getContractAt('Inbox', '0x0000000000000000000000000000000000000000'); + const inboxCalldata = inbox.interface.encodeFunctionData('createRetryableTicket', [ + l2ToContractAddress, + l2CallValue, + L1ToL2MessageGasParams.maxSubmissionCost, + refundAddress, + refundAddress, + L1ToL2MessageGasParams.gasLimit, + L1ToL2MessageGasParams.maxFeePerGas, + l2CallData, + ]); + console.log(`The l1 to l2 call target: ${inboxAddr}`); + console.log(`The l1 to l2 call data: ${inboxCalldata}`); + console.log(`The l1 to l2 call value: ${L1ToL2MessageGasParams.deposit.toString()}`); + }); + +task('checkL1TxStatus', 'Check the l1 tx status') + .addParam('l1TxHash', 'The l1 tx hash', undefined, types.string) + .setAction(async taskArgs => { + const l1TxHash = taskArgs.l1TxHash; + console.log(`The l1 tx hash: ${l1TxHash}`); + + const l1Provider = new providers.JsonRpcProvider(process.env.L1RPC); + const l2Provider = new providers.JsonRpcProvider(process.env.L2RPC); + const l1TxReceipt = new L1TransactionReceipt(await l1Provider.getTransactionReceipt(l1TxHash)); + + /** + * In principle, a single L1 txn can trigger any number of L1-to-L2 messages (each with its own sequencer number). + * In this case, we know our txn triggered only one + * Here, We check if our L1 to L2 message is redeemed on L2 + */ + const messages = await l1TxReceipt.getL1ToL2Messages(l2Provider); + const message = messages[0]; + console.log('Waiting for the L2 execution of the transaction. This may take up to 10-15 minutes ⏰'); + const messageResult = await message.waitForStatus(); + const status = messageResult.status; + if (status === L1ToL2MessageStatus.REDEEMED) { + console.log(`L2 retryable ticket is executed 🥳 ${messageResult.l2TxReceipt.transactionHash}`); + } else { + console.log(`L2 retryable ticket is failed with status ${L1ToL2MessageStatus[status]}`); + } + }); diff --git a/examples/base/package-lock.json b/examples/base/package-lock.json index e15cab7..7c27324 100644 --- a/examples/base/package-lock.json +++ b/examples/base/package-lock.json @@ -9,10 +9,11 @@ "version": "1.0.0", "license": "MIT", "dependencies": { + "@eth-optimism/core-utils": "^0.13.1", "dotenv": "^16.4.1" }, "devDependencies": { - "@eth-optimism/sdk": "^3.2.0", + "@eth-optimism/sdk": "^3.2.3", "@nomiclabs/hardhat-ethers": "^2.0.2", "ethers": "^5.7.2", "hardhat": "^2.9.1" @@ -67,7 +68,6 @@ "version": "0.13.1", "resolved": "https://registry.npmmirror.com/@eth-optimism/core-utils/-/core-utils-0.13.1.tgz", "integrity": "sha512-1FvzbUmCEy9zSKPG1QWg2VfA2Cy90xBA9Wkp11lXXrz91zUPCNCNSRTujXWYIC86ketNsZp7p4njSf6lTycHCw==", - "dev": true, "hasInstallScript": true, "dependencies": { "@ethersproject/abi": "^5.7.0", @@ -87,9 +87,9 @@ } }, "node_modules/@eth-optimism/sdk": { - "version": "3.2.2", - "resolved": "https://registry.npmmirror.com/@eth-optimism/sdk/-/sdk-3.2.2.tgz", - "integrity": "sha512-P8YXAlh2lun0KZlwrw4FqmK4kNIoOOzI816XXhfkW3nMVADGRAru3TKSM74MgmEuyGiHrA9EoPRq1WLqUX4B0w==", + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/@eth-optimism/sdk/-/sdk-3.2.3.tgz", + "integrity": "sha512-e3XQTbbU+HTzsEv/VIsJpZifK6YZVlzEtF6tj/Vz/VIEDCjZk5JPcnCQOMVcs9ICI4EJyyur+y/+RU7fPa6qtg==", "dev": true, "dependencies": { "@eth-optimism/contracts": "0.6.0", @@ -176,7 +176,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/abi/-/abi-5.7.0.tgz", "integrity": "sha512-351ktp42TiRcYB3H1OP8yajPeAQstMW/yCFokj/AthP9bLHzQFPlOrxOcwYEDkUAICmOHljvN4K39OMTMUa9RA==", - "dev": true, "dependencies": { "@ethersproject/address": "^5.7.0", "@ethersproject/bignumber": "^5.7.0", @@ -193,7 +192,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/abstract-provider/-/abstract-provider-5.7.0.tgz", "integrity": "sha512-R41c9UkchKCpAqStMYUpdunjo3pkEvZC3FAwZn5S5MGbXoMQOHIdHItezTETxAO5bevtMApSyEhn9+CHcDsWBw==", - "dev": true, "dependencies": { "@ethersproject/bignumber": "^5.7.0", "@ethersproject/bytes": "^5.7.0", @@ -208,7 +206,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/abstract-signer/-/abstract-signer-5.7.0.tgz", "integrity": "sha512-a16V8bq1/Cz+TGCkE2OPMTOUDLS3grCpdjoJCYNnVBbdYEMSgKrU0+B90s8b6H+ByYTBZN7a3g76jdIJi7UfKQ==", - "dev": true, "dependencies": { "@ethersproject/abstract-provider": "^5.7.0", "@ethersproject/bignumber": "^5.7.0", @@ -221,7 +218,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/address/-/address-5.7.0.tgz", "integrity": "sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA==", - "dev": true, "dependencies": { "@ethersproject/bignumber": "^5.7.0", "@ethersproject/bytes": "^5.7.0", @@ -234,7 +230,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/base64/-/base64-5.7.0.tgz", "integrity": "sha512-Dr8tcHt2mEbsZr/mwTPIQAf3Ai0Bks/7gTw9dSqk1mQvhW3XvRlmDJr/4n+wg1JmCl16NZue17CDh8xb/vZ0sQ==", - "dev": true, "dependencies": { "@ethersproject/bytes": "^5.7.0" } @@ -243,7 +238,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/basex/-/basex-5.7.0.tgz", "integrity": "sha512-ywlh43GwZLv2Voc2gQVTKBoVQ1mti3d8HK5aMxsfu/nRDnMmNqaSJ3r3n85HBByT8OpoY96SXM1FogC533T4zw==", - "dev": true, "dependencies": { "@ethersproject/bytes": "^5.7.0", "@ethersproject/properties": "^5.7.0" @@ -253,7 +247,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/bignumber/-/bignumber-5.7.0.tgz", "integrity": "sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw==", - "dev": true, "dependencies": { "@ethersproject/bytes": "^5.7.0", "@ethersproject/logger": "^5.7.0", @@ -264,7 +257,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/bytes/-/bytes-5.7.0.tgz", "integrity": "sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A==", - "dev": true, "dependencies": { "@ethersproject/logger": "^5.7.0" } @@ -273,7 +265,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/constants/-/constants-5.7.0.tgz", "integrity": "sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA==", - "dev": true, "dependencies": { "@ethersproject/bignumber": "^5.7.0" } @@ -282,7 +273,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/contracts/-/contracts-5.7.0.tgz", "integrity": "sha512-5GJbzEU3X+d33CdfPhcyS+z8MzsTrBGk/sc+G+59+tPa9yFkl6HQ9D6L0QMgNTA9q8dT0XKxxkyp883XsQvbbg==", - "dev": true, "dependencies": { "@ethersproject/abi": "^5.7.0", "@ethersproject/abstract-provider": "^5.7.0", @@ -300,7 +290,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/hash/-/hash-5.7.0.tgz", "integrity": "sha512-qX5WrQfnah1EFnO5zJv1v46a8HW0+E5xuBBDTwMFZLuVTx0tbU2kkx15NqdjxecrLGatQN9FGQKpb1FKdHCt+g==", - "dev": true, "dependencies": { "@ethersproject/abstract-signer": "^5.7.0", "@ethersproject/address": "^5.7.0", @@ -317,7 +306,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/hdnode/-/hdnode-5.7.0.tgz", "integrity": "sha512-OmyYo9EENBPPf4ERhR7oj6uAtUAhYGqOnIS+jE5pTXvdKBS99ikzq1E7Iv0ZQZ5V36Lqx1qZLeak0Ra16qpeOg==", - "dev": true, "dependencies": { "@ethersproject/abstract-signer": "^5.7.0", "@ethersproject/basex": "^5.7.0", @@ -337,7 +325,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/json-wallets/-/json-wallets-5.7.0.tgz", "integrity": "sha512-8oee5Xgu6+RKgJTkvEMl2wDgSPSAQ9MB/3JYjFV9jlKvcYHUXZC+cQp0njgmxdHkYWn8s6/IqIZYm0YWCjO/0g==", - "dev": true, "dependencies": { "@ethersproject/abstract-signer": "^5.7.0", "@ethersproject/address": "^5.7.0", @@ -358,7 +345,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/keccak256/-/keccak256-5.7.0.tgz", "integrity": "sha512-2UcPboeL/iW+pSg6vZ6ydF8tCnv3Iu/8tUmLLzWWGzxWKFFqOBQFLo6uLUv6BDrLgCDfN28RJ/wtByx+jZ4KBg==", - "dev": true, "dependencies": { "@ethersproject/bytes": "^5.7.0", "js-sha3": "0.8.0" @@ -367,14 +353,12 @@ "node_modules/@ethersproject/logger": { "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/logger/-/logger-5.7.0.tgz", - "integrity": "sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig==", - "dev": true + "integrity": "sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig==" }, "node_modules/@ethersproject/networks": { "version": "5.7.1", "resolved": "https://registry.npmmirror.com/@ethersproject/networks/-/networks-5.7.1.tgz", "integrity": "sha512-n/MufjFYv3yFcUyfhnXotyDlNdFb7onmkSy8aQERi2PjNcnWQ66xXxa3XlS8nCcA8aJKJjIIMNJTC7tu80GwpQ==", - "dev": true, "dependencies": { "@ethersproject/logger": "^5.7.0" } @@ -383,7 +367,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/pbkdf2/-/pbkdf2-5.7.0.tgz", "integrity": "sha512-oR/dBRZR6GTyaofd86DehG72hY6NpAjhabkhxgr3X2FpJtJuodEl2auADWBZfhDHgVCbu3/H/Ocq2uC6dpNjjw==", - "dev": true, "dependencies": { "@ethersproject/bytes": "^5.7.0", "@ethersproject/sha2": "^5.7.0" @@ -393,7 +376,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/properties/-/properties-5.7.0.tgz", "integrity": "sha512-J87jy8suntrAkIZtecpxEPxY//szqr1mlBaYlQ0r4RCaiD2hjheqF9s1LVE8vVuJCXisjIP+JgtK/Do54ej4Sw==", - "dev": true, "dependencies": { "@ethersproject/logger": "^5.7.0" } @@ -402,7 +384,6 @@ "version": "5.7.2", "resolved": "https://registry.npmmirror.com/@ethersproject/providers/-/providers-5.7.2.tgz", "integrity": "sha512-g34EWZ1WWAVgr4aptGlVBF8mhl3VWjv+8hoAnzStu8Ah22VHBsuGzP17eb6xDVRzw895G4W7vvx60lFFur/1Rg==", - "dev": true, "dependencies": { "@ethersproject/abstract-provider": "^5.7.0", "@ethersproject/abstract-signer": "^5.7.0", @@ -430,7 +411,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/random/-/random-5.7.0.tgz", "integrity": "sha512-19WjScqRA8IIeWclFme75VMXSBvi4e6InrUNuaR4s5pTF2qNhcGdCUwdxUVGtDDqC00sDLCO93jPQoDUH4HVmQ==", - "dev": true, "dependencies": { "@ethersproject/bytes": "^5.7.0", "@ethersproject/logger": "^5.7.0" @@ -440,7 +420,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/rlp/-/rlp-5.7.0.tgz", "integrity": "sha512-rBxzX2vK8mVF7b0Tol44t5Tb8gomOHkj5guL+HhzQ1yBh/ydjGnpw6at+X6Iw0Kp3OzzzkcKp8N9r0W4kYSs9w==", - "dev": true, "dependencies": { "@ethersproject/bytes": "^5.7.0", "@ethersproject/logger": "^5.7.0" @@ -450,7 +429,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/sha2/-/sha2-5.7.0.tgz", "integrity": "sha512-gKlH42riwb3KYp0reLsFTokByAKoJdgFCwI+CCiX/k+Jm2mbNs6oOaCjYQSlI1+XBVejwH2KrmCbMAT/GnRDQw==", - "dev": true, "dependencies": { "@ethersproject/bytes": "^5.7.0", "@ethersproject/logger": "^5.7.0", @@ -461,7 +439,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/signing-key/-/signing-key-5.7.0.tgz", "integrity": "sha512-MZdy2nL3wO0u7gkB4nA/pEf8lu1TlFswPNmy8AiYkfKTdO6eXBJyUdmHO/ehm/htHw9K/qF8ujnTyUAD+Ry54Q==", - "dev": true, "dependencies": { "@ethersproject/bytes": "^5.7.0", "@ethersproject/logger": "^5.7.0", @@ -475,7 +452,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/solidity/-/solidity-5.7.0.tgz", "integrity": "sha512-HmabMd2Dt/raavyaGukF4XxizWKhKQ24DoLtdNbBmNKUOPqwjsKQSdV9GQtj9CBEea9DlzETlVER1gYeXXBGaA==", - "dev": true, "dependencies": { "@ethersproject/bignumber": "^5.7.0", "@ethersproject/bytes": "^5.7.0", @@ -489,7 +465,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/strings/-/strings-5.7.0.tgz", "integrity": "sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg==", - "dev": true, "dependencies": { "@ethersproject/bytes": "^5.7.0", "@ethersproject/constants": "^5.7.0", @@ -500,7 +475,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/transactions/-/transactions-5.7.0.tgz", "integrity": "sha512-kmcNicCp1lp8qanMTC3RIikGgoJ80ztTyvtsFvCYpSCfkjhD0jZ2LOrnbcuxuToLIUYYf+4XwD1rP+B/erDIhQ==", - "dev": true, "dependencies": { "@ethersproject/address": "^5.7.0", "@ethersproject/bignumber": "^5.7.0", @@ -517,7 +491,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/units/-/units-5.7.0.tgz", "integrity": "sha512-pD3xLMy3SJu9kG5xDGI7+xhTEmGXlEqXU4OfNapmfnxLVY4EMSSRp7j1k7eezutBPH7RBN/7QPnwR7hzNlEFeg==", - "dev": true, "dependencies": { "@ethersproject/bignumber": "^5.7.0", "@ethersproject/constants": "^5.7.0", @@ -528,7 +501,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/wallet/-/wallet-5.7.0.tgz", "integrity": "sha512-MhmXlJXEJFBFVKrDLB4ZdDzxcBxQ3rLyCkhNqVu3CDYvR97E+8r01UgrI+TI99Le+aYm/in/0vp86guJuM7FCA==", - "dev": true, "dependencies": { "@ethersproject/abstract-provider": "^5.7.0", "@ethersproject/abstract-signer": "^5.7.0", @@ -551,7 +523,6 @@ "version": "5.7.1", "resolved": "https://registry.npmmirror.com/@ethersproject/web/-/web-5.7.1.tgz", "integrity": "sha512-Gueu8lSvyjBWL4cYsWsjh6MtMwM0+H4HvqFPZfB6dV8ctbP9zFAO73VG1cMWae0FLPCtz0peKPpZY8/ugJJX2w==", - "dev": true, "dependencies": { "@ethersproject/base64": "^5.7.0", "@ethersproject/bytes": "^5.7.0", @@ -564,7 +535,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/wordlists/-/wordlists-5.7.0.tgz", "integrity": "sha512-S2TFNJNfHWVHNE6cNDjbVlZ6MgE17MIxMbMg2zv3wn+3XSJGosL1m9ZVv3GXCf/2ymSsQ+hRI5IzoMJTG6aoVA==", - "dev": true, "dependencies": { "@ethersproject/bytes": "^5.7.0", "@ethersproject/hash": "^5.7.0", @@ -1277,8 +1247,7 @@ "node_modules/aes-js": { "version": "3.0.0", "resolved": "https://registry.npmmirror.com/aes-js/-/aes-js-3.0.0.tgz", - "integrity": "sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw==", - "dev": true + "integrity": "sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw==" }, "node_modules/agent-base": { "version": "6.0.2", @@ -1379,7 +1348,6 @@ "version": "1.1.0", "resolved": "https://registry.npmmirror.com/assertion-error/-/assertion-error-1.1.0.tgz", "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", - "dev": true, "engines": { "node": "*" } @@ -1402,8 +1370,7 @@ "node_modules/bech32": { "version": "1.1.4", "resolved": "https://registry.npmmirror.com/bech32/-/bech32-1.1.4.tgz", - "integrity": "sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==", - "dev": true + "integrity": "sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==" }, "node_modules/bignumber.js": { "version": "9.1.2", @@ -1432,8 +1399,7 @@ "node_modules/bn.js": { "version": "5.2.1", "resolved": "https://registry.npmmirror.com/bn.js/-/bn.js-5.2.1.tgz", - "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==", - "dev": true + "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==" }, "node_modules/boxen": { "version": "5.1.2", @@ -1552,8 +1518,7 @@ "node_modules/brorand": { "version": "1.1.0", "resolved": "https://registry.npmmirror.com/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==", - "dev": true + "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==" }, "node_modules/browser-stdout": { "version": "1.3.1", @@ -1644,7 +1609,6 @@ "version": "4.4.1", "resolved": "https://registry.npmmirror.com/chai/-/chai-4.4.1.tgz", "integrity": "sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==", - "dev": true, "dependencies": { "assertion-error": "^1.1.0", "check-error": "^1.0.3", @@ -1676,7 +1640,6 @@ "version": "1.0.3", "resolved": "https://registry.npmmirror.com/check-error/-/check-error-1.0.3.tgz", "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", - "dev": true, "dependencies": { "get-func-name": "^2.0.2" }, @@ -1855,7 +1818,6 @@ "version": "4.1.3", "resolved": "https://registry.npmmirror.com/deep-eql/-/deep-eql-4.1.3.tgz", "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", - "dev": true, "dependencies": { "type-detect": "^4.0.0" }, @@ -1893,7 +1855,6 @@ "version": "6.5.4", "resolved": "https://registry.npmmirror.com/elliptic/-/elliptic-6.5.4.tgz", "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", - "dev": true, "dependencies": { "bn.js": "^4.11.9", "brorand": "^1.1.0", @@ -1907,8 +1868,7 @@ "node_modules/elliptic/node_modules/bn.js": { "version": "4.12.0", "resolved": "https://registry.npmmirror.com/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", - "dev": true + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" }, "node_modules/emoji-regex": { "version": "8.0.0", @@ -2050,7 +2010,6 @@ "version": "5.7.2", "resolved": "https://registry.npmmirror.com/ethers/-/ethers-5.7.2.tgz", "integrity": "sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg==", - "dev": true, "dependencies": { "@ethersproject/abi": "5.7.0", "@ethersproject/abstract-provider": "5.7.0", @@ -2228,7 +2187,6 @@ "version": "2.0.2", "resolved": "https://registry.npmmirror.com/get-func-name/-/get-func-name-2.0.2.tgz", "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", - "dev": true, "engines": { "node": "*" } @@ -2370,7 +2328,6 @@ "version": "1.1.7", "resolved": "https://registry.npmmirror.com/hash.js/-/hash.js-1.1.7.tgz", "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", - "dev": true, "dependencies": { "inherits": "^2.0.3", "minimalistic-assert": "^1.0.1" @@ -2389,7 +2346,6 @@ "version": "1.0.1", "resolved": "https://registry.npmmirror.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz", "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", - "dev": true, "dependencies": { "hash.js": "^1.0.3", "minimalistic-assert": "^1.0.0", @@ -2465,8 +2421,7 @@ "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmmirror.com/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "node_modules/io-ts": { "version": "1.10.4", @@ -2559,8 +2514,7 @@ "node_modules/js-sha3": { "version": "0.8.0", "resolved": "https://registry.npmmirror.com/js-sha3/-/js-sha3-0.8.0.tgz", - "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==", - "dev": true + "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==" }, "node_modules/js-yaml": { "version": "4.1.0", @@ -2707,7 +2661,6 @@ "version": "2.3.7", "resolved": "https://registry.npmmirror.com/loupe/-/loupe-2.3.7.tgz", "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", - "dev": true, "dependencies": { "get-func-name": "^2.0.1" } @@ -2775,14 +2728,12 @@ "node_modules/minimalistic-assert": { "version": "1.0.1", "resolved": "https://registry.npmmirror.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", - "dev": true + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" }, "node_modules/minimalistic-crypto-utils": { "version": "1.0.1", "resolved": "https://registry.npmmirror.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", - "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==", - "dev": true + "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==" }, "node_modules/minimatch": { "version": "3.1.2", @@ -3017,7 +2968,6 @@ "version": "2.7.0", "resolved": "https://registry.npmmirror.com/node-fetch/-/node-fetch-2.7.0.tgz", "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", - "dev": true, "dependencies": { "whatwg-url": "^5.0.0" }, @@ -3170,7 +3120,6 @@ "version": "1.1.1", "resolved": "https://registry.npmmirror.com/pathval/-/pathval-1.1.1.tgz", "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", - "dev": true, "engines": { "node": "*" } @@ -3326,8 +3275,7 @@ "node_modules/scrypt-js": { "version": "3.0.1", "resolved": "https://registry.npmmirror.com/scrypt-js/-/scrypt-js-3.0.1.tgz", - "integrity": "sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==", - "dev": true + "integrity": "sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==" }, "node_modules/secp256k1": { "version": "4.0.3", @@ -3601,8 +3549,7 @@ "node_modules/tr46": { "version": "0.0.3", "resolved": "https://registry.npmmirror.com/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "dev": true + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" }, "node_modules/treeify": { "version": "1.1.0", @@ -3641,7 +3588,6 @@ "version": "4.0.8", "resolved": "https://registry.npmmirror.com/type-detect/-/type-detect-4.0.8.tgz", "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true, "engines": { "node": ">=4" } @@ -3776,14 +3722,12 @@ "node_modules/webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmmirror.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "dev": true + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" }, "node_modules/whatwg-url": { "version": "5.0.0", "resolved": "https://registry.npmmirror.com/whatwg-url/-/whatwg-url-5.0.0.tgz", "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "dev": true, "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" @@ -3861,7 +3805,6 @@ "version": "7.4.6", "resolved": "https://registry.npmmirror.com/ws/-/ws-7.4.6.tgz", "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==", - "dev": true, "engines": { "node": ">=8.3.0" }, diff --git a/examples/base/package.json b/examples/base/package.json index 787d94f..15ecc04 100644 --- a/examples/base/package.json +++ b/examples/base/package.json @@ -4,12 +4,13 @@ "version": "1.0.0", "scripts": {}, "devDependencies": { - "@eth-optimism/sdk": "^3.2.0", + "@eth-optimism/sdk": "^3.2.3", "@nomiclabs/hardhat-ethers": "^2.0.2", "ethers": "^5.7.2", "hardhat": "^2.9.1" }, "dependencies": { + "@eth-optimism/core-utils": "^0.13.1", "dotenv": "^16.4.1" } } diff --git a/examples/base/scripts/baseTasks.js b/examples/base/scripts/baseTasks.js index e200e4a..1a2ae32 100644 --- a/examples/base/scripts/baseTasks.js +++ b/examples/base/scripts/baseTasks.js @@ -7,8 +7,9 @@ const { changeFeeParams, encodeSetValidator, encodeChangeFeeParams, -} = require('../../utils/opstack-utils'); -const { L1_MAINNET_CONTRACTS, L1_TESTNET_CONTRACTS } = require('./constants'); + encodeL1ToL2Calldata, + checkL1TxStatus, +} = require('../../optimism/scripts/opstack-utils'); const { task, types } = require('hardhat/config'); require('dotenv').config(); @@ -21,16 +22,12 @@ async function initMessenger() { const l1Wallet = new ethers.Wallet(walletPrivateKey, l1Provider); const l2Wallet = new ethers.Wallet(walletPrivateKey, l2Provider); - const messengerL1Contracts = ethereumName !== 'ETHEREUM' ? L1_TESTNET_CONTRACTS : L1_MAINNET_CONTRACTS; const messenger = new base.CrossChainMessenger({ - l1ChainId: await l1Wallet.getChainId(), // 11155111 for Sepolia, 1 for Ethereum - l2ChainId: await l2Wallet.getChainId(), // 84532 for Base Sepolia, 8453 for Base Mainnet + l1ChainId: await l1Wallet.getChainId(), + l2ChainId: await l2Wallet.getChainId(), l1SignerOrProvider: l1Wallet, l2SignerOrProvider: l2Wallet, bedrock: true, - contracts: { - l1: messengerL1Contracts, - }, }); return { messenger, ethereumName, baseName }; @@ -43,7 +40,7 @@ task('syncBatchRoot', 'Forward message to L2').setAction(async (_, hre) => { const l2CurrentBlock = await l2Wallet.provider.getBlockNumber(); console.log(`Current block on l2: ${l2CurrentBlock}`); - const message = await syncBatchRoot(hre, messenger, ethereumName, baseName, 'base'); + const message = await syncBatchRoot(hre, messenger, ethereumName, baseName); // Waiting for the official base bridge to forward the message to L2 await messenger.waitForMessageStatus(message, base.MessageStatus.RELAYED); const rec = await messenger.getMessageReceipt(message, 0, l2CurrentBlock, 'latest'); @@ -63,7 +60,7 @@ task('syncL2Requests', 'Send sync point to arbitrator') const { messenger, ethereumName, baseName } = await initMessenger(); - await syncL2Requests(hre, messenger, ethereumName, baseName, 'base', txs); + await syncL2Requests(hre, messenger, ethereumName, baseName, txs); console.log('Done!'); @@ -86,7 +83,7 @@ task('setValidator', 'Set validator for zkLink') const l2CurrentBlock = await l2Wallet.provider.getBlockNumber(); console.log(`Current block on l2: ${l2CurrentBlock}`); - const message = await setValidator(hre, messenger, ethereumName, baseName, 'base', validatorAddr, isActive); + const message = await setValidator(hre, messenger, ethereumName, baseName, validatorAddr, isActive); // Waiting for the official base bridge to forward the message to L2 await messenger.waitForMessageStatus(message, base.MessageStatus.RELAYED); const rec = await messenger.getMessageReceipt(message, 0, l2CurrentBlock, 'latest'); @@ -101,7 +98,7 @@ task('changeFeeParams', 'Change fee params for zkLink').setAction(async (_, hre) const l2CurrentBlock = await l2Wallet.provider.getBlockNumber(); console.log(`Current block on l2: ${l2CurrentBlock}`); - const message = await changeFeeParams(hre, messenger, ethereumName, baseName, 'base'); + const message = await changeFeeParams(hre, messenger, ethereumName, baseName); // Waiting for the official base bridge to forward the message to L2 await messenger.waitForMessageStatus(message, base.MessageStatus.RELAYED); const rec = await messenger.getMessageReceipt(message, 0, l2CurrentBlock, 'latest'); @@ -112,7 +109,7 @@ task('changeFeeParams', 'Change fee params for zkLink').setAction(async (_, hre) task('encodeChangeFeeParams', 'Get the calldata of changing fee params for zkLink').setAction(async (_, hre) => { const { messenger, ethereumName, baseName } = await initMessenger(); - await encodeChangeFeeParams(hre, messenger, ethereumName, baseName, 'base'); + await encodeChangeFeeParams(hre, messenger, ethereumName, baseName); }); task('encodeSetValidator', 'Get the calldata of set validator for zkLink') @@ -125,5 +122,32 @@ task('encodeSetValidator', 'Get the calldata of set validator for zkLink') const { messenger, ethereumName, baseName } = await initMessenger(); - await encodeSetValidator(hre, messenger, ethereumName, baseName, 'base', validatorAddr, isActive); + await encodeSetValidator(hre, messenger, ethereumName, baseName, validatorAddr, isActive); + }); + +task('encodeL1ToL2Calldata', 'Encode call data for l1 to l2') + .addParam('to', 'The l2 target address', undefined, types.string) + .addParam('l2CallData', 'The l2 call data to target address', undefined, types.string) + .addParam('l2CallValue', 'The l2 call value to target address', undefined, types.int) + .setAction(async (taskArgs, hre) => { + const l2ToContractAddress = taskArgs.to; + const l2CallData = taskArgs.l2CallData; + const l2CallValue = taskArgs.l2CallValue; + console.log(`The l2 target contract address: ${l2ToContractAddress}`); + console.log(`The l2 call data to target address: ${l2CallData}`); + console.log(`The l2 call value to target address: ${l2CallValue}`); + + const { messenger, ethereumName, baseName } = await initMessenger(); + + await encodeL1ToL2Calldata(hre, messenger, ethereumName, baseName, l2ToContractAddress, l2CallData, l2CallValue); + }); + +task('checkL1TxStatus', 'Check the l1 tx status') + .addParam('l1TxHash', 'The l1 tx hash', undefined, types.string) + .setAction(async (taskArgs, hre) => { + const l1TxHash = taskArgs.l1TxHash; + console.log(`The l1 tx hash: ${l1TxHash}`); + + const { messenger, ethereumName, baseName } = await initMessenger(); + await checkL1TxStatus(hre, messenger, ethereumName, baseName, l1TxHash); }); diff --git a/examples/base/scripts/constants.js b/examples/base/scripts/constants.js deleted file mode 100644 index f735b82..0000000 --- a/examples/base/scripts/constants.js +++ /dev/null @@ -1,28 +0,0 @@ -// Testnet -const L1_TESTNET_CONTRACTS = { - StateCommitmentChain: '0x0000000000000000000000000000000000000000', - BondManager: '0x0000000000000000000000000000000000000000', - CanonicalTransactionChain: '0x0000000000000000000000000000000000000000', - AddressManager: '0x709c2B8ef4A9feFc629A8a2C1AF424Dc5BD6ad1B', - L1CrossDomainMessenger: '0xC34855F4De64F1840e5686e64278da901e261f20', - L1StandardBridge: '0xfd0Bf71F60660E2f608ed56e1659C450eB113120', - OptimismPortal: '0x49f53e41452C74589E85cA1677426Ba426459e85', - L2OutputOracle: '0x84457ca9D0163FbC4bbfe4Dfbb20ba46e48DF254', -}; - -// Mainnet -const L1_MAINNET_CONTRACTS = { - StateCommitmentChain: '0x0000000000000000000000000000000000000000', - BondManager: '0x0000000000000000000000000000000000000000', - CanonicalTransactionChain: '0x0000000000000000000000000000000000000000', - AddressManager: '0x8EfB6B5c4767B09Dc9AA6Af4eAA89F749522BaE2', - L1CrossDomainMessenger: '0x866E82a600A1414e583f7F13623F1aC5d58b0Afa', - L1StandardBridge: '0x3154Cf16ccdb4C6d922629664174b904d80F2C35', - OptimismPortal: '0x49048044D57e1C92A77f79988d21Fa8fAF74E97e', - L2OutputOracle: '0x56315b90c40730925ec5485cf004d835058518A0', -}; - -module.exports = { - L1_TESTNET_CONTRACTS, - L1_MAINNET_CONTRACTS, -}; diff --git a/examples/blast/package-lock.json b/examples/blast/package-lock.json index ca273b6..9480acf 100644 --- a/examples/blast/package-lock.json +++ b/examples/blast/package-lock.json @@ -9,10 +9,11 @@ "version": "1.0.0", "license": "MIT", "dependencies": { + "@eth-optimism/core-utils": "^0.13.1", "dotenv": "^16.4.1" }, "devDependencies": { - "@eth-optimism/sdk": "^3.2.0", + "@eth-optimism/sdk": "^3.2.3", "@nomiclabs/hardhat-ethers": "^2.0.2", "ethers": "^5.7.2", "hardhat": "^2.9.1" @@ -67,7 +68,6 @@ "version": "0.13.1", "resolved": "https://registry.npmmirror.com/@eth-optimism/core-utils/-/core-utils-0.13.1.tgz", "integrity": "sha512-1FvzbUmCEy9zSKPG1QWg2VfA2Cy90xBA9Wkp11lXXrz91zUPCNCNSRTujXWYIC86ketNsZp7p4njSf6lTycHCw==", - "dev": true, "hasInstallScript": true, "dependencies": { "@ethersproject/abi": "^5.7.0", @@ -87,11 +87,10 @@ } }, "node_modules/@eth-optimism/sdk": { - "version": "3.2.1", - "resolved": "https://registry.npmmirror.com/@eth-optimism/sdk/-/sdk-3.2.1.tgz", - "integrity": "sha512-COmnT2zRzFn2XhMW/OD1ML3gCrT6SO95YF3hV/Mx3G1G4Q6zOv09rwU1avH/OcqdDMBmZ/DTrZm+9OVmc+YPlQ==", + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/@eth-optimism/sdk/-/sdk-3.2.3.tgz", + "integrity": "sha512-e3XQTbbU+HTzsEv/VIsJpZifK6YZVlzEtF6tj/Vz/VIEDCjZk5JPcnCQOMVcs9ICI4EJyyur+y/+RU7fPa6qtg==", "dev": true, - "hasInstallScript": true, "dependencies": { "@eth-optimism/contracts": "0.6.0", "@eth-optimism/contracts-bedrock": "0.17.1", @@ -177,7 +176,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/abi/-/abi-5.7.0.tgz", "integrity": "sha512-351ktp42TiRcYB3H1OP8yajPeAQstMW/yCFokj/AthP9bLHzQFPlOrxOcwYEDkUAICmOHljvN4K39OMTMUa9RA==", - "dev": true, "dependencies": { "@ethersproject/address": "^5.7.0", "@ethersproject/bignumber": "^5.7.0", @@ -194,7 +192,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/abstract-provider/-/abstract-provider-5.7.0.tgz", "integrity": "sha512-R41c9UkchKCpAqStMYUpdunjo3pkEvZC3FAwZn5S5MGbXoMQOHIdHItezTETxAO5bevtMApSyEhn9+CHcDsWBw==", - "dev": true, "dependencies": { "@ethersproject/bignumber": "^5.7.0", "@ethersproject/bytes": "^5.7.0", @@ -209,7 +206,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/abstract-signer/-/abstract-signer-5.7.0.tgz", "integrity": "sha512-a16V8bq1/Cz+TGCkE2OPMTOUDLS3grCpdjoJCYNnVBbdYEMSgKrU0+B90s8b6H+ByYTBZN7a3g76jdIJi7UfKQ==", - "dev": true, "dependencies": { "@ethersproject/abstract-provider": "^5.7.0", "@ethersproject/bignumber": "^5.7.0", @@ -222,7 +218,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/address/-/address-5.7.0.tgz", "integrity": "sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA==", - "dev": true, "dependencies": { "@ethersproject/bignumber": "^5.7.0", "@ethersproject/bytes": "^5.7.0", @@ -235,7 +230,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/base64/-/base64-5.7.0.tgz", "integrity": "sha512-Dr8tcHt2mEbsZr/mwTPIQAf3Ai0Bks/7gTw9dSqk1mQvhW3XvRlmDJr/4n+wg1JmCl16NZue17CDh8xb/vZ0sQ==", - "dev": true, "dependencies": { "@ethersproject/bytes": "^5.7.0" } @@ -244,7 +238,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/basex/-/basex-5.7.0.tgz", "integrity": "sha512-ywlh43GwZLv2Voc2gQVTKBoVQ1mti3d8HK5aMxsfu/nRDnMmNqaSJ3r3n85HBByT8OpoY96SXM1FogC533T4zw==", - "dev": true, "dependencies": { "@ethersproject/bytes": "^5.7.0", "@ethersproject/properties": "^5.7.0" @@ -254,7 +247,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/bignumber/-/bignumber-5.7.0.tgz", "integrity": "sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw==", - "dev": true, "dependencies": { "@ethersproject/bytes": "^5.7.0", "@ethersproject/logger": "^5.7.0", @@ -265,7 +257,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/bytes/-/bytes-5.7.0.tgz", "integrity": "sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A==", - "dev": true, "dependencies": { "@ethersproject/logger": "^5.7.0" } @@ -274,7 +265,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/constants/-/constants-5.7.0.tgz", "integrity": "sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA==", - "dev": true, "dependencies": { "@ethersproject/bignumber": "^5.7.0" } @@ -283,7 +273,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/contracts/-/contracts-5.7.0.tgz", "integrity": "sha512-5GJbzEU3X+d33CdfPhcyS+z8MzsTrBGk/sc+G+59+tPa9yFkl6HQ9D6L0QMgNTA9q8dT0XKxxkyp883XsQvbbg==", - "dev": true, "dependencies": { "@ethersproject/abi": "^5.7.0", "@ethersproject/abstract-provider": "^5.7.0", @@ -301,7 +290,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/hash/-/hash-5.7.0.tgz", "integrity": "sha512-qX5WrQfnah1EFnO5zJv1v46a8HW0+E5xuBBDTwMFZLuVTx0tbU2kkx15NqdjxecrLGatQN9FGQKpb1FKdHCt+g==", - "dev": true, "dependencies": { "@ethersproject/abstract-signer": "^5.7.0", "@ethersproject/address": "^5.7.0", @@ -318,7 +306,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/hdnode/-/hdnode-5.7.0.tgz", "integrity": "sha512-OmyYo9EENBPPf4ERhR7oj6uAtUAhYGqOnIS+jE5pTXvdKBS99ikzq1E7Iv0ZQZ5V36Lqx1qZLeak0Ra16qpeOg==", - "dev": true, "dependencies": { "@ethersproject/abstract-signer": "^5.7.0", "@ethersproject/basex": "^5.7.0", @@ -338,7 +325,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/json-wallets/-/json-wallets-5.7.0.tgz", "integrity": "sha512-8oee5Xgu6+RKgJTkvEMl2wDgSPSAQ9MB/3JYjFV9jlKvcYHUXZC+cQp0njgmxdHkYWn8s6/IqIZYm0YWCjO/0g==", - "dev": true, "dependencies": { "@ethersproject/abstract-signer": "^5.7.0", "@ethersproject/address": "^5.7.0", @@ -359,7 +345,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/keccak256/-/keccak256-5.7.0.tgz", "integrity": "sha512-2UcPboeL/iW+pSg6vZ6ydF8tCnv3Iu/8tUmLLzWWGzxWKFFqOBQFLo6uLUv6BDrLgCDfN28RJ/wtByx+jZ4KBg==", - "dev": true, "dependencies": { "@ethersproject/bytes": "^5.7.0", "js-sha3": "0.8.0" @@ -368,14 +353,12 @@ "node_modules/@ethersproject/logger": { "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/logger/-/logger-5.7.0.tgz", - "integrity": "sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig==", - "dev": true + "integrity": "sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig==" }, "node_modules/@ethersproject/networks": { "version": "5.7.1", "resolved": "https://registry.npmmirror.com/@ethersproject/networks/-/networks-5.7.1.tgz", "integrity": "sha512-n/MufjFYv3yFcUyfhnXotyDlNdFb7onmkSy8aQERi2PjNcnWQ66xXxa3XlS8nCcA8aJKJjIIMNJTC7tu80GwpQ==", - "dev": true, "dependencies": { "@ethersproject/logger": "^5.7.0" } @@ -384,7 +367,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/pbkdf2/-/pbkdf2-5.7.0.tgz", "integrity": "sha512-oR/dBRZR6GTyaofd86DehG72hY6NpAjhabkhxgr3X2FpJtJuodEl2auADWBZfhDHgVCbu3/H/Ocq2uC6dpNjjw==", - "dev": true, "dependencies": { "@ethersproject/bytes": "^5.7.0", "@ethersproject/sha2": "^5.7.0" @@ -394,7 +376,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/properties/-/properties-5.7.0.tgz", "integrity": "sha512-J87jy8suntrAkIZtecpxEPxY//szqr1mlBaYlQ0r4RCaiD2hjheqF9s1LVE8vVuJCXisjIP+JgtK/Do54ej4Sw==", - "dev": true, "dependencies": { "@ethersproject/logger": "^5.7.0" } @@ -403,7 +384,6 @@ "version": "5.7.2", "resolved": "https://registry.npmmirror.com/@ethersproject/providers/-/providers-5.7.2.tgz", "integrity": "sha512-g34EWZ1WWAVgr4aptGlVBF8mhl3VWjv+8hoAnzStu8Ah22VHBsuGzP17eb6xDVRzw895G4W7vvx60lFFur/1Rg==", - "dev": true, "dependencies": { "@ethersproject/abstract-provider": "^5.7.0", "@ethersproject/abstract-signer": "^5.7.0", @@ -431,7 +411,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/random/-/random-5.7.0.tgz", "integrity": "sha512-19WjScqRA8IIeWclFme75VMXSBvi4e6InrUNuaR4s5pTF2qNhcGdCUwdxUVGtDDqC00sDLCO93jPQoDUH4HVmQ==", - "dev": true, "dependencies": { "@ethersproject/bytes": "^5.7.0", "@ethersproject/logger": "^5.7.0" @@ -441,7 +420,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/rlp/-/rlp-5.7.0.tgz", "integrity": "sha512-rBxzX2vK8mVF7b0Tol44t5Tb8gomOHkj5guL+HhzQ1yBh/ydjGnpw6at+X6Iw0Kp3OzzzkcKp8N9r0W4kYSs9w==", - "dev": true, "dependencies": { "@ethersproject/bytes": "^5.7.0", "@ethersproject/logger": "^5.7.0" @@ -451,7 +429,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/sha2/-/sha2-5.7.0.tgz", "integrity": "sha512-gKlH42riwb3KYp0reLsFTokByAKoJdgFCwI+CCiX/k+Jm2mbNs6oOaCjYQSlI1+XBVejwH2KrmCbMAT/GnRDQw==", - "dev": true, "dependencies": { "@ethersproject/bytes": "^5.7.0", "@ethersproject/logger": "^5.7.0", @@ -462,7 +439,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/signing-key/-/signing-key-5.7.0.tgz", "integrity": "sha512-MZdy2nL3wO0u7gkB4nA/pEf8lu1TlFswPNmy8AiYkfKTdO6eXBJyUdmHO/ehm/htHw9K/qF8ujnTyUAD+Ry54Q==", - "dev": true, "dependencies": { "@ethersproject/bytes": "^5.7.0", "@ethersproject/logger": "^5.7.0", @@ -476,7 +452,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/solidity/-/solidity-5.7.0.tgz", "integrity": "sha512-HmabMd2Dt/raavyaGukF4XxizWKhKQ24DoLtdNbBmNKUOPqwjsKQSdV9GQtj9CBEea9DlzETlVER1gYeXXBGaA==", - "dev": true, "dependencies": { "@ethersproject/bignumber": "^5.7.0", "@ethersproject/bytes": "^5.7.0", @@ -490,7 +465,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/strings/-/strings-5.7.0.tgz", "integrity": "sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg==", - "dev": true, "dependencies": { "@ethersproject/bytes": "^5.7.0", "@ethersproject/constants": "^5.7.0", @@ -501,7 +475,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/transactions/-/transactions-5.7.0.tgz", "integrity": "sha512-kmcNicCp1lp8qanMTC3RIikGgoJ80ztTyvtsFvCYpSCfkjhD0jZ2LOrnbcuxuToLIUYYf+4XwD1rP+B/erDIhQ==", - "dev": true, "dependencies": { "@ethersproject/address": "^5.7.0", "@ethersproject/bignumber": "^5.7.0", @@ -518,7 +491,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/units/-/units-5.7.0.tgz", "integrity": "sha512-pD3xLMy3SJu9kG5xDGI7+xhTEmGXlEqXU4OfNapmfnxLVY4EMSSRp7j1k7eezutBPH7RBN/7QPnwR7hzNlEFeg==", - "dev": true, "dependencies": { "@ethersproject/bignumber": "^5.7.0", "@ethersproject/constants": "^5.7.0", @@ -529,7 +501,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/wallet/-/wallet-5.7.0.tgz", "integrity": "sha512-MhmXlJXEJFBFVKrDLB4ZdDzxcBxQ3rLyCkhNqVu3CDYvR97E+8r01UgrI+TI99Le+aYm/in/0vp86guJuM7FCA==", - "dev": true, "dependencies": { "@ethersproject/abstract-provider": "^5.7.0", "@ethersproject/abstract-signer": "^5.7.0", @@ -552,7 +523,6 @@ "version": "5.7.1", "resolved": "https://registry.npmmirror.com/@ethersproject/web/-/web-5.7.1.tgz", "integrity": "sha512-Gueu8lSvyjBWL4cYsWsjh6MtMwM0+H4HvqFPZfB6dV8ctbP9zFAO73VG1cMWae0FLPCtz0peKPpZY8/ugJJX2w==", - "dev": true, "dependencies": { "@ethersproject/base64": "^5.7.0", "@ethersproject/bytes": "^5.7.0", @@ -565,7 +535,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/wordlists/-/wordlists-5.7.0.tgz", "integrity": "sha512-S2TFNJNfHWVHNE6cNDjbVlZ6MgE17MIxMbMg2zv3wn+3XSJGosL1m9ZVv3GXCf/2ymSsQ+hRI5IzoMJTG6aoVA==", - "dev": true, "dependencies": { "@ethersproject/bytes": "^5.7.0", "@ethersproject/hash": "^5.7.0", @@ -1451,8 +1420,7 @@ "node_modules/aes-js": { "version": "3.0.0", "resolved": "https://registry.npmmirror.com/aes-js/-/aes-js-3.0.0.tgz", - "integrity": "sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw==", - "dev": true + "integrity": "sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw==" }, "node_modules/agent-base": { "version": "6.0.2", @@ -1553,7 +1521,6 @@ "version": "1.1.0", "resolved": "https://registry.npmmirror.com/assertion-error/-/assertion-error-1.1.0.tgz", "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", - "dev": true, "engines": { "node": "*" } @@ -1576,8 +1543,7 @@ "node_modules/bech32": { "version": "1.1.4", "resolved": "https://registry.npmmirror.com/bech32/-/bech32-1.1.4.tgz", - "integrity": "sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==", - "dev": true + "integrity": "sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==" }, "node_modules/bigint-crypto-utils": { "version": "3.3.0", @@ -1615,8 +1581,7 @@ "node_modules/bn.js": { "version": "5.2.1", "resolved": "https://registry.npmmirror.com/bn.js/-/bn.js-5.2.1.tgz", - "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==", - "dev": true + "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==" }, "node_modules/boxen": { "version": "5.1.2", @@ -1735,8 +1700,7 @@ "node_modules/brorand": { "version": "1.1.0", "resolved": "https://registry.npmmirror.com/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==", - "dev": true + "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==" }, "node_modules/browser-stdout": { "version": "1.3.1", @@ -1827,7 +1791,6 @@ "version": "4.4.1", "resolved": "https://registry.npmmirror.com/chai/-/chai-4.4.1.tgz", "integrity": "sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==", - "dev": true, "dependencies": { "assertion-error": "^1.1.0", "check-error": "^1.0.3", @@ -1859,7 +1822,6 @@ "version": "1.0.3", "resolved": "https://registry.npmmirror.com/check-error/-/check-error-1.0.3.tgz", "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", - "dev": true, "dependencies": { "get-func-name": "^2.0.2" }, @@ -2038,7 +2000,6 @@ "version": "4.1.3", "resolved": "https://registry.npmmirror.com/deep-eql/-/deep-eql-4.1.3.tgz", "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", - "dev": true, "dependencies": { "type-detect": "^4.0.0" }, @@ -2076,7 +2037,6 @@ "version": "6.5.4", "resolved": "https://registry.npmmirror.com/elliptic/-/elliptic-6.5.4.tgz", "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", - "dev": true, "dependencies": { "bn.js": "^4.11.9", "brorand": "^1.1.0", @@ -2090,8 +2050,7 @@ "node_modules/elliptic/node_modules/bn.js": { "version": "4.12.0", "resolved": "https://registry.npmmirror.com/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", - "dev": true + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" }, "node_modules/emoji-regex": { "version": "8.0.0", @@ -2233,7 +2192,6 @@ "version": "5.7.2", "resolved": "https://registry.npmmirror.com/ethers/-/ethers-5.7.2.tgz", "integrity": "sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg==", - "dev": true, "dependencies": { "@ethersproject/abi": "5.7.0", "@ethersproject/abstract-provider": "5.7.0", @@ -2411,7 +2369,6 @@ "version": "2.0.2", "resolved": "https://registry.npmmirror.com/get-func-name/-/get-func-name-2.0.2.tgz", "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", - "dev": true, "engines": { "node": "*" } @@ -2566,7 +2523,6 @@ "version": "1.1.7", "resolved": "https://registry.npmmirror.com/hash.js/-/hash.js-1.1.7.tgz", "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", - "dev": true, "dependencies": { "inherits": "^2.0.3", "minimalistic-assert": "^1.0.1" @@ -2585,7 +2541,6 @@ "version": "1.0.1", "resolved": "https://registry.npmmirror.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz", "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", - "dev": true, "dependencies": { "hash.js": "^1.0.3", "minimalistic-assert": "^1.0.0", @@ -2661,8 +2616,7 @@ "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmmirror.com/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "node_modules/io-ts": { "version": "1.10.4", @@ -2761,8 +2715,7 @@ "node_modules/js-sha3": { "version": "0.8.0", "resolved": "https://registry.npmmirror.com/js-sha3/-/js-sha3-0.8.0.tgz", - "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==", - "dev": true + "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==" }, "node_modules/js-yaml": { "version": "4.1.0", @@ -2909,7 +2862,6 @@ "version": "2.3.7", "resolved": "https://registry.npmmirror.com/loupe/-/loupe-2.3.7.tgz", "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", - "dev": true, "dependencies": { "get-func-name": "^2.0.1" } @@ -2974,14 +2926,12 @@ "node_modules/minimalistic-assert": { "version": "1.0.1", "resolved": "https://registry.npmmirror.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", - "dev": true + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" }, "node_modules/minimalistic-crypto-utils": { "version": "1.0.1", "resolved": "https://registry.npmmirror.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", - "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==", - "dev": true + "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==" }, "node_modules/minimatch": { "version": "3.1.2", @@ -3216,7 +3166,6 @@ "version": "2.7.0", "resolved": "https://registry.npmmirror.com/node-fetch/-/node-fetch-2.7.0.tgz", "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", - "dev": true, "dependencies": { "whatwg-url": "^5.0.0" }, @@ -3369,7 +3318,6 @@ "version": "1.1.1", "resolved": "https://registry.npmmirror.com/pathval/-/pathval-1.1.1.tgz", "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", - "dev": true, "engines": { "node": "*" } @@ -3540,8 +3488,7 @@ "node_modules/scrypt-js": { "version": "3.0.1", "resolved": "https://registry.npmmirror.com/scrypt-js/-/scrypt-js-3.0.1.tgz", - "integrity": "sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==", - "dev": true + "integrity": "sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==" }, "node_modules/secp256k1": { "version": "4.0.3", @@ -3833,8 +3780,7 @@ "node_modules/tr46": { "version": "0.0.3", "resolved": "https://registry.npmmirror.com/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "dev": true + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" }, "node_modules/treeify": { "version": "1.1.0", @@ -3873,7 +3819,6 @@ "version": "4.0.8", "resolved": "https://registry.npmmirror.com/type-detect/-/type-detect-4.0.8.tgz", "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true, "engines": { "node": ">=4" } @@ -4008,14 +3953,12 @@ "node_modules/webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmmirror.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "dev": true + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" }, "node_modules/whatwg-url": { "version": "5.0.0", "resolved": "https://registry.npmmirror.com/whatwg-url/-/whatwg-url-5.0.0.tgz", "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "dev": true, "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" @@ -4093,7 +4036,6 @@ "version": "7.4.6", "resolved": "https://registry.npmmirror.com/ws/-/ws-7.4.6.tgz", "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==", - "dev": true, "engines": { "node": ">=8.3.0" }, diff --git a/examples/blast/package.json b/examples/blast/package.json index 80e7f85..40ed0a7 100644 --- a/examples/blast/package.json +++ b/examples/blast/package.json @@ -4,12 +4,13 @@ "version": "1.0.0", "scripts": {}, "devDependencies": { - "@eth-optimism/sdk": "^3.2.0", + "@eth-optimism/sdk": "^3.2.3", "@nomiclabs/hardhat-ethers": "^2.0.2", "ethers": "^5.7.2", "hardhat": "^2.9.1" }, "dependencies": { + "@eth-optimism/core-utils": "^0.13.1", "dotenv": "^16.4.1" } } diff --git a/examples/blast/scripts/blastTasks.js b/examples/blast/scripts/blastTasks.js index b308b1a..58617cb 100644 --- a/examples/blast/scripts/blastTasks.js +++ b/examples/blast/scripts/blastTasks.js @@ -7,7 +7,9 @@ const { changeFeeParams, encodeSetValidator, encodeChangeFeeParams, -} = require('../../utils/opstack-utils'); + encodeL1ToL2Calldata, + checkL1TxStatus, +} = require('../../optimism/scripts/opstack-utils'); const { MESSAGE_PASSER_ABI, MESSAGE_PASSER_ADDRESS, @@ -34,8 +36,8 @@ async function initMessenger() { const yieldManagerAddress = ethereumName !== 'ETHEREUM' ? YIELD_MANAGER_TESTNET_ADDRESS : YIELD_MANAGER_MAINNET_ADDRESS; const messenger = new blast.CrossChainMessenger({ - l1ChainId: await l1Wallet.getChainId(), // 11155111 for Sepolia, 1 for Ethereum - l2ChainId: await l2Wallet.getChainId(), // 168587773 for Blast Testnet, 81457 for Blast Mainnet + l1ChainId: await l1Wallet.getChainId(), + l2ChainId: await l2Wallet.getChainId(), l1SignerOrProvider: l1Wallet, l2SignerOrProvider: l2Wallet, bedrock: true, @@ -54,6 +56,19 @@ async function initMessenger() { return { messenger, messengerL1Contracts, yieldManagerAddress, ethereumName, blastName }; } +task('depositETH', 'Deposit eth to L2') + .addParam('amount', 'The deposit amount', undefined, types.string, false) + .setAction(async taskArgs => { + const amount = taskArgs.amount; + console.log(`The deposit amount: ${amount}`); + const { messenger } = await initMessenger(); + + const tx = await messenger.depositETH(ethers.utils.parseEther(amount)); + console.log(`The tx hash: ${tx.hash}`); + await tx.wait(); + console.log(`Deposit success`); + }); + task('syncBatchRoot', 'Forward message to L2').setAction(async (_, hre) => { const { messenger, ethereumName, blastName } = await initMessenger(); @@ -61,7 +76,7 @@ task('syncBatchRoot', 'Forward message to L2').setAction(async (_, hre) => { const l2CurrentBlock = await l2Wallet.provider.getBlockNumber(); console.log(`Current block on l2: ${l2CurrentBlock}`); - const message = await syncBatchRoot(hre, messenger, ethereumName, blastName, 'blast'); + const message = await syncBatchRoot(hre, messenger, ethereumName, blastName); await messenger.waitForMessageStatus(message, blast.MessageStatus.RELAYED); const rec = await messenger.getMessageReceipt(message, 0, l2CurrentBlock, 'latest'); @@ -100,7 +115,7 @@ task('syncL2Requests', 'Send sync point to arbitrator') const l2WalletBalance = ethers.utils.formatEther(await l2Wallet.getBalance()); console.log(`${l2WalletAddress} balance on l2: ${l2WalletBalance} ether`); - const { zkLinkAddr } = await getContractAddresses(ethereumName, blastName, 'blast'); + const { zkLinkAddr } = await getContractAddresses(ethereumName, blastName); const zkLink = await hre.ethers.getContractAt('ZkLink', zkLinkAddr, l2Wallet); const calldata = zkLink.interface.encodeFunctionData('syncL2Requests', [txs]); @@ -230,7 +245,7 @@ task('setValidator', 'Set validator for zkLink') const l2CurrentBlock = await l2Wallet.provider.getBlockNumber(); console.log(`Current block on l2: ${l2CurrentBlock}`); - const message = await setValidator(hre, messenger, ethereumName, blastName, 'blast', validatorAddr, isActive); + const message = await setValidator(hre, messenger, ethereumName, blastName, validatorAddr, isActive); await messenger.waitForMessageStatus(message, blast.MessageStatus.RELAYED); const rec = await messenger.getMessageReceipt(message, 0, l2CurrentBlock, 'latest'); @@ -245,7 +260,7 @@ task('changeFeeParams', 'Change fee params for zkLink').setAction(async (taskArg const l2CurrentBlock = await l2Wallet.provider.getBlockNumber(); console.log(`Current block on l2: ${l2CurrentBlock}`); - const message = await changeFeeParams(hre, messenger, ethereumName, blastName, 'blast'); + const message = await changeFeeParams(hre, messenger, ethereumName, blastName); await messenger.waitForMessageStatus(message, blast.MessageStatus.RELAYED); const rec = await messenger.getMessageReceipt(message, 0, l2CurrentBlock, 'latest'); @@ -256,7 +271,7 @@ task('changeFeeParams', 'Change fee params for zkLink').setAction(async (taskArg task('encodeChangeFeeParams', 'Get the calldata of changing fee params for zkLink').setAction(async (_, hre) => { const { messenger, ethereumName, blastName } = await initMessenger(); - await encodeChangeFeeParams(hre, messenger, ethereumName, blastName, 'blast'); + await encodeChangeFeeParams(hre, messenger, ethereumName, blastName); }); task('encodeSetValidator', 'Get the calldata of set validator for zkLink') @@ -269,5 +284,40 @@ task('encodeSetValidator', 'Get the calldata of set validator for zkLink') const { messenger, ethereumName, blastName } = await initMessenger(); - await encodeSetValidator(hre, messenger, ethereumName, blastName, 'blast', validatorAddr, isActive); + await encodeSetValidator(hre, messenger, ethereumName, blastName, validatorAddr, isActive); + }); + +task('encodeL1ToL2Calldata', 'Encode call data for l1 to l2') + .addParam('to', 'The l2 target address', undefined, types.string) + .addParam('l2CallData', 'The l2 call data to target address', undefined, types.string) + .addParam('l2CallValue', 'The l2 call value to target address', undefined, types.int) + .setAction(async (taskArgs, hre) => { + const l2ToContractAddress = taskArgs.to; + const l2CallData = taskArgs.l2CallData; + const l2CallValue = taskArgs.l2CallValue; + console.log(`The l2 target contract address: ${l2ToContractAddress}`); + console.log(`The l2 call data to target address: ${l2CallData}`); + console.log(`The l2 call value to target address: ${l2CallValue}`); + + const initInfo = await initMessenger(); + + await encodeL1ToL2Calldata( + hre, + initInfo.messenger, + initInfo.ethereumName, + initInfo.blastName, + l2ToContractAddress, + l2CallData, + l2CallValue, + ); + }); + +task('checkL1TxStatus', 'Check the l1 tx status') + .addParam('l1TxHash', 'The l1 tx hash', undefined, types.string) + .setAction(async (taskArgs, hre) => { + const l1TxHash = taskArgs.l1TxHash; + console.log(`The l1 tx hash: ${l1TxHash}`); + + const initInfo = await initMessenger(); + await checkL1TxStatus(hre, initInfo.messenger, initInfo.ethereumName, initInfo.blastName, l1TxHash); }); diff --git a/examples/linea/hardhat.config.js b/examples/linea/hardhat.config.js index d6ffded..d9849f3 100644 --- a/examples/linea/hardhat.config.js +++ b/examples/linea/hardhat.config.js @@ -4,6 +4,7 @@ require('./scripts/syncBatchRoot'); require('./scripts/setValidator'); require('./scripts/changeFeeParams'); require('./scripts/setSecondaryGateway'); +require('./scripts/governance'); const BaseConfig = require('../../hardhat.base.config'); diff --git a/examples/linea/scripts/changeFeeParams.js b/examples/linea/scripts/changeFeeParams.js index 44324a1..fda6d8a 100644 --- a/examples/linea/scripts/changeFeeParams.js +++ b/examples/linea/scripts/changeFeeParams.js @@ -1,15 +1,11 @@ const { JsonRpcProvider, Wallet, formatEther } = require('ethers'); -const { LineaSDK, OnChainMessageStatus } = require('@consensys/linea-sdk'); const { readDeployContract, getLogName } = require('../../../script/utils'); const logName = require('../../../script/deploy_log_name'); const { task } = require('hardhat/config'); +const { claimL1ToL2Message } = require('./common'); require('dotenv').config(); -function sleep(ms) { - return new Promise(resolve => setTimeout(resolve, ms)); -} - task('changeFeeParams', 'Change fee params for zkLink').setAction(async (taskArgs, hre) => { const walletPrivateKey = process.env.DEVNET_PRIVKEY; const l1Provider = new JsonRpcProvider(process.env.L1RPC); @@ -18,16 +14,6 @@ task('changeFeeParams', 'Change fee params for zkLink').setAction(async (taskArg const lineaName = process.env.LINEA; const l1Wallet = new Wallet(walletPrivateKey, l1Provider); const l2Wallet = new Wallet(walletPrivateKey, l2Provider); - const sdk = new LineaSDK({ - l1RpcUrl: process.env.L1RPC ?? '', - l2RpcUrl: process.env.L2RPC ?? '', - l1SignerPrivateKey: walletPrivateKey ?? '', - l2SignerPrivateKey: walletPrivateKey ?? '', - network: ethereumName === 'GOERLI' ? 'linea-goerli' : 'linea-mainnet', - mode: 'read-write', - }); - const lineaL1Contract = sdk.getL1Contract(); - const lineaL2Contract = sdk.getL2Contract(); const l1WalletAddress = await l1Wallet.getAddress(); const l1WalletBalance = formatEther(await l1Provider.getBalance(l1WalletAddress)); @@ -71,29 +57,8 @@ task('changeFeeParams', 'Change fee params for zkLink').setAction(async (taskArg const adapterParams = '0x'; const { INIT_FEE_PARAMS } = require('../../../script/zksync_era'); let tx = await arbitrator.changeFeeParams(lineaL1GatewayAddr, INIT_FEE_PARAMS, adapterParams); - console.log(`The tx hash: ${tx.hash}`); + console.log(`The l1 tx hash: ${tx.hash}`); await tx.wait(); - console.log(`The tx confirmed`); - - /** - * Query the transaction status on L2 via messageHash. - */ - const message = (await lineaL1Contract.getMessagesByTransactionHash(tx.hash)).pop(); - - // Waiting for the official Linea bridge to forward the message to L2 - // And manually claim the message on L2 - /*eslint no-constant-condition: ["error", { "checkLoops": false }]*/ - while (true) { - const messageStatus = await lineaL2Contract.getMessageStatus(message.messageHash); - console.log(`The message status: ${messageStatus}`); - if (messageStatus === OnChainMessageStatus.CLAIMABLE) { - const tx = await lineaL2Contract.claim(message); - console.log(`The tx hash: ${tx.hash}`); - await tx.wait(); - console.log(`The tx confirmed`); - break; - } - await sleep(60 * 1000); - } - console.log('Done'); + console.log(`The l1 tx confirmed`); + await claimL1ToL2Message(tx.hash); }); diff --git a/examples/linea/scripts/common.js b/examples/linea/scripts/common.js new file mode 100644 index 0000000..991f484 --- /dev/null +++ b/examples/linea/scripts/common.js @@ -0,0 +1,98 @@ +const { LineaSDK, OnChainMessageStatus } = require('@consensys/linea-sdk'); + +function initSDK() { + const walletPrivateKey = process.env.DEVNET_PRIVKEY; + const ethereumName = process.env.ETHEREUM; + const sdk = new LineaSDK({ + l1RpcUrl: process.env.L1RPC ?? '', + l2RpcUrl: process.env.L2RPC ?? '', + l1SignerPrivateKey: walletPrivateKey ?? '', + l2SignerPrivateKey: walletPrivateKey ?? '', + network: ethereumName === 'GOERLI' ? 'linea-goerli' : ethereumName === 'SEPOLIA' ? 'localhost' : 'linea-mainnet', // sdk not support SEPOLIA + mode: 'read-write', + }); + const sepoliaContracts = { + l1ContractAddress: '0xB218f8A4Bc926cF1cA7b3423c154a0D627Bdb7E5', + l2ContractAddress: '0x971e727e956690b9957be6d51Ec16E73AcAC83A7', + }; + const lineaL1Contract = sdk.getL1Contract(sepoliaContracts.l1ContractAddress); + const lineaL2Contract = sdk.getL2Contract(sepoliaContracts.l2ContractAddress); + const lineaL1ClaimingService = sdk.getL1ClaimingService( + sepoliaContracts.l1ContractAddress, + sepoliaContracts.l2ContractAddress, + ); + return { lineaL1Contract, lineaL2Contract, lineaL1ClaimingService }; +} + +async function claimL1ToL2Message(l1TxHash) { + const sdkInit = initSDK(); + const lineaL1Contract = sdkInit.lineaL1Contract; + const lineaL2Contract = sdkInit.lineaL2Contract; + + /** + * Query the transaction status on L2 via messageHash. + */ + const message = (await lineaL1Contract.getMessagesByTransactionHash(l1TxHash)).pop(); + + // Waiting for the official Linea bridge to forward the message to L2 + // And manually claim the message on L2 + /*eslint no-constant-condition: ["error", { "checkLoops": false }]*/ + while (true) { + const messageStatus = await lineaL2Contract.getMessageStatus(message.messageHash); + console.log(`The message status: ${messageStatus}`); + if (messageStatus === OnChainMessageStatus.CLAIMABLE) { + const tx = await lineaL2Contract.claim(message); + console.log(`The tx hash: ${tx.hash}`); + await tx.wait(); + console.log(`The tx confirmed`); + break; + } + await sleep(60 * 1000); + } +} + +async function claimL2ToL1Message(l2TxHash) { + const sdkInit = initSDK(); + const lineaL1ClaimingService = sdkInit.lineaL1ClaimingService; + const lineaL2Contract = sdkInit.lineaL2Contract; + + /** + * Query the message informations on L2 via txHash. + */ + const message = (await lineaL2Contract.getMessagesByTransactionHash(l2TxHash)).pop(); + console.log(`The messageSender: ${message.messageSender}`); + console.log(`The destination: ${message.destination}`); + console.log(`The fee: ${message.fee}`); + console.log(`The value: ${message.value}`); + console.log(`The messageNonce: ${message.messageNonce}`); + console.log(`The calldata: ${message.calldata}`); + console.log(`The messageHash: ${message.messageHash}`); + + // Waiting for the official Linea bridge to forward the message to L1 + // And manually claim the message on L1 + /*eslint no-constant-condition: ["error", { "checkLoops": false }]*/ + while (true) { + /** + * Query the transaction status on L1 via messageHash. + */ + const messageStatus = await lineaL1ClaimingService.getMessageStatus(message.messageHash); + console.log(`The message status: ${messageStatus}`); + if (messageStatus === OnChainMessageStatus.CLAIMABLE) { + const tx = await lineaL1ClaimingService.claimMessage(message); + console.log(`The tx hash: ${tx.hash}`); + await tx.wait(); + console.log(`The tx confirmed`); + break; + } + await sleep(60 * 1000 * 30); + } +} + +function sleep(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); +} + +module.exports = { + claimL1ToL2Message, + claimL2ToL1Message, +}; diff --git a/examples/linea/scripts/governance.js b/examples/linea/scripts/governance.js new file mode 100644 index 0000000..56f0165 --- /dev/null +++ b/examples/linea/scripts/governance.js @@ -0,0 +1,86 @@ +const { JsonRpcProvider, formatEther } = require('ethers'); +const { readDeployContract } = require('../../../script/utils'); +const logName = require('../../../script/deploy_log_name'); +const { task, types } = require('hardhat/config'); +const { zkLinkConfig } = require('../../../script/zklink_config'); +const { claimL1ToL2Message } = require('./common'); + +require('dotenv').config(); + +task('encodeL1ToL2Calldata', 'Encode call data for l1 to l2') + .addParam('to', 'The l2 target address', undefined, types.string) + .addParam('l2CallData', 'The l2 call data to target address', undefined, types.string) + .addParam('l2CallValue', 'The l2 call value to target address', undefined, types.int) + .setAction(async (taskArgs, hre) => { + const l2ToContractAddress = taskArgs.to; + const l2CallData = taskArgs.l2CallData; + const l2CallValue = BigInt(taskArgs.l2CallValue); + console.log(`The l2 target contract address: ${l2ToContractAddress}`); + console.log(`The l2 call data to target address: ${l2CallData}`); + console.log(`The l2 call value to target address: ${l2CallValue}`); + + const l2Provider = new JsonRpcProvider(process.env.L2RPC); + const lineaName = process.env.LINEA; + + const l2ChainInfo = zkLinkConfig[lineaName]; + if (l2ChainInfo === undefined) { + console.log('The l2 chain info not exist'); + return; + } + const messageServiceAddr = l2ChainInfo['l1Gateway']['constructParams'][0]; + if (messageServiceAddr === undefined) { + console.log('The arbitrum inbox address not exist'); + return; + } + console.log(`The linea l1 message service address: ${messageServiceAddr}`); + + const lineaL2GovernanceAddr = readDeployContract( + logName.DEPLOY_LINEA_L2_GOVERNANCE_LOG_PREFIX, + logName.DEPLOY_LOG_GOVERNANCE, + lineaName, + ); + if (lineaL2GovernanceAddr === undefined) { + console.log('linea l2 governance address not exist'); + return; + } + console.log(`The linea l2 governance address: ${lineaL2GovernanceAddr}`); + if (l2CallValue > 0) { + const l2GovernanceBalance = await l2Provider.getBalance(lineaL2GovernanceAddr); + console.log(`The linea l2 governance balance: ${formatEther(l2GovernanceBalance)} ETH`); + if (l2GovernanceBalance < l2CallValue) { + console.log(`Please transfer some eth to linea l2 governance`); + return; + } + } + + const call = { + target: l2ToContractAddress, + value: l2CallValue, + data: l2CallData, + }; + const lineaL2Governance = await hre.ethers.getContractAt( + 'LineaL2Governance', + '0x0000000000000000000000000000000000000000', + ); + const lineaL2GovernanceCallData = lineaL2Governance.interface.encodeFunctionData('execute', [[call]]); + const lineaMessageService = await hre.ethers.getContractAt( + 'IMessageService', + '0x0000000000000000000000000000000000000000', + ); + const l1ToL2Calldata = lineaMessageService.interface.encodeFunctionData('sendMessage', [ + lineaL2GovernanceAddr, + 0, + lineaL2GovernanceCallData, + ]); + console.log(`The l1 to l2 call target: ${messageServiceAddr}`); + console.log(`The l1 to l2 call data: ${l1ToL2Calldata}`); + console.log(`The l1 to l2 call value: 0`); + }); + +task('checkL1TxStatus', 'Check the l1 tx status') + .addParam('l1TxHash', 'The l1 tx hash', undefined, types.string) + .setAction(async taskArgs => { + const l1TxHash = taskArgs.l1TxHash; + console.log(`The l1 tx hash: ${l1TxHash}`); + await claimL1ToL2Message(l1TxHash); + }); diff --git a/examples/linea/scripts/setSecondaryGateway.js b/examples/linea/scripts/setSecondaryGateway.js index 18a60fa..31b77d8 100644 --- a/examples/linea/scripts/setSecondaryGateway.js +++ b/examples/linea/scripts/setSecondaryGateway.js @@ -1,15 +1,11 @@ const { JsonRpcProvider, Wallet, formatEther } = require('ethers'); -const { LineaSDK, OnChainMessageStatus } = require('@consensys/linea-sdk'); const { readDeployLogField, readDeployContract, getLogName } = require('../../../script/utils'); const logName = require('../../../script/deploy_log_name'); const { task, types } = require('hardhat/config'); +const { claimL1ToL2Message } = require('./common'); require('dotenv').config(); -function sleep(ms) { - return new Promise(resolve => setTimeout(resolve, ms)); -} - task('setSecondaryGateway', 'Set secondary gateway') .addOptionalParam( 'arbitrator', @@ -39,16 +35,6 @@ task('setSecondaryGateway', 'Set secondary gateway') const l2Provider = new JsonRpcProvider(process.env.L2RPC); const l1Wallet = new Wallet(walletPrivateKey, l1Provider); const l2Wallet = new Wallet(walletPrivateKey, l2Provider); - const sdk = new LineaSDK({ - l1RpcUrl: process.env.L1RPC ?? '', - l2RpcUrl: process.env.L2RPC ?? '', - l1SignerPrivateKey: walletPrivateKey ?? '', - l2SignerPrivateKey: walletPrivateKey ?? '', - network: ethereumName === 'GOERLI' ? 'linea-goerli' : 'linea-mainnet', - mode: 'read-write', - }); - const lineaL1Contract = sdk.getL1Contract(); - const lineaL2Contract = sdk.getL2Contract(); const l1WalletAddress = await l1Wallet.getAddress(); const l1WalletBalance = formatEther(await l1Provider.getBalance(l1WalletAddress)); @@ -87,31 +73,10 @@ task('setSecondaryGateway', 'Set secondary gateway') const arbitrator = await hre.ethers.getContractAt('Arbitrator', arbitratorAddr, l1Wallet); const adapterParams = '0x'; let tx = await arbitrator.setSecondaryChainGateway(l1GatewayAddr, active, adapterParams); - console.log(`The tx hash: ${tx.hash}`); + console.log(`The l1 tx hash: ${tx.hash}`); await tx.wait(); - console.log(`The tx confirmed`); - - /** - * Query the transaction status on L2 via messageHash. - */ - const message = (await lineaL1Contract.getMessagesByTransactionHash(tx.hash)).pop(); - - // Waiting for the official Linea bridge to forward the message to L2 - // And manually claim the message on L2 - /*eslint no-constant-condition: ["error", { "checkLoops": false }]*/ - while (true) { - const messageStatus = await lineaL2Contract.getMessageStatus(message.messageHash); - console.log(`The message status: ${messageStatus}`); - if (messageStatus === OnChainMessageStatus.CLAIMABLE) { - const tx = await lineaL2Contract.claim(message); - console.log(`The tx hash: ${tx.hash}`); - await tx.wait(); - console.log(`The tx confirmed`); - break; - } - await sleep(60 * 1000); - } - console.log('Done'); + console.log(`The l1 tx confirmed`); + await claimL1ToL2Message(tx.hash); }); task('encodeSetSecondaryGateway', 'Get the calldata of set secondary gateway') diff --git a/examples/linea/scripts/setValidator.js b/examples/linea/scripts/setValidator.js index f02b8bd..aa31f4c 100644 --- a/examples/linea/scripts/setValidator.js +++ b/examples/linea/scripts/setValidator.js @@ -1,15 +1,11 @@ const { JsonRpcProvider, Wallet, formatEther } = require('ethers'); -const { LineaSDK, OnChainMessageStatus } = require('@consensys/linea-sdk'); const { readDeployContract, getLogName } = require('../../../script/utils'); const logName = require('../../../script/deploy_log_name'); const { task, types } = require('hardhat/config'); +const { claimL1ToL2Message } = require('./common'); require('dotenv').config(); -function sleep(ms) { - return new Promise(resolve => setTimeout(resolve, ms)); -} - task('setValidator', 'Set validator for zkLink') .addParam('validator', 'Validator Address', undefined, types.string) .addOptionalParam('active', 'Whether to activate the validator address', true, types.boolean) @@ -25,16 +21,6 @@ task('setValidator', 'Set validator for zkLink') const lineaName = process.env.LINEA; const l1Wallet = new Wallet(walletPrivateKey, l1Provider); const l2Wallet = new Wallet(walletPrivateKey, l2Provider); - const sdk = new LineaSDK({ - l1RpcUrl: process.env.L1RPC ?? '', - l2RpcUrl: process.env.L2RPC ?? '', - l1SignerPrivateKey: walletPrivateKey ?? '', - l2SignerPrivateKey: walletPrivateKey ?? '', - network: ethereumName === 'GOERLI' ? 'linea-goerli' : 'linea-mainnet', - mode: 'read-write', - }); - const lineaL1Contract = sdk.getL1Contract(); - const lineaL2Contract = sdk.getL2Contract(); const l1WalletAddress = await l1Wallet.getAddress(); const l1WalletBalance = formatEther(await l1Provider.getBalance(l1WalletAddress)); @@ -77,29 +63,8 @@ task('setValidator', 'Set validator for zkLink') const arbitrator = await hre.ethers.getContractAt('Arbitrator', arbitratorAddr, l1Wallet); const adapterParams = '0x'; let tx = await arbitrator.setValidator(lineaL1GatewayAddr, validatorAddr, isActive, adapterParams); - console.log(`The tx hash: ${tx.hash}`); + console.log(`The l1 tx hash: ${tx.hash}`); await tx.wait(); - console.log(`The tx confirmed`); - - /** - * Query the transaction status on L2 via messageHash. - */ - const message = (await lineaL1Contract.getMessagesByTransactionHash(tx.hash)).pop(); - - // Waiting for the official Linea bridge to forward the message to L2 - // And manually claim the message on L2 - /*eslint no-constant-condition: ["error", { "checkLoops": false }]*/ - while (true) { - const messageStatus = await lineaL2Contract.getMessageStatus(message.messageHash); - console.log(`The message status: ${messageStatus}`); - if (messageStatus === OnChainMessageStatus.CLAIMABLE) { - const tx = await lineaL2Contract.claim(message); - console.log(`The tx hash: ${tx.hash}`); - await tx.wait(); - console.log(`The tx confirmed`); - break; - } - await sleep(60 * 1000); - } - console.log('Done'); + console.log(`The l1 tx confirmed`); + await claimL1ToL2Message(tx.hash); }); diff --git a/examples/linea/scripts/syncBatchRoot.js b/examples/linea/scripts/syncBatchRoot.js index e1f118f..c56523e 100644 --- a/examples/linea/scripts/syncBatchRoot.js +++ b/examples/linea/scripts/syncBatchRoot.js @@ -1,15 +1,11 @@ const { JsonRpcProvider, Wallet, formatEther, keccak256, toUtf8Bytes } = require('ethers'); -const { LineaSDK, OnChainMessageStatus } = require('@consensys/linea-sdk'); const { readDeployContract, getLogName } = require('../../../script/utils'); const logName = require('../../../script/deploy_log_name'); const { task } = require('hardhat/config'); +const { claimL1ToL2Message } = require('./common'); require('dotenv').config(); -function sleep(ms) { - return new Promise(resolve => setTimeout(resolve, ms)); -} - task('syncBatchRoot', 'Forward message to L2').setAction(async (taskArgs, hre) => { const walletPrivateKey = process.env.DEVNET_PRIVKEY; const l1Provider = new JsonRpcProvider(process.env.L1RPC); @@ -18,16 +14,6 @@ task('syncBatchRoot', 'Forward message to L2').setAction(async (taskArgs, hre) = const lineaName = process.env.LINEA; const l1Wallet = new Wallet(walletPrivateKey, l1Provider); const l2Wallet = new Wallet(walletPrivateKey, l2Provider); - const sdk = new LineaSDK({ - l1RpcUrl: process.env.L1RPC ?? '', - l2RpcUrl: process.env.L2RPC ?? '', - l1SignerPrivateKey: walletPrivateKey ?? '', - l2SignerPrivateKey: walletPrivateKey ?? '', - network: ethereumName === 'GOERLI' ? 'linea-goerli' : 'linea-mainnet', - mode: 'read-write', - }); - const lineaL1Contract = sdk.getL1Contract(); - const lineaL2Contract = sdk.getL2Contract(); const l1WalletAddress = await l1Wallet.getAddress(); const l1WalletBalance = formatEther(await l1Provider.getBalance(l1WalletAddress)); @@ -87,42 +73,10 @@ task('syncBatchRoot', 'Forward message to L2').setAction(async (taskArgs, hre) = const arbitrator = await hre.ethers.getContractAt('DummyArbitrator', arbitratorAddr, l1Wallet); const adapterParams = '0x'; let tx = await arbitrator.forwardMessage(lineaL1GatewayAddr, 0, executeCalldata, adapterParams); - console.log(`The tx hash: ${tx.hash}`); + console.log(`The l1 tx hash: ${tx.hash}`); await tx.wait(); - console.log(`The tx confirmed`); - // const txHash = "0x60eda85e11f963c5317559999bd7a54ae4aa1086e8eff0e306523f9f3947bd7c"; - - /** - * Query the message informations on L1 via txHash. - */ - const message = (await lineaL1Contract.getMessagesByTransactionHash(tx.hash)).pop(); - console.log(`The messageSender: ${message.messageSender}`); - console.log(`The destination: ${message.destination}`); - console.log(`The fee: ${message.fee}`); - console.log(`The value: ${message.value}`); - console.log(`The messageNonce: ${message.messageNonce}`); - console.log(`The calldata: ${message.calldata}`); - console.log(`The messageHash: ${message.messageHash}`); - - // Waiting for the official Linea bridge to forward the message to L2 - // And manually claim the message on L2 - /*eslint no-constant-condition: ["error", { "checkLoops": false }]*/ - while (true) { - /** - * Query the transaction status on L2 via messageHash. - */ - const messageStatus = await lineaL2Contract.getMessageStatus(message.messageHash); - console.log(`The message status: ${messageStatus}`); - if (messageStatus === OnChainMessageStatus.CLAIMABLE) { - const tx = await lineaL2Contract.claim(message); - console.log(`The tx hash: ${tx.hash}`); - await tx.wait(); - console.log(`The tx confirmed`); - break; - } - await sleep(60 * 1000); - } - console.log('Done'); + console.log(`The l1 tx confirmed`); + await claimL1ToL2Message(tx.hash); // Example txs: // https://goerli.etherscan.io/tx/0x60eda85e11f963c5317559999bd7a54ae4aa1086e8eff0e306523f9f3947bd7c diff --git a/examples/linea/scripts/syncL2Requests.js b/examples/linea/scripts/syncL2Requests.js index 1bc5733..dcdd0fa 100644 --- a/examples/linea/scripts/syncL2Requests.js +++ b/examples/linea/scripts/syncL2Requests.js @@ -1,15 +1,12 @@ const { JsonRpcProvider, Wallet, formatEther } = require('ethers'); -const { LineaSDK, OnChainMessageStatus } = require('@consensys/linea-sdk'); +const { L2MessageServiceContract } = require('@consensys/linea-sdk'); const { readDeployContract } = require('../../../script/utils'); const logName = require('../../../script/deploy_log_name'); const { task, types } = require('hardhat/config'); +const { claimL2ToL1Message } = require('./common'); require('dotenv').config(); -function sleep(ms) { - return new Promise(resolve => setTimeout(resolve, ms)); -} - task('syncL2Requests', 'Send sync point to arbitrator') .addParam('txs', 'New sync point', 100, types.int, true) .setAction(async (taskArgs, hre) => { @@ -19,20 +16,9 @@ task('syncL2Requests', 'Send sync point to arbitrator') const walletPrivateKey = process.env.DEVNET_PRIVKEY; const l1Provider = new JsonRpcProvider(process.env.L1RPC); const l2Provider = new JsonRpcProvider(process.env.L2RPC); - const ethereumName = process.env.ETHEREUM; const lineaName = process.env.LINEA; const l1Wallet = new Wallet(walletPrivateKey, l1Provider); const l2Wallet = new Wallet(walletPrivateKey, l2Provider); - const sdk = new LineaSDK({ - l1RpcUrl: process.env.L1RPC ?? '', - l2RpcUrl: process.env.L2RPC ?? '', - l1SignerPrivateKey: walletPrivateKey ?? '', - l2SignerPrivateKey: walletPrivateKey ?? '', - network: ethereumName === 'GOERLI' ? 'linea-goerli' : 'linea-mainnet', - mode: 'read-write', - }); - const lineaL2Contract = sdk.getL2Contract(); - const lineaL1ClaimingService = sdk.getL1ClaimingService(); const l1WalletAddress = await l1Wallet.getAddress(); const l1WalletBalance = formatEther(await l1Provider.getBalance(l1WalletAddress)); @@ -62,9 +48,10 @@ task('syncL2Requests', 'Send sync point to arbitrator') const l2MessageServiceAddress = await l2Gateway.MESSAGE_SERVICE(); // Transfer ETH to ZKLink as a fee - const minimumFee = await lineaL2Contract - .getContract(l2MessageServiceAddress, lineaL2Contract.signer) - .minimumFeeInWei(); + const minimumFee = await L2MessageServiceContract.getContract( + l2MessageServiceAddress, + l2Provider, + ).minimumFeeInWei(); console.log(`The minimum fee: ${formatEther(minimumFee.toBigInt())} ether`); // send tx @@ -73,41 +60,10 @@ task('syncL2Requests', 'Send sync point to arbitrator') let tx = await zkLink.syncL2Requests(txs, { value: minimumFee.toBigInt(), }); - console.log(`The tx hash: ${tx.hash}`); + console.log(`The l2 tx hash: ${tx.hash}`); await tx.wait(); - console.log(`The tx confirmed`); - - /** - * Query the message informations on L2 via txHash. - */ - const message = (await lineaL2Contract.getMessagesByTransactionHash(tx.hash)).pop(); - console.log(`The messageSender: ${message.messageSender}`); - console.log(`The destination: ${message.destination}`); - console.log(`The fee: ${message.fee}`); - console.log(`The value: ${message.value}`); - console.log(`The messageNonce: ${message.messageNonce}`); - console.log(`The calldata: ${message.calldata}`); - console.log(`The messageHash: ${message.messageHash}`); - - // Waiting for the official Linea bridge to forward the message to L1 - // And manually claim the message on L1 - /*eslint no-constant-condition: ["error", { "checkLoops": false }]*/ - while (true) { - /** - * Query the transaction status on L1 via messageHash. - */ - const messageStatus = await lineaL1ClaimingService.getMessageStatus(message.messageHash); - console.log(`The message status: ${messageStatus}`); - if (messageStatus === OnChainMessageStatus.CLAIMABLE) { - const tx = await lineaL1ClaimingService.claimMessage(message); - console.log(`The tx hash: ${tx.hash}`); - await tx.wait(); - console.log(`The tx confirmed`); - break; - } - await sleep(60 * 1000 * 30); - } - console.log('Done'); + console.log(`The l2 tx confirmed`); + await claimL2ToL1Message(tx.hash); // Example txs: // https://goerli.lineascan.build/tx/0x71ac2f88392b0045d0dd2e4eb657c875f7b076301b3ddb15e638e5856d7addd1 diff --git a/examples/manta/package-lock.json b/examples/manta/package-lock.json index d8675b9..3ff4ab4 100644 --- a/examples/manta/package-lock.json +++ b/examples/manta/package-lock.json @@ -9,10 +9,11 @@ "version": "1.0.0", "license": "MIT", "dependencies": { + "@eth-optimism/core-utils": "^0.13.1", "dotenv": "^16.4.1" }, "devDependencies": { - "@eth-optimism/sdk": "^3.2.0", + "@eth-optimism/sdk": "^3.2.3", "@nomiclabs/hardhat-ethers": "^2.0.2", "ethers": "^5.7.2", "hardhat": "^2.9.1" @@ -67,7 +68,6 @@ "version": "0.13.1", "resolved": "https://registry.npmmirror.com/@eth-optimism/core-utils/-/core-utils-0.13.1.tgz", "integrity": "sha512-1FvzbUmCEy9zSKPG1QWg2VfA2Cy90xBA9Wkp11lXXrz91zUPCNCNSRTujXWYIC86ketNsZp7p4njSf6lTycHCw==", - "dev": true, "hasInstallScript": true, "dependencies": { "@ethersproject/abi": "^5.7.0", @@ -87,11 +87,10 @@ } }, "node_modules/@eth-optimism/sdk": { - "version": "3.2.0", - "resolved": "https://registry.npmmirror.com/@eth-optimism/sdk/-/sdk-3.2.0.tgz", - "integrity": "sha512-+ZEO/mDWz3WLzaPVHvgOAK4iN723HmI6sLLr2tmO1/RUoCHVfWMUDwuiikrA49cAsdsjMxCV9+0XNZ8btD2JUg==", + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/@eth-optimism/sdk/-/sdk-3.2.3.tgz", + "integrity": "sha512-e3XQTbbU+HTzsEv/VIsJpZifK6YZVlzEtF6tj/Vz/VIEDCjZk5JPcnCQOMVcs9ICI4EJyyur+y/+RU7fPa6qtg==", "dev": true, - "hasInstallScript": true, "dependencies": { "@eth-optimism/contracts": "0.6.0", "@eth-optimism/contracts-bedrock": "0.17.1", @@ -99,7 +98,7 @@ "lodash": "^4.17.21", "merkletreejs": "^0.3.11", "rlp": "^2.2.7", - "semver": "^7.5.4" + "semver": "^7.6.0" }, "peerDependencies": { "ethers": "^5" @@ -177,7 +176,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/abi/-/abi-5.7.0.tgz", "integrity": "sha512-351ktp42TiRcYB3H1OP8yajPeAQstMW/yCFokj/AthP9bLHzQFPlOrxOcwYEDkUAICmOHljvN4K39OMTMUa9RA==", - "dev": true, "dependencies": { "@ethersproject/address": "^5.7.0", "@ethersproject/bignumber": "^5.7.0", @@ -194,7 +192,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/abstract-provider/-/abstract-provider-5.7.0.tgz", "integrity": "sha512-R41c9UkchKCpAqStMYUpdunjo3pkEvZC3FAwZn5S5MGbXoMQOHIdHItezTETxAO5bevtMApSyEhn9+CHcDsWBw==", - "dev": true, "dependencies": { "@ethersproject/bignumber": "^5.7.0", "@ethersproject/bytes": "^5.7.0", @@ -209,7 +206,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/abstract-signer/-/abstract-signer-5.7.0.tgz", "integrity": "sha512-a16V8bq1/Cz+TGCkE2OPMTOUDLS3grCpdjoJCYNnVBbdYEMSgKrU0+B90s8b6H+ByYTBZN7a3g76jdIJi7UfKQ==", - "dev": true, "dependencies": { "@ethersproject/abstract-provider": "^5.7.0", "@ethersproject/bignumber": "^5.7.0", @@ -222,7 +218,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/address/-/address-5.7.0.tgz", "integrity": "sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA==", - "dev": true, "dependencies": { "@ethersproject/bignumber": "^5.7.0", "@ethersproject/bytes": "^5.7.0", @@ -235,7 +230,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/base64/-/base64-5.7.0.tgz", "integrity": "sha512-Dr8tcHt2mEbsZr/mwTPIQAf3Ai0Bks/7gTw9dSqk1mQvhW3XvRlmDJr/4n+wg1JmCl16NZue17CDh8xb/vZ0sQ==", - "dev": true, "dependencies": { "@ethersproject/bytes": "^5.7.0" } @@ -244,7 +238,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/basex/-/basex-5.7.0.tgz", "integrity": "sha512-ywlh43GwZLv2Voc2gQVTKBoVQ1mti3d8HK5aMxsfu/nRDnMmNqaSJ3r3n85HBByT8OpoY96SXM1FogC533T4zw==", - "dev": true, "dependencies": { "@ethersproject/bytes": "^5.7.0", "@ethersproject/properties": "^5.7.0" @@ -254,7 +247,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/bignumber/-/bignumber-5.7.0.tgz", "integrity": "sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw==", - "dev": true, "dependencies": { "@ethersproject/bytes": "^5.7.0", "@ethersproject/logger": "^5.7.0", @@ -265,7 +257,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/bytes/-/bytes-5.7.0.tgz", "integrity": "sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A==", - "dev": true, "dependencies": { "@ethersproject/logger": "^5.7.0" } @@ -274,7 +265,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/constants/-/constants-5.7.0.tgz", "integrity": "sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA==", - "dev": true, "dependencies": { "@ethersproject/bignumber": "^5.7.0" } @@ -283,7 +273,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/contracts/-/contracts-5.7.0.tgz", "integrity": "sha512-5GJbzEU3X+d33CdfPhcyS+z8MzsTrBGk/sc+G+59+tPa9yFkl6HQ9D6L0QMgNTA9q8dT0XKxxkyp883XsQvbbg==", - "dev": true, "dependencies": { "@ethersproject/abi": "^5.7.0", "@ethersproject/abstract-provider": "^5.7.0", @@ -301,7 +290,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/hash/-/hash-5.7.0.tgz", "integrity": "sha512-qX5WrQfnah1EFnO5zJv1v46a8HW0+E5xuBBDTwMFZLuVTx0tbU2kkx15NqdjxecrLGatQN9FGQKpb1FKdHCt+g==", - "dev": true, "dependencies": { "@ethersproject/abstract-signer": "^5.7.0", "@ethersproject/address": "^5.7.0", @@ -318,7 +306,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/hdnode/-/hdnode-5.7.0.tgz", "integrity": "sha512-OmyYo9EENBPPf4ERhR7oj6uAtUAhYGqOnIS+jE5pTXvdKBS99ikzq1E7Iv0ZQZ5V36Lqx1qZLeak0Ra16qpeOg==", - "dev": true, "dependencies": { "@ethersproject/abstract-signer": "^5.7.0", "@ethersproject/basex": "^5.7.0", @@ -338,7 +325,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/json-wallets/-/json-wallets-5.7.0.tgz", "integrity": "sha512-8oee5Xgu6+RKgJTkvEMl2wDgSPSAQ9MB/3JYjFV9jlKvcYHUXZC+cQp0njgmxdHkYWn8s6/IqIZYm0YWCjO/0g==", - "dev": true, "dependencies": { "@ethersproject/abstract-signer": "^5.7.0", "@ethersproject/address": "^5.7.0", @@ -359,7 +345,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/keccak256/-/keccak256-5.7.0.tgz", "integrity": "sha512-2UcPboeL/iW+pSg6vZ6ydF8tCnv3Iu/8tUmLLzWWGzxWKFFqOBQFLo6uLUv6BDrLgCDfN28RJ/wtByx+jZ4KBg==", - "dev": true, "dependencies": { "@ethersproject/bytes": "^5.7.0", "js-sha3": "0.8.0" @@ -368,14 +353,12 @@ "node_modules/@ethersproject/logger": { "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/logger/-/logger-5.7.0.tgz", - "integrity": "sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig==", - "dev": true + "integrity": "sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig==" }, "node_modules/@ethersproject/networks": { "version": "5.7.1", "resolved": "https://registry.npmmirror.com/@ethersproject/networks/-/networks-5.7.1.tgz", "integrity": "sha512-n/MufjFYv3yFcUyfhnXotyDlNdFb7onmkSy8aQERi2PjNcnWQ66xXxa3XlS8nCcA8aJKJjIIMNJTC7tu80GwpQ==", - "dev": true, "dependencies": { "@ethersproject/logger": "^5.7.0" } @@ -384,7 +367,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/pbkdf2/-/pbkdf2-5.7.0.tgz", "integrity": "sha512-oR/dBRZR6GTyaofd86DehG72hY6NpAjhabkhxgr3X2FpJtJuodEl2auADWBZfhDHgVCbu3/H/Ocq2uC6dpNjjw==", - "dev": true, "dependencies": { "@ethersproject/bytes": "^5.7.0", "@ethersproject/sha2": "^5.7.0" @@ -394,7 +376,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/properties/-/properties-5.7.0.tgz", "integrity": "sha512-J87jy8suntrAkIZtecpxEPxY//szqr1mlBaYlQ0r4RCaiD2hjheqF9s1LVE8vVuJCXisjIP+JgtK/Do54ej4Sw==", - "dev": true, "dependencies": { "@ethersproject/logger": "^5.7.0" } @@ -403,7 +384,6 @@ "version": "5.7.2", "resolved": "https://registry.npmmirror.com/@ethersproject/providers/-/providers-5.7.2.tgz", "integrity": "sha512-g34EWZ1WWAVgr4aptGlVBF8mhl3VWjv+8hoAnzStu8Ah22VHBsuGzP17eb6xDVRzw895G4W7vvx60lFFur/1Rg==", - "dev": true, "dependencies": { "@ethersproject/abstract-provider": "^5.7.0", "@ethersproject/abstract-signer": "^5.7.0", @@ -431,7 +411,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/random/-/random-5.7.0.tgz", "integrity": "sha512-19WjScqRA8IIeWclFme75VMXSBvi4e6InrUNuaR4s5pTF2qNhcGdCUwdxUVGtDDqC00sDLCO93jPQoDUH4HVmQ==", - "dev": true, "dependencies": { "@ethersproject/bytes": "^5.7.0", "@ethersproject/logger": "^5.7.0" @@ -441,7 +420,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/rlp/-/rlp-5.7.0.tgz", "integrity": "sha512-rBxzX2vK8mVF7b0Tol44t5Tb8gomOHkj5guL+HhzQ1yBh/ydjGnpw6at+X6Iw0Kp3OzzzkcKp8N9r0W4kYSs9w==", - "dev": true, "dependencies": { "@ethersproject/bytes": "^5.7.0", "@ethersproject/logger": "^5.7.0" @@ -451,7 +429,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/sha2/-/sha2-5.7.0.tgz", "integrity": "sha512-gKlH42riwb3KYp0reLsFTokByAKoJdgFCwI+CCiX/k+Jm2mbNs6oOaCjYQSlI1+XBVejwH2KrmCbMAT/GnRDQw==", - "dev": true, "dependencies": { "@ethersproject/bytes": "^5.7.0", "@ethersproject/logger": "^5.7.0", @@ -462,7 +439,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/signing-key/-/signing-key-5.7.0.tgz", "integrity": "sha512-MZdy2nL3wO0u7gkB4nA/pEf8lu1TlFswPNmy8AiYkfKTdO6eXBJyUdmHO/ehm/htHw9K/qF8ujnTyUAD+Ry54Q==", - "dev": true, "dependencies": { "@ethersproject/bytes": "^5.7.0", "@ethersproject/logger": "^5.7.0", @@ -476,7 +452,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/solidity/-/solidity-5.7.0.tgz", "integrity": "sha512-HmabMd2Dt/raavyaGukF4XxizWKhKQ24DoLtdNbBmNKUOPqwjsKQSdV9GQtj9CBEea9DlzETlVER1gYeXXBGaA==", - "dev": true, "dependencies": { "@ethersproject/bignumber": "^5.7.0", "@ethersproject/bytes": "^5.7.0", @@ -490,7 +465,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/strings/-/strings-5.7.0.tgz", "integrity": "sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg==", - "dev": true, "dependencies": { "@ethersproject/bytes": "^5.7.0", "@ethersproject/constants": "^5.7.0", @@ -501,7 +475,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/transactions/-/transactions-5.7.0.tgz", "integrity": "sha512-kmcNicCp1lp8qanMTC3RIikGgoJ80ztTyvtsFvCYpSCfkjhD0jZ2LOrnbcuxuToLIUYYf+4XwD1rP+B/erDIhQ==", - "dev": true, "dependencies": { "@ethersproject/address": "^5.7.0", "@ethersproject/bignumber": "^5.7.0", @@ -518,7 +491,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/units/-/units-5.7.0.tgz", "integrity": "sha512-pD3xLMy3SJu9kG5xDGI7+xhTEmGXlEqXU4OfNapmfnxLVY4EMSSRp7j1k7eezutBPH7RBN/7QPnwR7hzNlEFeg==", - "dev": true, "dependencies": { "@ethersproject/bignumber": "^5.7.0", "@ethersproject/constants": "^5.7.0", @@ -529,7 +501,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/wallet/-/wallet-5.7.0.tgz", "integrity": "sha512-MhmXlJXEJFBFVKrDLB4ZdDzxcBxQ3rLyCkhNqVu3CDYvR97E+8r01UgrI+TI99Le+aYm/in/0vp86guJuM7FCA==", - "dev": true, "dependencies": { "@ethersproject/abstract-provider": "^5.7.0", "@ethersproject/abstract-signer": "^5.7.0", @@ -552,7 +523,6 @@ "version": "5.7.1", "resolved": "https://registry.npmmirror.com/@ethersproject/web/-/web-5.7.1.tgz", "integrity": "sha512-Gueu8lSvyjBWL4cYsWsjh6MtMwM0+H4HvqFPZfB6dV8ctbP9zFAO73VG1cMWae0FLPCtz0peKPpZY8/ugJJX2w==", - "dev": true, "dependencies": { "@ethersproject/base64": "^5.7.0", "@ethersproject/bytes": "^5.7.0", @@ -565,7 +535,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/wordlists/-/wordlists-5.7.0.tgz", "integrity": "sha512-S2TFNJNfHWVHNE6cNDjbVlZ6MgE17MIxMbMg2zv3wn+3XSJGosL1m9ZVv3GXCf/2ymSsQ+hRI5IzoMJTG6aoVA==", - "dev": true, "dependencies": { "@ethersproject/bytes": "^5.7.0", "@ethersproject/hash": "^5.7.0", @@ -1451,8 +1420,7 @@ "node_modules/aes-js": { "version": "3.0.0", "resolved": "https://registry.npmmirror.com/aes-js/-/aes-js-3.0.0.tgz", - "integrity": "sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw==", - "dev": true + "integrity": "sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw==" }, "node_modules/agent-base": { "version": "6.0.2", @@ -1553,7 +1521,6 @@ "version": "1.1.0", "resolved": "https://registry.npmmirror.com/assertion-error/-/assertion-error-1.1.0.tgz", "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", - "dev": true, "engines": { "node": "*" } @@ -1576,8 +1543,7 @@ "node_modules/bech32": { "version": "1.1.4", "resolved": "https://registry.npmmirror.com/bech32/-/bech32-1.1.4.tgz", - "integrity": "sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==", - "dev": true + "integrity": "sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==" }, "node_modules/bigint-crypto-utils": { "version": "3.3.0", @@ -1615,8 +1581,7 @@ "node_modules/bn.js": { "version": "5.2.1", "resolved": "https://registry.npmmirror.com/bn.js/-/bn.js-5.2.1.tgz", - "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==", - "dev": true + "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==" }, "node_modules/boxen": { "version": "5.1.2", @@ -1735,8 +1700,7 @@ "node_modules/brorand": { "version": "1.1.0", "resolved": "https://registry.npmmirror.com/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==", - "dev": true + "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==" }, "node_modules/browser-stdout": { "version": "1.3.1", @@ -1827,7 +1791,6 @@ "version": "4.4.1", "resolved": "https://registry.npmmirror.com/chai/-/chai-4.4.1.tgz", "integrity": "sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==", - "dev": true, "dependencies": { "assertion-error": "^1.1.0", "check-error": "^1.0.3", @@ -1859,7 +1822,6 @@ "version": "1.0.3", "resolved": "https://registry.npmmirror.com/check-error/-/check-error-1.0.3.tgz", "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", - "dev": true, "dependencies": { "get-func-name": "^2.0.2" }, @@ -2038,7 +2000,6 @@ "version": "4.1.3", "resolved": "https://registry.npmmirror.com/deep-eql/-/deep-eql-4.1.3.tgz", "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", - "dev": true, "dependencies": { "type-detect": "^4.0.0" }, @@ -2076,7 +2037,6 @@ "version": "6.5.4", "resolved": "https://registry.npmmirror.com/elliptic/-/elliptic-6.5.4.tgz", "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", - "dev": true, "dependencies": { "bn.js": "^4.11.9", "brorand": "^1.1.0", @@ -2090,8 +2050,7 @@ "node_modules/elliptic/node_modules/bn.js": { "version": "4.12.0", "resolved": "https://registry.npmmirror.com/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", - "dev": true + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" }, "node_modules/emoji-regex": { "version": "8.0.0", @@ -2233,7 +2192,6 @@ "version": "5.7.2", "resolved": "https://registry.npmmirror.com/ethers/-/ethers-5.7.2.tgz", "integrity": "sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg==", - "dev": true, "dependencies": { "@ethersproject/abi": "5.7.0", "@ethersproject/abstract-provider": "5.7.0", @@ -2411,7 +2369,6 @@ "version": "2.0.2", "resolved": "https://registry.npmmirror.com/get-func-name/-/get-func-name-2.0.2.tgz", "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", - "dev": true, "engines": { "node": "*" } @@ -2566,7 +2523,6 @@ "version": "1.1.7", "resolved": "https://registry.npmmirror.com/hash.js/-/hash.js-1.1.7.tgz", "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", - "dev": true, "dependencies": { "inherits": "^2.0.3", "minimalistic-assert": "^1.0.1" @@ -2585,7 +2541,6 @@ "version": "1.0.1", "resolved": "https://registry.npmmirror.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz", "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", - "dev": true, "dependencies": { "hash.js": "^1.0.3", "minimalistic-assert": "^1.0.0", @@ -2661,8 +2616,7 @@ "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmmirror.com/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "node_modules/io-ts": { "version": "1.10.4", @@ -2761,8 +2715,7 @@ "node_modules/js-sha3": { "version": "0.8.0", "resolved": "https://registry.npmmirror.com/js-sha3/-/js-sha3-0.8.0.tgz", - "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==", - "dev": true + "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==" }, "node_modules/js-yaml": { "version": "4.1.0", @@ -2909,7 +2862,6 @@ "version": "2.3.7", "resolved": "https://registry.npmmirror.com/loupe/-/loupe-2.3.7.tgz", "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", - "dev": true, "dependencies": { "get-func-name": "^2.0.1" } @@ -2974,14 +2926,12 @@ "node_modules/minimalistic-assert": { "version": "1.0.1", "resolved": "https://registry.npmmirror.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", - "dev": true + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" }, "node_modules/minimalistic-crypto-utils": { "version": "1.0.1", "resolved": "https://registry.npmmirror.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", - "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==", - "dev": true + "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==" }, "node_modules/minimatch": { "version": "3.1.2", @@ -3216,7 +3166,6 @@ "version": "2.7.0", "resolved": "https://registry.npmmirror.com/node-fetch/-/node-fetch-2.7.0.tgz", "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", - "dev": true, "dependencies": { "whatwg-url": "^5.0.0" }, @@ -3369,7 +3318,6 @@ "version": "1.1.1", "resolved": "https://registry.npmmirror.com/pathval/-/pathval-1.1.1.tgz", "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", - "dev": true, "engines": { "node": "*" } @@ -3540,8 +3488,7 @@ "node_modules/scrypt-js": { "version": "3.0.1", "resolved": "https://registry.npmmirror.com/scrypt-js/-/scrypt-js-3.0.1.tgz", - "integrity": "sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==", - "dev": true + "integrity": "sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==" }, "node_modules/secp256k1": { "version": "4.0.3", @@ -3833,8 +3780,7 @@ "node_modules/tr46": { "version": "0.0.3", "resolved": "https://registry.npmmirror.com/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "dev": true + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" }, "node_modules/treeify": { "version": "1.1.0", @@ -3873,7 +3819,6 @@ "version": "4.0.8", "resolved": "https://registry.npmmirror.com/type-detect/-/type-detect-4.0.8.tgz", "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true, "engines": { "node": ">=4" } @@ -4008,14 +3953,12 @@ "node_modules/webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmmirror.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "dev": true + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" }, "node_modules/whatwg-url": { "version": "5.0.0", "resolved": "https://registry.npmmirror.com/whatwg-url/-/whatwg-url-5.0.0.tgz", "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "dev": true, "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" @@ -4093,7 +4036,6 @@ "version": "7.4.6", "resolved": "https://registry.npmmirror.com/ws/-/ws-7.4.6.tgz", "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==", - "dev": true, "engines": { "node": ">=8.3.0" }, diff --git a/examples/manta/package.json b/examples/manta/package.json index 8069eb4..e576784 100644 --- a/examples/manta/package.json +++ b/examples/manta/package.json @@ -4,12 +4,13 @@ "version": "1.0.0", "scripts": {}, "devDependencies": { - "@eth-optimism/sdk": "^3.2.0", + "@eth-optimism/sdk": "^3.2.3", "@nomiclabs/hardhat-ethers": "^2.0.2", "ethers": "^5.7.2", "hardhat": "^2.9.1" }, "dependencies": { + "@eth-optimism/core-utils": "^0.13.1", "dotenv": "^16.4.1" } } diff --git a/examples/manta/scripts/mantaTasks.js b/examples/manta/scripts/mantaTasks.js index 2364262..8304872 100644 --- a/examples/manta/scripts/mantaTasks.js +++ b/examples/manta/scripts/mantaTasks.js @@ -7,7 +7,9 @@ const { changeFeeParams, encodeSetValidator, encodeChangeFeeParams, -} = require('../../utils/opstack-utils'); + encodeL1ToL2Calldata, + checkL1TxStatus, +} = require('../../optimism/scripts/opstack-utils'); const { L1_MAINNET_CONTRACTS, L1_TESTNET_CONTRACTS } = require('./constants'); const { task, types } = require('hardhat/config'); require('dotenv').config(); @@ -39,7 +41,7 @@ async function initMessenger() { task('syncBatchRoot', 'Forward message to L2').setAction(async (_, hre) => { const { messenger, ethereumName, mantaName } = await initMessenger(); - const message = await syncBatchRoot(hre, messenger, ethereumName, mantaName, 'manta'); + const message = await syncBatchRoot(hre, messenger, ethereumName, mantaName); // Waiting for the official manta bridge to forward the message to L2 const rec = await messenger.waitForMessageReceipt(message); console.log(`The tx receipt: ${JSON.stringify(rec, null, 2)}`); @@ -58,7 +60,7 @@ task('syncL2Requests', 'Send sync point to arbitrator') const { messenger, ethereumName, mantaName } = await initMessenger(); - await syncL2Requests(hre, messenger, ethereumName, mantaName, 'manta', txs); + await syncL2Requests(hre, messenger, ethereumName, mantaName, txs); console.log('Done!'); @@ -70,7 +72,7 @@ task('syncL2Requests', 'Send sync point to arbitrator') task('changeFeeParams', 'Change fee params for zkLink').setAction(async (_, hre) => { const { messenger, ethereumName, mantaName } = await initMessenger(); - const message = await changeFeeParams(hre, messenger, ethereumName, mantaName, 'manta'); + const message = await changeFeeParams(hre, messenger, ethereumName, mantaName); // Waiting for the official manta bridge to forward the message to L2 const rec = await messenger.waitForMessageReceipt(message); @@ -88,7 +90,7 @@ task('setValidator', 'Set validator for zkLink') const { messenger, ethereumName, mantaName } = await initMessenger(); - const message = await setValidator(hre, messenger, ethereumName, mantaName, 'manta', validatorAddr, isActive); + const message = await setValidator(hre, messenger, ethereumName, mantaName, validatorAddr, isActive); // Waiting for the official manta bridge to forward the message to L2 const rec = await messenger.waitForMessageReceipt(message); @@ -106,11 +108,38 @@ task('encodeSetValidator', 'Get the calldata of set validator for zkLink') const { messenger, ethereumName, mantaName } = await initMessenger(); - await encodeSetValidator(hre, messenger, ethereumName, mantaName, 'manta', validatorAddr, isActive); + await encodeSetValidator(hre, messenger, ethereumName, mantaName, validatorAddr, isActive); }); task('encodeChangeFeeParams', 'Get the calldata of changing fee params for zkLink').setAction(async (_, hre) => { const { messenger, ethereumName, mantaName } = await initMessenger(); - await encodeChangeFeeParams(hre, messenger, ethereumName, mantaName, 'manta'); + await encodeChangeFeeParams(hre, messenger, ethereumName, mantaName); }); + +task('encodeL1ToL2Calldata', 'Encode call data for l1 to l2') + .addParam('to', 'The l2 target address', undefined, types.string) + .addParam('l2CallData', 'The l2 call data to target address', undefined, types.string) + .addParam('l2CallValue', 'The l2 call value to target address', undefined, types.int) + .setAction(async (taskArgs, hre) => { + const l2ToContractAddress = taskArgs.to; + const l2CallData = taskArgs.l2CallData; + const l2CallValue = taskArgs.l2CallValue; + console.log(`The l2 target contract address: ${l2ToContractAddress}`); + console.log(`The l2 call data to target address: ${l2CallData}`); + console.log(`The l2 call value to target address: ${l2CallValue}`); + + const { messenger, ethereumName, mantaName } = await initMessenger(); + + await encodeL1ToL2Calldata(hre, messenger, ethereumName, mantaName, l2ToContractAddress, l2CallData, l2CallValue); + }); + +task('checkL1TxStatus', 'Check the l1 tx status') + .addParam('l1TxHash', 'The l1 tx hash', undefined, types.string) + .setAction(async (taskArgs, hre) => { + const l1TxHash = taskArgs.l1TxHash; + console.log(`The l1 tx hash: ${l1TxHash}`); + + const { messenger, ethereumName, mantaName } = await initMessenger(); + await checkL1TxStatus(hre, messenger, ethereumName, mantaName, l1TxHash); + }); diff --git a/examples/mantle/hardhat.config.js b/examples/mantle/hardhat.config.js index ef15cb5..cbac017 100644 --- a/examples/mantle/hardhat.config.js +++ b/examples/mantle/hardhat.config.js @@ -3,6 +3,7 @@ require('./scripts/syncL2Requests'); require('./scripts/syncBatchRoot'); require('./scripts/setValidator'); require('./scripts/changeFeeParams'); +require('./scripts/governance'); const BaseConfig = require('../../hardhat.base.config'); diff --git a/examples/mantle/package-lock.json b/examples/mantle/package-lock.json index ab462ef..ec9c79d 100644 --- a/examples/mantle/package-lock.json +++ b/examples/mantle/package-lock.json @@ -12,7 +12,7 @@ "dotenv": "^16.4.1" }, "devDependencies": { - "@mantleio/sdk": "^1.0.0", + "@mantleio/sdk": "^1.0.3", "@nomiclabs/hardhat-ethers": "^2.0.2", "ethers": "^5.7.2", "hardhat": "^2.9.1" @@ -547,9 +547,9 @@ } }, "node_modules/@mantleio/sdk": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/@mantleio/sdk/-/sdk-1.0.0.tgz", - "integrity": "sha512-G81lpOLpf2kqRvckW6FV9g6krrzK7CoCHIrUAsMu4BntxuvbyJlMz8TnmmnaXdpHSIfyeOPuRRsccdTWlBSZdQ==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@mantleio/sdk/-/sdk-1.0.3.tgz", + "integrity": "sha512-66ucAVrPplGnZ+otsxGzuviuKVPzmLCw8pczrOzjDTeVAF9ab4BLWbovghwy1u9titzbnQ8PhYMkLCkhFYomsw==", "dev": true, "dependencies": { "@mantleio/contracts": "0.3.0", diff --git a/examples/mantle/package.json b/examples/mantle/package.json index aef2c13..5bb7028 100644 --- a/examples/mantle/package.json +++ b/examples/mantle/package.json @@ -4,7 +4,7 @@ "version": "1.0.0", "scripts": {}, "devDependencies": { - "@mantleio/sdk": "^1.0.0", + "@mantleio/sdk": "^1.0.3", "@nomiclabs/hardhat-ethers": "^2.0.2", "ethers": "^5.7.2", "hardhat": "^2.9.1" diff --git a/examples/mantle/scripts/constants.js b/examples/mantle/scripts/constants.js new file mode 100644 index 0000000..5f3f268 --- /dev/null +++ b/examples/mantle/scripts/constants.js @@ -0,0 +1,28 @@ +// Testnet +const L1_TESTNET_CONTRACTS = { + StateCommitmentChain: '0x0000000000000000000000000000000000000000', + BondManager: '0x0000000000000000000000000000000000000000', + CanonicalTransactionChain: '0x0000000000000000000000000000000000000000', + AddressManager: '0x0000000000000000000000000000000000000000', + L1CrossDomainMessenger: '0x536beD6283500BF93BA4428c18a7A629425a5c7e', + L1StandardBridge: '0xf26e9932106E6477a4Ae15dA0eDDCdB985065a1a', + OptimismPortal: '0xB3db4bd5bc225930eD674494F9A4F6a11B8EFBc8', + L2OutputOracle: '0x4121dc8e48Bc6196795eb4867772A5e259fecE07', +}; + +// Mainnet +const L1_MAINNET_CONTRACTS = { + StateCommitmentChain: '0x0000000000000000000000000000000000000000', + BondManager: '0x0000000000000000000000000000000000000000', + CanonicalTransactionChain: '0x0000000000000000000000000000000000000000', + AddressManager: '0x0000000000000000000000000000000000000000', + L1CrossDomainMessenger: '0xb8DE82551fA4BA3bE4B3d9097763EDBeED541308', + L1StandardBridge: '0xb4133552BA49dFb60DA6eb5cA0102d0f94ce071f', + OptimismPortal: '0xc54cb22944F2bE476E02dECfCD7e3E7d3e15A8Fb', + L2OutputOracle: '0x31d543e7BE1dA6eFDc2206Ef7822879045B9f481', +}; + +module.exports = { + L1_TESTNET_CONTRACTS, + L1_MAINNET_CONTRACTS, +}; diff --git a/examples/mantle/scripts/governance.js b/examples/mantle/scripts/governance.js new file mode 100644 index 0000000..3bf27c8 --- /dev/null +++ b/examples/mantle/scripts/governance.js @@ -0,0 +1,149 @@ +const mantle = require('@mantleio/sdk'); +const { DepositTx, applyL1ToL2Alias } = require('@mantleio/core-utils'); +const { readDeployContract } = require('../../../script/utils'); +const logName = require('../../../script/deploy_log_name'); +const { task, types } = require('hardhat/config'); +const { zkLinkConfig } = require('../../../script/zklink_config'); +const ethers = require('ethers'); +const { L1_TESTNET_CONTRACTS, L1_MAINNET_CONTRACTS } = require('./constants'); +const { BigNumber, Contract } = require('ethers'); + +require('dotenv').config(); + +async function initMessenger() { + const walletPrivateKey = process.env.DEVNET_PRIVKEY; + const l1Provider = new ethers.providers.StaticJsonRpcProvider(process.env.L1RPC); + const l2Provider = new ethers.providers.StaticJsonRpcProvider(process.env.L2RPC); + const ethereumName = process.env.ETHEREUM; + const mantleName = process.env.MANTLE; + const l1Wallet = new ethers.Wallet(walletPrivateKey, l1Provider); + const l2Wallet = new ethers.Wallet(walletPrivateKey, l2Provider); + // https://docs-v2.mantle.xyz/intro/system-components/on-chain-system + const messengerL1Contracts = ethereumName !== 'ETHEREUM' ? L1_TESTNET_CONTRACTS : L1_MAINNET_CONTRACTS; + const messenger = new mantle.CrossChainMessenger({ + l1ChainId: await l1Wallet.getChainId(), + l2ChainId: await l2Wallet.getChainId(), + l1SignerOrProvider: l1Wallet, + l2SignerOrProvider: l2Wallet, + bedrock: true, + contracts: { + l1: messengerL1Contracts, + }, + }); + + return { messenger, ethereumName, mantleName }; +} + +task('encodeL1ToL2Calldata', 'Encode call data for l1 to l2') + .addParam('to', 'The l2 target address', undefined, types.string) + .addParam('l2CallData', 'The l2 call data to target address', undefined, types.string) + .addParam('l2CallValue', 'The l2 call value to target address', undefined, types.int) + .setAction(async taskArgs => { + const l2ToContractAddress = taskArgs.to; + const l2CallData = taskArgs.l2CallData; + const l2CallValue = taskArgs.l2CallValue; + console.log(`The l2 target contract address: ${l2ToContractAddress}`); + console.log(`The l2 call data to target address: ${l2CallData}`); + console.log(`The l2 call value to target address: ${l2CallValue}`); + + const { messenger, ethereumName, mantleName: opChainName } = await initMessenger(); + + const l2ChainInfo = zkLinkConfig[opChainName]; + if (l2ChainInfo === undefined) { + console.log('The l2 chain info not exist'); + return; + } + const portalContract = messenger.contracts.l1.OptimismPortal; + console.log(`The optimism portal address: ${portalContract.address}`); + + const l1GovernanceAddr = readDeployContract( + logName.DEPLOY_GOVERNANCE_LOG_PREFIX, + logName.DEPLOY_LOG_GOVERNANCE, + ethereumName, + ); + if (l1GovernanceAddr === undefined) { + console.log('governance address not exist'); + return; + } + console.log(`The l1 governance address: ${l1GovernanceAddr}`); + const l2GovernanceAddr = applyL1ToL2Alias(l1GovernanceAddr); + console.log(`The l2 governance address: ${l2GovernanceAddr}`); + + const l2Provider = messenger.l2Provider; + const l2GovernanceBalance = await l2Provider.getBalance(l2GovernanceAddr); + console.log(`The l2 governance balance: ${l2GovernanceBalance.toString()}`); + if (l2GovernanceBalance.eq(BigNumber.from(0))) { + console.log(`Estimate gas will failed with error: insufficient funds for transfer`); + console.log(`Please transfer some mnt token to the l2 governance address for estimating gas`); + return; + } + let l2GasLimit = await l2Provider.estimateGas({ + from: l2GovernanceAddr, + to: l2ToContractAddress, + data: l2CallData, + value: l2CallValue, + }); + const tokenRatioAbi = + '[{\n' + + ' "inputs": [],\n' + + ' "name": "tokenRatio",\n' + + ' "outputs": [\n' + + ' {\n' + + ' "internalType": "uint256",\n' + + ' "name": "",\n' + + ' "type": "uint256"\n' + + ' }\n' + + ' ],\n' + + ' "stateMutability": "view",\n' + + ' "type": "function"\n' + + ' }]'; + const tokenRatioInterface = new ethers.utils.Interface(tokenRatioAbi); + const l2GasPriceOracle = new Contract( + messenger.contracts.l2.BVM_GasPriceOracle.address, + tokenRatioInterface, + l2Provider, + ); + const tokenRatio = await l2GasPriceOracle.tokenRatio(); + console.log(`The eth/mnt token ratio: ${tokenRatio}`); + l2GasLimit = l2GasLimit.div(BigNumber.from(tokenRatio)); + console.log(`The l2 gas limit: ${l2GasLimit.toString()}`); + l2GasLimit = l2GasLimit.mul(120).div(100); // Add 20% buffer + console.log(`The l2 gas limit: ${l2GasLimit.toString()}`); + + const sendMessageCalldata = portalContract.interface.encodeFunctionData('depositTransaction', [ + l2CallValue, + l2ToContractAddress, + l2CallValue, + l2GasLimit, + false, + l2CallData, + ]); + console.log(`The l1 to l2 call target: ${portalContract.address}`); + console.log(`The l1 to l2 call data: ${sendMessageCalldata}`); + console.log(`The l1 to l2 call value: ${l2CallValue}`); + }); + +task('checkL1TxStatus', 'Check the l1 tx status') + .addParam('l1TxHash', 'The l1 tx hash', undefined, types.string) + .setAction(async taskArgs => { + const l1TxHash = taskArgs.l1TxHash; + console.log(`The l1 tx hash: ${l1TxHash}`); + + const { messenger } = await initMessenger(); + + const l1Provider = messenger.l1Provider; + const l2Provider = messenger.l2Provider; + const l1TxReceipt = await l1Provider.getTransactionReceipt(l1TxHash); + const eventFilter = + 'TransactionDeposited(address indexed from, address indexed to, uint256 indexed version, bytes opaqueData)'; + const event = ( + await messenger.contracts.l1.OptimismPortal.queryFilter( + eventFilter, + l1TxReceipt.blockNumber, + l1TxReceipt.blockNumber, + ) + ).pop(); + const deposit = DepositTx.fromL1Event(event); + await l2Provider.waitForTransaction(deposit.hash()); + console.log(`L1 to l2 tx is executed 🥳`); + }); diff --git a/examples/optimism/package-lock.json b/examples/optimism/package-lock.json index dbca45b..d160717 100644 --- a/examples/optimism/package-lock.json +++ b/examples/optimism/package-lock.json @@ -9,10 +9,11 @@ "version": "1.0.0", "license": "MIT", "dependencies": { + "@eth-optimism/core-utils": "^0.13.1", "dotenv": "^16.4.1" }, "devDependencies": { - "@eth-optimism/sdk": "^3.2.0", + "@eth-optimism/sdk": "^3.2.3", "@nomiclabs/hardhat-ethers": "^2.0.2", "ethers": "^5.7.2", "hardhat": "^2.9.1" @@ -65,9 +66,8 @@ }, "node_modules/@eth-optimism/core-utils": { "version": "0.13.1", - "resolved": "https://registry.npmmirror.com/@eth-optimism/core-utils/-/core-utils-0.13.1.tgz", + "resolved": "https://registry.npmjs.org/@eth-optimism/core-utils/-/core-utils-0.13.1.tgz", "integrity": "sha512-1FvzbUmCEy9zSKPG1QWg2VfA2Cy90xBA9Wkp11lXXrz91zUPCNCNSRTujXWYIC86ketNsZp7p4njSf6lTycHCw==", - "dev": true, "hasInstallScript": true, "dependencies": { "@ethersproject/abi": "^5.7.0", @@ -87,11 +87,10 @@ } }, "node_modules/@eth-optimism/sdk": { - "version": "3.2.0", - "resolved": "https://registry.npmmirror.com/@eth-optimism/sdk/-/sdk-3.2.0.tgz", - "integrity": "sha512-+ZEO/mDWz3WLzaPVHvgOAK4iN723HmI6sLLr2tmO1/RUoCHVfWMUDwuiikrA49cAsdsjMxCV9+0XNZ8btD2JUg==", + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/@eth-optimism/sdk/-/sdk-3.2.3.tgz", + "integrity": "sha512-e3XQTbbU+HTzsEv/VIsJpZifK6YZVlzEtF6tj/Vz/VIEDCjZk5JPcnCQOMVcs9ICI4EJyyur+y/+RU7fPa6qtg==", "dev": true, - "hasInstallScript": true, "dependencies": { "@eth-optimism/contracts": "0.6.0", "@eth-optimism/contracts-bedrock": "0.17.1", @@ -99,7 +98,7 @@ "lodash": "^4.17.21", "merkletreejs": "^0.3.11", "rlp": "^2.2.7", - "semver": "^7.5.4" + "semver": "^7.6.0" }, "peerDependencies": { "ethers": "^5" @@ -204,7 +203,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/abi/-/abi-5.7.0.tgz", "integrity": "sha512-351ktp42TiRcYB3H1OP8yajPeAQstMW/yCFokj/AthP9bLHzQFPlOrxOcwYEDkUAICmOHljvN4K39OMTMUa9RA==", - "dev": true, "dependencies": { "@ethersproject/address": "^5.7.0", "@ethersproject/bignumber": "^5.7.0", @@ -221,7 +219,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/abstract-provider/-/abstract-provider-5.7.0.tgz", "integrity": "sha512-R41c9UkchKCpAqStMYUpdunjo3pkEvZC3FAwZn5S5MGbXoMQOHIdHItezTETxAO5bevtMApSyEhn9+CHcDsWBw==", - "dev": true, "dependencies": { "@ethersproject/bignumber": "^5.7.0", "@ethersproject/bytes": "^5.7.0", @@ -236,7 +233,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/abstract-signer/-/abstract-signer-5.7.0.tgz", "integrity": "sha512-a16V8bq1/Cz+TGCkE2OPMTOUDLS3grCpdjoJCYNnVBbdYEMSgKrU0+B90s8b6H+ByYTBZN7a3g76jdIJi7UfKQ==", - "dev": true, "dependencies": { "@ethersproject/abstract-provider": "^5.7.0", "@ethersproject/bignumber": "^5.7.0", @@ -249,7 +245,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/address/-/address-5.7.0.tgz", "integrity": "sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA==", - "dev": true, "dependencies": { "@ethersproject/bignumber": "^5.7.0", "@ethersproject/bytes": "^5.7.0", @@ -262,7 +257,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/base64/-/base64-5.7.0.tgz", "integrity": "sha512-Dr8tcHt2mEbsZr/mwTPIQAf3Ai0Bks/7gTw9dSqk1mQvhW3XvRlmDJr/4n+wg1JmCl16NZue17CDh8xb/vZ0sQ==", - "dev": true, "dependencies": { "@ethersproject/bytes": "^5.7.0" } @@ -271,7 +265,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/basex/-/basex-5.7.0.tgz", "integrity": "sha512-ywlh43GwZLv2Voc2gQVTKBoVQ1mti3d8HK5aMxsfu/nRDnMmNqaSJ3r3n85HBByT8OpoY96SXM1FogC533T4zw==", - "dev": true, "dependencies": { "@ethersproject/bytes": "^5.7.0", "@ethersproject/properties": "^5.7.0" @@ -281,7 +274,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/bignumber/-/bignumber-5.7.0.tgz", "integrity": "sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw==", - "dev": true, "dependencies": { "@ethersproject/bytes": "^5.7.0", "@ethersproject/logger": "^5.7.0", @@ -292,7 +284,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/bytes/-/bytes-5.7.0.tgz", "integrity": "sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A==", - "dev": true, "dependencies": { "@ethersproject/logger": "^5.7.0" } @@ -301,7 +292,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/constants/-/constants-5.7.0.tgz", "integrity": "sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA==", - "dev": true, "dependencies": { "@ethersproject/bignumber": "^5.7.0" } @@ -310,7 +300,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/contracts/-/contracts-5.7.0.tgz", "integrity": "sha512-5GJbzEU3X+d33CdfPhcyS+z8MzsTrBGk/sc+G+59+tPa9yFkl6HQ9D6L0QMgNTA9q8dT0XKxxkyp883XsQvbbg==", - "dev": true, "dependencies": { "@ethersproject/abi": "^5.7.0", "@ethersproject/abstract-provider": "^5.7.0", @@ -328,7 +317,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/hash/-/hash-5.7.0.tgz", "integrity": "sha512-qX5WrQfnah1EFnO5zJv1v46a8HW0+E5xuBBDTwMFZLuVTx0tbU2kkx15NqdjxecrLGatQN9FGQKpb1FKdHCt+g==", - "dev": true, "dependencies": { "@ethersproject/abstract-signer": "^5.7.0", "@ethersproject/address": "^5.7.0", @@ -345,7 +333,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/hdnode/-/hdnode-5.7.0.tgz", "integrity": "sha512-OmyYo9EENBPPf4ERhR7oj6uAtUAhYGqOnIS+jE5pTXvdKBS99ikzq1E7Iv0ZQZ5V36Lqx1qZLeak0Ra16qpeOg==", - "dev": true, "dependencies": { "@ethersproject/abstract-signer": "^5.7.0", "@ethersproject/basex": "^5.7.0", @@ -365,7 +352,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/json-wallets/-/json-wallets-5.7.0.tgz", "integrity": "sha512-8oee5Xgu6+RKgJTkvEMl2wDgSPSAQ9MB/3JYjFV9jlKvcYHUXZC+cQp0njgmxdHkYWn8s6/IqIZYm0YWCjO/0g==", - "dev": true, "dependencies": { "@ethersproject/abstract-signer": "^5.7.0", "@ethersproject/address": "^5.7.0", @@ -386,7 +372,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/keccak256/-/keccak256-5.7.0.tgz", "integrity": "sha512-2UcPboeL/iW+pSg6vZ6ydF8tCnv3Iu/8tUmLLzWWGzxWKFFqOBQFLo6uLUv6BDrLgCDfN28RJ/wtByx+jZ4KBg==", - "dev": true, "dependencies": { "@ethersproject/bytes": "^5.7.0", "js-sha3": "0.8.0" @@ -395,14 +380,12 @@ "node_modules/@ethersproject/logger": { "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/logger/-/logger-5.7.0.tgz", - "integrity": "sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig==", - "dev": true + "integrity": "sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig==" }, "node_modules/@ethersproject/networks": { "version": "5.7.1", "resolved": "https://registry.npmmirror.com/@ethersproject/networks/-/networks-5.7.1.tgz", "integrity": "sha512-n/MufjFYv3yFcUyfhnXotyDlNdFb7onmkSy8aQERi2PjNcnWQ66xXxa3XlS8nCcA8aJKJjIIMNJTC7tu80GwpQ==", - "dev": true, "dependencies": { "@ethersproject/logger": "^5.7.0" } @@ -411,7 +394,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/pbkdf2/-/pbkdf2-5.7.0.tgz", "integrity": "sha512-oR/dBRZR6GTyaofd86DehG72hY6NpAjhabkhxgr3X2FpJtJuodEl2auADWBZfhDHgVCbu3/H/Ocq2uC6dpNjjw==", - "dev": true, "dependencies": { "@ethersproject/bytes": "^5.7.0", "@ethersproject/sha2": "^5.7.0" @@ -421,7 +403,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/properties/-/properties-5.7.0.tgz", "integrity": "sha512-J87jy8suntrAkIZtecpxEPxY//szqr1mlBaYlQ0r4RCaiD2hjheqF9s1LVE8vVuJCXisjIP+JgtK/Do54ej4Sw==", - "dev": true, "dependencies": { "@ethersproject/logger": "^5.7.0" } @@ -430,7 +411,6 @@ "version": "5.7.2", "resolved": "https://registry.npmmirror.com/@ethersproject/providers/-/providers-5.7.2.tgz", "integrity": "sha512-g34EWZ1WWAVgr4aptGlVBF8mhl3VWjv+8hoAnzStu8Ah22VHBsuGzP17eb6xDVRzw895G4W7vvx60lFFur/1Rg==", - "dev": true, "dependencies": { "@ethersproject/abstract-provider": "^5.7.0", "@ethersproject/abstract-signer": "^5.7.0", @@ -458,7 +438,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/random/-/random-5.7.0.tgz", "integrity": "sha512-19WjScqRA8IIeWclFme75VMXSBvi4e6InrUNuaR4s5pTF2qNhcGdCUwdxUVGtDDqC00sDLCO93jPQoDUH4HVmQ==", - "dev": true, "dependencies": { "@ethersproject/bytes": "^5.7.0", "@ethersproject/logger": "^5.7.0" @@ -468,7 +447,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/rlp/-/rlp-5.7.0.tgz", "integrity": "sha512-rBxzX2vK8mVF7b0Tol44t5Tb8gomOHkj5guL+HhzQ1yBh/ydjGnpw6at+X6Iw0Kp3OzzzkcKp8N9r0W4kYSs9w==", - "dev": true, "dependencies": { "@ethersproject/bytes": "^5.7.0", "@ethersproject/logger": "^5.7.0" @@ -478,7 +456,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/sha2/-/sha2-5.7.0.tgz", "integrity": "sha512-gKlH42riwb3KYp0reLsFTokByAKoJdgFCwI+CCiX/k+Jm2mbNs6oOaCjYQSlI1+XBVejwH2KrmCbMAT/GnRDQw==", - "dev": true, "dependencies": { "@ethersproject/bytes": "^5.7.0", "@ethersproject/logger": "^5.7.0", @@ -489,7 +466,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/signing-key/-/signing-key-5.7.0.tgz", "integrity": "sha512-MZdy2nL3wO0u7gkB4nA/pEf8lu1TlFswPNmy8AiYkfKTdO6eXBJyUdmHO/ehm/htHw9K/qF8ujnTyUAD+Ry54Q==", - "dev": true, "dependencies": { "@ethersproject/bytes": "^5.7.0", "@ethersproject/logger": "^5.7.0", @@ -503,7 +479,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/solidity/-/solidity-5.7.0.tgz", "integrity": "sha512-HmabMd2Dt/raavyaGukF4XxizWKhKQ24DoLtdNbBmNKUOPqwjsKQSdV9GQtj9CBEea9DlzETlVER1gYeXXBGaA==", - "dev": true, "dependencies": { "@ethersproject/bignumber": "^5.7.0", "@ethersproject/bytes": "^5.7.0", @@ -517,7 +492,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/strings/-/strings-5.7.0.tgz", "integrity": "sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg==", - "dev": true, "dependencies": { "@ethersproject/bytes": "^5.7.0", "@ethersproject/constants": "^5.7.0", @@ -528,7 +502,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/transactions/-/transactions-5.7.0.tgz", "integrity": "sha512-kmcNicCp1lp8qanMTC3RIikGgoJ80ztTyvtsFvCYpSCfkjhD0jZ2LOrnbcuxuToLIUYYf+4XwD1rP+B/erDIhQ==", - "dev": true, "dependencies": { "@ethersproject/address": "^5.7.0", "@ethersproject/bignumber": "^5.7.0", @@ -545,7 +518,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/units/-/units-5.7.0.tgz", "integrity": "sha512-pD3xLMy3SJu9kG5xDGI7+xhTEmGXlEqXU4OfNapmfnxLVY4EMSSRp7j1k7eezutBPH7RBN/7QPnwR7hzNlEFeg==", - "dev": true, "dependencies": { "@ethersproject/bignumber": "^5.7.0", "@ethersproject/constants": "^5.7.0", @@ -556,7 +528,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/wallet/-/wallet-5.7.0.tgz", "integrity": "sha512-MhmXlJXEJFBFVKrDLB4ZdDzxcBxQ3rLyCkhNqVu3CDYvR97E+8r01UgrI+TI99Le+aYm/in/0vp86guJuM7FCA==", - "dev": true, "dependencies": { "@ethersproject/abstract-provider": "^5.7.0", "@ethersproject/abstract-signer": "^5.7.0", @@ -579,7 +550,6 @@ "version": "5.7.1", "resolved": "https://registry.npmmirror.com/@ethersproject/web/-/web-5.7.1.tgz", "integrity": "sha512-Gueu8lSvyjBWL4cYsWsjh6MtMwM0+H4HvqFPZfB6dV8ctbP9zFAO73VG1cMWae0FLPCtz0peKPpZY8/ugJJX2w==", - "dev": true, "dependencies": { "@ethersproject/base64": "^5.7.0", "@ethersproject/bytes": "^5.7.0", @@ -592,7 +562,6 @@ "version": "5.7.0", "resolved": "https://registry.npmmirror.com/@ethersproject/wordlists/-/wordlists-5.7.0.tgz", "integrity": "sha512-S2TFNJNfHWVHNE6cNDjbVlZ6MgE17MIxMbMg2zv3wn+3XSJGosL1m9ZVv3GXCf/2ymSsQ+hRI5IzoMJTG6aoVA==", - "dev": true, "dependencies": { "@ethersproject/bytes": "^5.7.0", "@ethersproject/hash": "^5.7.0", @@ -1478,8 +1447,7 @@ "node_modules/aes-js": { "version": "3.0.0", "resolved": "https://registry.npmmirror.com/aes-js/-/aes-js-3.0.0.tgz", - "integrity": "sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw==", - "dev": true + "integrity": "sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw==" }, "node_modules/agent-base": { "version": "6.0.2", @@ -1580,7 +1548,6 @@ "version": "1.1.0", "resolved": "https://registry.npmmirror.com/assertion-error/-/assertion-error-1.1.0.tgz", "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", - "dev": true, "engines": { "node": "*" } @@ -1603,8 +1570,7 @@ "node_modules/bech32": { "version": "1.1.4", "resolved": "https://registry.npmmirror.com/bech32/-/bech32-1.1.4.tgz", - "integrity": "sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==", - "dev": true + "integrity": "sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==" }, "node_modules/bigint-crypto-utils": { "version": "3.3.0", @@ -1642,8 +1608,7 @@ "node_modules/bn.js": { "version": "5.2.1", "resolved": "https://registry.npmmirror.com/bn.js/-/bn.js-5.2.1.tgz", - "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==", - "dev": true + "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==" }, "node_modules/boxen": { "version": "5.1.2", @@ -1762,8 +1727,7 @@ "node_modules/brorand": { "version": "1.1.0", "resolved": "https://registry.npmmirror.com/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==", - "dev": true + "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==" }, "node_modules/browser-stdout": { "version": "1.3.1", @@ -1854,7 +1818,6 @@ "version": "4.4.1", "resolved": "https://registry.npmmirror.com/chai/-/chai-4.4.1.tgz", "integrity": "sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==", - "dev": true, "dependencies": { "assertion-error": "^1.1.0", "check-error": "^1.0.3", @@ -1886,7 +1849,6 @@ "version": "1.0.3", "resolved": "https://registry.npmmirror.com/check-error/-/check-error-1.0.3.tgz", "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", - "dev": true, "dependencies": { "get-func-name": "^2.0.2" }, @@ -2065,7 +2027,6 @@ "version": "4.1.3", "resolved": "https://registry.npmmirror.com/deep-eql/-/deep-eql-4.1.3.tgz", "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", - "dev": true, "dependencies": { "type-detect": "^4.0.0" }, @@ -2103,7 +2064,6 @@ "version": "6.5.4", "resolved": "https://registry.npmmirror.com/elliptic/-/elliptic-6.5.4.tgz", "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", - "dev": true, "dependencies": { "bn.js": "^4.11.9", "brorand": "^1.1.0", @@ -2117,8 +2077,7 @@ "node_modules/elliptic/node_modules/bn.js": { "version": "4.12.0", "resolved": "https://registry.npmmirror.com/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", - "dev": true + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" }, "node_modules/emoji-regex": { "version": "8.0.0", @@ -2260,7 +2219,6 @@ "version": "5.7.2", "resolved": "https://registry.npmmirror.com/ethers/-/ethers-5.7.2.tgz", "integrity": "sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg==", - "dev": true, "dependencies": { "@ethersproject/abi": "5.7.0", "@ethersproject/abstract-provider": "5.7.0", @@ -2438,7 +2396,6 @@ "version": "2.0.2", "resolved": "https://registry.npmmirror.com/get-func-name/-/get-func-name-2.0.2.tgz", "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", - "dev": true, "engines": { "node": "*" } @@ -2584,7 +2541,6 @@ "version": "1.1.7", "resolved": "https://registry.npmmirror.com/hash.js/-/hash.js-1.1.7.tgz", "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", - "dev": true, "dependencies": { "inherits": "^2.0.3", "minimalistic-assert": "^1.0.1" @@ -2603,7 +2559,6 @@ "version": "1.0.1", "resolved": "https://registry.npmmirror.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz", "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", - "dev": true, "dependencies": { "hash.js": "^1.0.3", "minimalistic-assert": "^1.0.0", @@ -2679,8 +2634,7 @@ "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmmirror.com/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "node_modules/io-ts": { "version": "1.10.4", @@ -2779,8 +2733,7 @@ "node_modules/js-sha3": { "version": "0.8.0", "resolved": "https://registry.npmmirror.com/js-sha3/-/js-sha3-0.8.0.tgz", - "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==", - "dev": true + "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==" }, "node_modules/js-yaml": { "version": "4.1.0", @@ -2927,7 +2880,6 @@ "version": "2.3.7", "resolved": "https://registry.npmmirror.com/loupe/-/loupe-2.3.7.tgz", "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", - "dev": true, "dependencies": { "get-func-name": "^2.0.1" } @@ -2992,14 +2944,12 @@ "node_modules/minimalistic-assert": { "version": "1.0.1", "resolved": "https://registry.npmmirror.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", - "dev": true + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" }, "node_modules/minimalistic-crypto-utils": { "version": "1.0.1", "resolved": "https://registry.npmmirror.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", - "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==", - "dev": true + "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==" }, "node_modules/minimatch": { "version": "3.1.2", @@ -3234,7 +3184,6 @@ "version": "2.7.0", "resolved": "https://registry.npmmirror.com/node-fetch/-/node-fetch-2.7.0.tgz", "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", - "dev": true, "dependencies": { "whatwg-url": "^5.0.0" }, @@ -3387,7 +3336,6 @@ "version": "1.1.1", "resolved": "https://registry.npmmirror.com/pathval/-/pathval-1.1.1.tgz", "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", - "dev": true, "engines": { "node": "*" } @@ -3558,8 +3506,7 @@ "node_modules/scrypt-js": { "version": "3.0.1", "resolved": "https://registry.npmmirror.com/scrypt-js/-/scrypt-js-3.0.1.tgz", - "integrity": "sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==", - "dev": true + "integrity": "sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==" }, "node_modules/secp256k1": { "version": "4.0.3", @@ -3833,8 +3780,7 @@ "node_modules/tr46": { "version": "0.0.3", "resolved": "https://registry.npmmirror.com/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "dev": true + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" }, "node_modules/treeify": { "version": "1.1.0", @@ -3873,7 +3819,6 @@ "version": "4.0.8", "resolved": "https://registry.npmmirror.com/type-detect/-/type-detect-4.0.8.tgz", "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true, "engines": { "node": ">=4" } @@ -4008,14 +3953,12 @@ "node_modules/webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmmirror.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "dev": true + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" }, "node_modules/whatwg-url": { "version": "5.0.0", "resolved": "https://registry.npmmirror.com/whatwg-url/-/whatwg-url-5.0.0.tgz", "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "dev": true, "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" @@ -4093,7 +4036,6 @@ "version": "7.4.6", "resolved": "https://registry.npmmirror.com/ws/-/ws-7.4.6.tgz", "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==", - "dev": true, "engines": { "node": ">=8.3.0" }, diff --git a/examples/optimism/package.json b/examples/optimism/package.json index c538a35..4934494 100644 --- a/examples/optimism/package.json +++ b/examples/optimism/package.json @@ -4,12 +4,13 @@ "version": "1.0.0", "scripts": {}, "devDependencies": { - "@eth-optimism/sdk": "^3.2.0", + "@eth-optimism/sdk": "^3.2.3", "@nomiclabs/hardhat-ethers": "^2.0.2", "ethers": "^5.7.2", "hardhat": "^2.9.1" }, "dependencies": { + "@eth-optimism/core-utils": "^0.13.1", "dotenv": "^16.4.1" } } diff --git a/examples/utils/opstack-utils.js b/examples/optimism/scripts/opstack-utils.js similarity index 79% rename from examples/utils/opstack-utils.js rename to examples/optimism/scripts/opstack-utils.js index 537336d..4c0093b 100644 --- a/examples/utils/opstack-utils.js +++ b/examples/optimism/scripts/opstack-utils.js @@ -1,7 +1,9 @@ const ethers = require('ethers'); -const { readDeployContract, getLogName } = require('../../script/utils'); -const logName = require('../../script/deploy_log_name'); -const { INIT_FEE_PARAMS } = require('../../script/zksync_era'); +const { readDeployContract, getLogName } = require('../../../script/utils'); +const logName = require('../../../script/deploy_log_name'); +const { INIT_FEE_PARAMS } = require('../../../script/zksync_era'); +const { zkLinkConfig } = require('../../../script/zklink_config'); +const { DepositTx, applyL1ToL2Alias } = require('@eth-optimism/core-utils'); const MessageStatus = { UNCONFIRMED_L1_TO_L2_MESSAGE: 0, @@ -17,11 +19,7 @@ function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } -async function getContractAddresses(ethereumName, opChainName, chainName) { - if (chainName === undefined) { - chainName = 'op stack chain'; - } - +async function getContractAddresses(ethereumName, opChainName) { const arbitratorAddr = readDeployContract( logName.DEPLOY_ARBITRATOR_LOG_PREFIX, logName.DEPLOY_LOG_ARBITRATOR, @@ -43,17 +41,17 @@ async function getContractAddresses(ethereumName, opChainName, chainName) { const l1GatewayLogName = getLogName(logName.DEPLOY_L1_GATEWAY_LOG_PREFIX, opChainName); const l1GatewayAddr = readDeployContract(l1GatewayLogName, logName.DEPLOY_GATEWAY, ethereumName); if (l1GatewayAddr === undefined) { - console.log(`${chainName} l1 gateway address not exist`); + console.log(`${opChainName} l1 gateway address not exist`); return; } - console.log(`The ${chainName} l1 gateway address: ${l1GatewayAddr}`); + console.log(`The ${opChainName} l1 gateway address: ${l1GatewayAddr}`); const l2GatewayAddr = readDeployContract(logName.DEPLOY_L2_GATEWAY_LOG_PREFIX, logName.DEPLOY_GATEWAY, opChainName); if (l2GatewayAddr === undefined) { - console.log(`${chainName} l2 gateway address not exist`); + console.log(`${opChainName} l2 gateway address not exist`); return; } - console.log(`The ${chainName} l2 gateway address: ${l2GatewayAddr}`); + console.log(`The ${opChainName} l2 gateway address: ${l2GatewayAddr}`); return { arbitratorAddr, @@ -80,11 +78,10 @@ async function generateAdapterParams(hre, messenger, l2GatewayAddr, executeCalld return adapterParams; } -async function syncBatchRoot(hre, messenger, ethereumName, opChainName, chainName) { +async function syncBatchRoot(hre, messenger, ethereumName, opChainName) { const { arbitratorAddr, zkLinkAddr, l1GatewayAddr, l2GatewayAddr } = await getContractAddresses( ethereumName, opChainName, - chainName, ); const l1Wallet = messenger.l1Signer; const l2Provider = messenger.l2Provider; @@ -138,11 +135,10 @@ async function syncBatchRoot(hre, messenger, ethereumName, opChainName, chainNam return message; } -async function setValidator(hre, messenger, ethereumName, opChainName, chainName, validatorAddr, isActive) { +async function setValidator(hre, messenger, ethereumName, opChainName, validatorAddr, isActive) { const { arbitratorAddr, zkLinkAddr, l1GatewayAddr, l2GatewayAddr } = await getContractAddresses( ethereumName, opChainName, - chainName, ); const l1Wallet = messenger.l1Signer; const l1WalletAddress = await l1Wallet.getAddress(); @@ -188,11 +184,10 @@ async function setValidator(hre, messenger, ethereumName, opChainName, chainName return message; } -async function changeFeeParams(hre, messenger, ethereumName, opChainName, chainName) { +async function changeFeeParams(hre, messenger, ethereumName, opChainName) { const { arbitratorAddr, zkLinkAddr, l1GatewayAddr, l2GatewayAddr } = await getContractAddresses( ethereumName, opChainName, - chainName, ); const l1Wallet = messenger.l1Signer; const l1WalletAddress = await l1Wallet.getAddress(); @@ -237,8 +232,8 @@ async function changeFeeParams(hre, messenger, ethereumName, opChainName, chainN return message; } -async function syncL2Requests(hre, messenger, ethereumName, opChainName, chainName, txs) { - const { zkLinkAddr } = await getContractAddresses(ethereumName, opChainName, chainName); +async function syncL2Requests(hre, messenger, ethereumName, opChainName, txs) { + const { zkLinkAddr } = await getContractAddresses(ethereumName, opChainName); const l2Wallet = messenger.l2Signer; const l1Wallet = messenger.l1Signer; @@ -304,8 +299,8 @@ async function syncL2Requests(hre, messenger, ethereumName, opChainName, chainNa console.log(`The message has been relayed`); } -async function encodeSetValidator(hre, messenger, ethereumName, opChainName, chainName, validatorAddr, isActive) { - const { zkLinkAddr, l1GatewayAddr, l2GatewayAddr } = await getContractAddresses(ethereumName, opChainName, chainName); +async function encodeSetValidator(hre, messenger, ethereumName, opChainName, validatorAddr, isActive) { + const { zkLinkAddr, l1GatewayAddr, l2GatewayAddr } = await getContractAddresses(ethereumName, opChainName); // pre-execution calldata const zkLink = await hre.ethers.getContractAt('ZkLink', zkLinkAddr); const executeCalldata = zkLink.interface.encodeFunctionData('setValidator', [validatorAddr, isActive]); @@ -323,8 +318,8 @@ async function encodeSetValidator(hre, messenger, ethereumName, opChainName, cha return calldata; } -async function encodeChangeFeeParams(hre, messenger, ethereumName, opChainName, chainName) { - const { zkLinkAddr, l1GatewayAddr, l2GatewayAddr } = await getContractAddresses(ethereumName, opChainName, chainName); +async function encodeChangeFeeParams(hre, messenger, ethereumName, opChainName) { + const { zkLinkAddr, l1GatewayAddr, l2GatewayAddr } = await getContractAddresses(ethereumName, opChainName); // pre-execution calldata const zkLink = await hre.ethers.getContractAt('ZkLink', zkLinkAddr); console.log(`The zkLink address: ${zkLink.address}`); @@ -342,6 +337,76 @@ async function encodeChangeFeeParams(hre, messenger, ethereumName, opChainName, return calldata; } +async function encodeL1ToL2Calldata( + hre, + messenger, + ethereumName, + opChainName, + l2ToContractAddress, + l2CallData, + l2CallValue, +) { + const l2ChainInfo = zkLinkConfig[opChainName]; + if (l2ChainInfo === undefined) { + console.log('The l2 chain info not exist'); + return; + } + const portalContract = messenger.contracts.l1.OptimismPortal; + console.log(`The optimism portal address: ${portalContract.address}`); + + const l1GovernanceAddr = readDeployContract( + logName.DEPLOY_GOVERNANCE_LOG_PREFIX, + logName.DEPLOY_LOG_GOVERNANCE, + ethereumName, + ); + if (l1GovernanceAddr === undefined) { + console.log('governance address not exist'); + return; + } + console.log(`The l1 governance address: ${l1GovernanceAddr}`); + const l2GovernanceAddr = applyL1ToL2Alias(l1GovernanceAddr); + console.log(`The l2 governance address: ${l2GovernanceAddr}`); + + const l2Provider = messenger.l2Provider; + let l2GasLimit = await l2Provider.estimateGas({ + from: l2GovernanceAddr, + to: l2ToContractAddress, + data: l2CallData, + value: l2CallValue, + }); + l2GasLimit = l2GasLimit.mul(120).div(100); // Add 20% buffer + console.log(`The l2 gas limit: ${l2GasLimit.toString()}`); + + const sendMessageCalldata = portalContract.interface.encodeFunctionData('depositTransaction', [ + l2ToContractAddress, + l2CallValue, + l2GasLimit, + false, + l2CallData, + ]); + console.log(`The l1 to l2 call target: ${portalContract.address}`); + console.log(`The l1 to l2 call data: ${sendMessageCalldata}`); + console.log(`The l1 to l2 call value: ${l2CallValue}`); +} + +async function checkL1TxStatus(hre, messenger, ethereumName, opChainName, l1TxHash) { + const l1Provider = messenger.l1Provider; + const l2Provider = messenger.l2Provider; + const l1TxReceipt = await l1Provider.getTransactionReceipt(l1TxHash); + const eventFilter = + 'TransactionDeposited(address indexed from, address indexed to, uint256 indexed version, bytes opaqueData)'; + const event = ( + await messenger.contracts.l1.OptimismPortal.queryFilter( + eventFilter, + l1TxReceipt.blockNumber, + l1TxReceipt.blockNumber, + ) + ).pop(); + const deposit = DepositTx.fromL1Event(event); + await l2Provider.waitForTransaction(deposit.hash()); + console.log(`L1 to l2 tx is executed 🥳`); +} + module.exports = { getContractAddresses, syncBatchRoot, @@ -350,4 +415,6 @@ module.exports = { syncL2Requests, encodeSetValidator, encodeChangeFeeParams, + encodeL1ToL2Calldata, + checkL1TxStatus, }; diff --git a/examples/optimism/scripts/optimismTasks.js b/examples/optimism/scripts/optimismTasks.js index b278f31..32a278b 100644 --- a/examples/optimism/scripts/optimismTasks.js +++ b/examples/optimism/scripts/optimismTasks.js @@ -7,7 +7,9 @@ const { changeFeeParams, encodeSetValidator, encodeChangeFeeParams, -} = require('../../utils/opstack-utils'); + encodeL1ToL2Calldata, + checkL1TxStatus, +} = require('./opstack-utils'); const { task, types } = require('hardhat/config'); require('dotenv').config(); @@ -32,7 +34,7 @@ async function initMessenger() { task('syncBatchRoot', 'Forward message to L2').setAction(async (_, hre) => { const { messenger, ethereumName, optimismName } = await initMessenger(); - const message = await syncBatchRoot(hre, messenger, ethereumName, optimismName, 'optimism'); + const message = await syncBatchRoot(hre, messenger, ethereumName, optimismName); // Waiting for the official optimism bridge to forward the message to L2 const rec = await messenger.waitForMessageReceipt(message); console.log(`The tx receipt: ${JSON.stringify(rec, null, 2)}`); @@ -51,7 +53,7 @@ task('syncL2Requests', 'Send sync point to arbitrator') const { messenger, ethereumName, optimismName } = await initMessenger(); - await syncL2Requests(hre, messenger, ethereumName, optimismName, 'optimism', txs); + await syncL2Requests(hre, messenger, ethereumName, optimismName, txs); console.log('Done! Your transaction is executed'); @@ -70,7 +72,7 @@ task('setValidator', 'Set validator for zkLink') const { messenger, ethereumName, optimismName } = await initMessenger(); - const message = await setValidator(hre, messenger, ethereumName, optimismName, 'optimism', validatorAddr, isActive); + const message = await setValidator(hre, messenger, ethereumName, optimismName, validatorAddr, isActive); // Waiting for the official optimism bridge to forward the message to L2 const rec = await messenger.waitForMessageReceipt(message); console.log(`The tx receipt: ${JSON.stringify(rec, null, 2)}`); @@ -80,7 +82,7 @@ task('setValidator', 'Set validator for zkLink') task('changeFeeParams', 'Change fee params for zkLink').setAction(async (_, hre) => { const { messenger, ethereumName, optimismName } = await initMessenger(); - const message = await changeFeeParams(hre, messenger, ethereumName, optimismName, 'optimism'); + const message = await changeFeeParams(hre, messenger, ethereumName, optimismName); // Waiting for the official optimism bridge to forward the message to L2 const rec = await messenger.waitForMessageReceipt(message); @@ -98,11 +100,46 @@ task('encodeSetValidator', 'Get the calldata of set validator for zkLink') const { messenger, ethereumName, optimismName } = await initMessenger(); - await encodeSetValidator(hre, messenger, ethereumName, optimismName, 'optimism', validatorAddr, isActive); + await encodeSetValidator(hre, messenger, ethereumName, optimismName, validatorAddr, isActive); }); task('encodeChangeFeeParams', 'Get the calldata of changing fee params for zkLink').setAction(async (_, hre) => { const { messenger, ethereumName, optimismName } = await initMessenger(); - await encodeChangeFeeParams(hre, messenger, ethereumName, optimismName, 'optimism'); + await encodeChangeFeeParams(hre, messenger, ethereumName, optimismName); }); + +task('encodeL1ToL2Calldata', 'Encode call data for l1 to l2') + .addParam('to', 'The l2 target address', undefined, types.string) + .addParam('l2CallData', 'The l2 call data to target address', undefined, types.string) + .addParam('l2CallValue', 'The l2 call value to target address', undefined, types.int) + .setAction(async (taskArgs, hre) => { + const l2ToContractAddress = taskArgs.to; + const l2CallData = taskArgs.l2CallData; + const l2CallValue = taskArgs.l2CallValue; + console.log(`The l2 target contract address: ${l2ToContractAddress}`); + console.log(`The l2 call data to target address: ${l2CallData}`); + console.log(`The l2 call value to target address: ${l2CallValue}`); + + const { messenger, ethereumName, optimismName } = await initMessenger(); + + await encodeL1ToL2Calldata( + hre, + messenger, + ethereumName, + optimismName, + l2ToContractAddress, + l2CallData, + l2CallValue, + ); + }); + +task('checkL1TxStatus', 'Check the l1 tx status') + .addParam('l1TxHash', 'The l1 tx hash', undefined, types.string) + .setAction(async (taskArgs, hre) => { + const l1TxHash = taskArgs.l1TxHash; + console.log(`The l1 tx hash: ${l1TxHash}`); + + const { messenger, ethereumName, optimismName } = await initMessenger(); + await checkL1TxStatus(hre, messenger, ethereumName, optimismName, l1TxHash); + }); diff --git a/examples/zksync/.env-sample b/examples/zksync/.env-sample index 14daf6e..330333f 100644 --- a/examples/zksync/.env-sample +++ b/examples/zksync/.env-sample @@ -18,4 +18,19 @@ L1RPC="" ZKSYNC="ZKSYNCTEST" # Ethereum chain name -ETHEREUM="SEPOLIA" \ No newline at end of file +ETHEREUM="SEPOLIA" + +# Your Private key + +ZKLINK_DEVNET_PRIVKEY="0x your key here" + +# Hosted Aggregator Node (JSON-RPC Endpoint). This is zkLink Testnet, can use any zkLink chain + +ZKLINK_L2RPC="https://goerli.rpc.zklink.io" + +# Linea RPC; i.e., for Sepolia https://rpc.sepolia.linea.build + +ZKLINK_L1RPC="https://rpc.sepolia.linea.build" + +# Linea chain name +LINEA="LINEATEST" \ No newline at end of file diff --git a/examples/zksync/hardhat.config.js b/examples/zksync/hardhat.config.js index 785d267..bc3905d 100644 --- a/examples/zksync/hardhat.config.js +++ b/examples/zksync/hardhat.config.js @@ -4,6 +4,7 @@ require('./scripts/syncL2Requests'); require('./scripts/syncBatchRoot'); require('./scripts/setValidator'); require('./scripts/changeFeeParams'); +require('./scripts/governance'); const BaseConfig = require('../../hardhat.base.config'); diff --git a/examples/zksync/scripts/governance.js b/examples/zksync/scripts/governance.js new file mode 100644 index 0000000..0416b70 --- /dev/null +++ b/examples/zksync/scripts/governance.js @@ -0,0 +1,193 @@ +const { Provider, Wallet, utils } = require('zksync-ethers'); +const { ethers } = require('ethers'); +const { readDeployContract } = require('../../../script/utils'); +const logName = require('../../../script/deploy_log_name'); +const { task, types } = require('hardhat/config'); + +require('dotenv').config(); + +async function initNetwork() { + const walletPrivateKey = process.env.DEVNET_PRIVKEY; + const l1Provider = new Provider(process.env.L1RPC); + const l2Provider = new Provider(process.env.L2RPC); + const ethereumName = process.env.ETHEREUM; + const zkSyncWallet = new Wallet(walletPrivateKey, l2Provider, l1Provider); + + const mailBoxAddr = await l1Provider.getMainContractAddress(); + if (mailBoxAddr === undefined) { + console.log('The zksync mailbox address not exist'); + return; + } + console.log(`The mailbox address: ${mailBoxAddr}`); + + const l1GovernanceAddr = readDeployContract( + logName.DEPLOY_GOVERNANCE_LOG_PREFIX, + logName.DEPLOY_LOG_GOVERNANCE, + ethereumName, + ); + if (l1GovernanceAddr === undefined) { + console.log('governance address not exist'); + return; + } + console.log(`The l1 governance address: ${l1GovernanceAddr}`); + return { + l1GovernanceAddr, + mailBoxAddr, + l1Provider, + l2Provider, + zkSyncWallet, + }; +} + +async function initZkLinkNetwork() { + const walletPrivateKey = process.env.ZKLINK_DEVNET_PRIVKEY; + const l1Provider = new Provider(process.env.ZKLINK_L1RPC); + const l2Provider = new Provider(process.env.ZKLINK_L2RPC); + const lineaName = process.env.LINEA; + const zkSyncWallet = new Wallet(walletPrivateKey, l2Provider, l1Provider); + + const mailBoxAddr = await l1Provider.getMainContractAddress(); + if (mailBoxAddr === undefined) { + console.log('The zksync mailbox address not exist'); + return; + } + console.log(`The mailbox address: ${mailBoxAddr}`); + + const l1GovernanceAddr = readDeployContract( + logName.DEPLOY_LINEA_L2_GOVERNANCE_LOG_PREFIX, + logName.DEPLOY_LOG_GOVERNANCE, + lineaName, + ); + if (l1GovernanceAddr === undefined) { + console.log('governance address not exist'); + return; + } + console.log(`The l1 governance address: ${l1GovernanceAddr}`); + return { + l1GovernanceAddr, + mailBoxAddr, + l1Provider, + l2Provider, + zkSyncWallet, + }; +} + +task('encodeL1ToL2Calldata', 'Encode call data for l1 to l2') + .addParam('to', 'The l2 target address', undefined, types.string) + .addParam('l2CallData', 'The l2 call data to target address', undefined, types.string) + .addParam('l2CallValue', 'The l2 call value to target address', undefined, types.int) + .addParam( + 'refundAddress', + 'The excess fee and value refund address(should be an EOA address)', + undefined, + types.string, + ) + .setAction(async (taskArgs, hre) => { + const networkInfo = await initNetwork(); + await encodeL1ToL2Calldata(taskArgs, hre, networkInfo); + }); + +task('zkLinkEncodeL1ToL2Calldata', 'Encode call data for l1 to l2') + .addParam('to', 'The l2 target address', undefined, types.string) + .addParam('l2CallData', 'The l2 call data to target address', undefined, types.string) + .addParam('l2CallValue', 'The l2 call value to target address', undefined, types.int) + .addParam( + 'refundAddress', + 'The excess fee and value refund address(should be an EOA address)', + undefined, + types.string, + ) + .setAction(async (taskArgs, hre) => { + const networkInfo = await initZkLinkNetwork(); + await encodeL1ToL2Calldata(taskArgs, hre, networkInfo); + }); + +task('checkL1TxStatus', 'Check the l1 tx status') + .addParam('l1TxHash', 'The l1 tx hash', undefined, types.string) + .setAction(async taskArgs => { + const l1Provider = new Provider(process.env.L1RPC); + const l2Provider = new Provider(process.env.L2RPC); + await checkL1TxStatus(taskArgs, l1Provider, l2Provider); + }); + +task('zkLinkCheckL1TxStatus', 'Check the l1 tx status') + .addParam('l1TxHash', 'The l1 tx hash', undefined, types.string) + .setAction(async taskArgs => { + const l1Provider = new Provider(process.env.ZKLINK_L1RPC); + const l2Provider = new Provider(process.env.ZKLINK_L2RPC); + await checkL1TxStatus(taskArgs, l1Provider, l2Provider); + }); + +async function encodeL1ToL2Calldata(taskArgs, hre, networkInfo) { + const { l1GovernanceAddr, mailBoxAddr, l1Provider, l2Provider, zkSyncWallet } = networkInfo; + + const l2ToContractAddress = taskArgs.to; + const l2CallData = taskArgs.l2CallData; + const l2CallValue = taskArgs.l2CallValue; + const refundAddress = taskArgs.refundAddress; + console.log(`The l2 target contract address: ${l2ToContractAddress}`); + console.log(`The l2 call data to target address: ${l2CallData}`); + console.log(`The l2 call value to target address: ${l2CallValue}`); + console.log(`The refund address: ${refundAddress}`); + + const l2GovernanceAddr = utils.applyL1ToL2Alias(l1GovernanceAddr); + console.log(`The l2 governance address: ${l2GovernanceAddr}`); + + /** + * The estimateL1ToL2Execute method gives us the gasLimit for sending an L1->L2 message + */ + + const l2GasLimit = await l2Provider.estimateL1ToL2Execute({ + contractAddress: l2GovernanceAddr, + calldata: l2CallData, + overrides: { + value: l2CallValue, + }, + }); + console.log(`Estimate gasLimit on L1 is ${l2GasLimit.valueOf()}`); + + /** + * The getGasPrice method gives us the current gas price on L1 + */ + const l1GasPrice = await l1Provider.getGasPrice(); + console.log(`Current gas price on L1 is ${ethers.formatEther(l1GasPrice)} ETH`); + + /** + * The getBaseCost method gives us the base cost of sending an L1->L2 message + */ + const baseCost = await zkSyncWallet.getBaseCost({ + // L2 computation + gasLimit: l2GasLimit, + // L1 gas price + gasPrice: l1GasPrice, + }); + console.log(`Executing this transaction will cost ${ethers.formatEther(baseCost)} ETH`); + const finalL1ToL2MsgValue = BigInt(l2CallValue) + BigInt(baseCost); + console.log(`The msg value: ${ethers.formatEther(finalL1ToL2MsgValue)} ETH`); + + const mailBox = await hre.ethers.getContractAt('IMailbox', '0x0000000000000000000000000000000000000000'); + const mailBoxCalldata = mailBox.interface.encodeFunctionData('requestL2Transaction', [ + l2ToContractAddress, + l2CallValue, + l2CallData, + l2GasLimit, + utils.REQUIRED_L1_TO_L2_GAS_PER_PUBDATA_LIMIT, + [], + refundAddress, + ]); + + console.log(`The l1 to l2 call target: ${mailBoxAddr}`); + console.log(`The l1 to l2 call data: ${mailBoxCalldata}`); + console.log(`The l1 to l2 call value: ${finalL1ToL2MsgValue}`); +} + +async function checkL1TxStatus(taskArgs, l1Provider, l2Provider) { + const l1TxHash = taskArgs.l1TxHash; + console.log(`The l1 tx hash: ${l1TxHash}`); + console.log('Waiting for the L2 execution of the transaction. This may take up to 10-15 minutes ⏰'); + const txHandle = await l1Provider.getTransaction(l1TxHash); + const l2Tx = await l2Provider.getL2TransactionFromPriorityOp(txHandle); + console.log(`The l2 tx hash: ${l2Tx.hash}`); + const l2TxStatus = await l2Provider.getTransactionStatus(l2Tx.hash); + console.log(`The l2 tx status: ${l2TxStatus}`); +} diff --git a/hardhat.config.js b/hardhat.config.js index 160f0cf..6d01963 100644 --- a/hardhat.config.js +++ b/hardhat.config.js @@ -6,6 +6,8 @@ require('./script/deploy_l1_gateway'); require('./script/deploy_l2_gateway'); require('./script/deploy_eth_gateway'); require('./script/deploy_erc20_bridge'); +require('./script/deploy_governance'); +require('./script/deploy_linea_l2_governance'); const BaseConfig = require('./hardhat.base.config'); diff --git a/script/ChainConfig.json b/script/ChainConfig.json index 85d2cef..e6011b6 100644 --- a/script/ChainConfig.json +++ b/script/ChainConfig.json @@ -180,13 +180,13 @@ "eth": true, "l2Gateway": { "contractName": "LineaL2Gateway", - "constructParams": ["0xC499a572640B64eA1C8c194c43Bc3E19940719dC"], + "constructParams": ["0x971e727e956690b9957be6d51Ec16E73AcAC83A7"], "initializeParams": [] }, "l1Gateway": { - "netName": "GOERLI", + "netName": "SEPOLIA", "contractName": "LineaL1Gateway", - "constructParams": ["0x70BaD09280FD342D02fe64119779BC1f0791BAC2"], + "constructParams": ["0xB218f8A4Bc926cF1cA7b3423c154a0D627Bdb7E5"], "initializeParams": [] } }, diff --git a/script/deploy_arbitrator.js b/script/deploy_arbitrator.js index 094644b..b98a3f1 100644 --- a/script/deploy_arbitrator.js +++ b/script/deploy_arbitrator.js @@ -121,6 +121,43 @@ task('upgradeArbitrator', 'Upgrade arbitrator') } }); +task('deployArbitratorTarget', 'Deploy arbitrator target') + .addOptionalParam('skipVerify', 'Skip verify', false, types.boolean) + .addOptionalParam('dummy', 'Deploy dummy contract for test', false, types.boolean) + .setAction(async (taskArgs, hardhat) => { + let skipVerify = taskArgs.skipVerify; + let dummy = taskArgs.dummy; + console.log('skip verify contracts?', skipVerify); + console.log('deploy dummy contracts?', dummy); + + const contractDeployer = new ChainContractDeployer(hardhat); + await contractDeployer.init(); + const deployerWallet = contractDeployer.deployerWallet; + + const { deployLogPath, deployLog } = createOrGetDeployLog(logName.DEPLOY_ARBITRATOR_LOG_PREFIX); + deployLog[logName.DEPLOY_LOG_DEPLOYER] = deployerWallet.address; + fs.writeFileSync(deployLogPath, JSON.stringify(deployLog, null, 2)); + + // deploy arbitrator target + let arbitratorTargetAddr; + console.log('deploy arbitrator target...'); + const contractName = getArbitratorContractName(dummy); + const contract = await contractDeployer.deployContract(contractName, []); + const transaction = await getDeployTx(contract); + console.log('deploy tx hash', transaction.hash); + arbitratorTargetAddr = await contract.getAddress(); + deployLog[logName.DEPLOY_LOG_ARBITRATOR_TARGET] = arbitratorTargetAddr; + fs.writeFileSync(deployLogPath, JSON.stringify(deployLog, null, 2)); + console.log('arbitrator', arbitratorTargetAddr); + + // verify target contract + if (!skipVerify) { + await verifyContractCode(hardhat, arbitratorTargetAddr, []); + deployLog[logName.DEPLOY_LOG_ARBITRATOR_VERIFIED] = true; + fs.writeFileSync(deployLogPath, JSON.stringify(deployLog, null, 2)); + } + }); + task('setValidatorForEthereum', 'Set validator for ethereum') .addParam('validator', 'Validator Address', undefined, types.string) .addOptionalParam('active', 'Whether to activate the validator address', true, types.boolean) diff --git a/script/deploy_governance.js b/script/deploy_governance.js new file mode 100644 index 0000000..e07cb1d --- /dev/null +++ b/script/deploy_governance.js @@ -0,0 +1,171 @@ +const fs = require('fs'); +const { + verifyContractCode, + createOrGetDeployLog, + ChainContractDeployer, + getDeployTx, + readDeployContract, +} = require('./utils'); +const logName = require('./deploy_log_name'); +const { task, types } = require('hardhat/config'); + +task('deployGovernance', 'Deploy governance') + .addParam('admin', 'The admin address (default is the deployer)', undefined, types.string, true) + .addParam( + 'securityCouncil', + 'The security council address (default is the zero address)', + '0x0000000000000000000000000000000000000000', + types.string, + true, + ) + .addParam('minDelay', 'The initial minimum delay (in seconds) to be set for operations', 0, types.int, true) + .addParam('skipVerify', 'Skip verify', false, types.boolean, true) + .setAction(async (taskArgs, hardhat) => { + const contractDeployer = new ChainContractDeployer(hardhat); + await contractDeployer.init(); + const deployerWallet = contractDeployer.deployerWallet; + + let adminAddr = taskArgs.admin; + if (adminAddr === undefined) { + adminAddr = deployerWallet.address; + } + let securityCouncilAddr = taskArgs.securityCouncil; + let minDelay = taskArgs.minDelay; + let skipVerify = taskArgs.skipVerify; + console.log('admin', adminAddr); + console.log('securityCouncil', securityCouncilAddr); + console.log('minDelay', minDelay); + console.log('skip verify contracts?', skipVerify); + + const { deployLogPath, deployLog } = createOrGetDeployLog(logName.DEPLOY_GOVERNANCE_LOG_PREFIX); + deployLog[logName.DEPLOY_LOG_DEPLOYER] = deployerWallet.address; + fs.writeFileSync(deployLogPath, JSON.stringify(deployLog, null, 2)); + + // deploy governance + let governanceAddr; + const allConstructParams = [adminAddr, securityCouncilAddr, minDelay]; + if (!(logName.DEPLOY_LOG_GOVERNANCE in deployLog)) { + console.log('deploy governance...'); + const contract = await contractDeployer.deployContract('Governance', allConstructParams); + const transaction = await getDeployTx(contract); + governanceAddr = await contract.getAddress(); + deployLog[logName.DEPLOY_LOG_GOVERNANCE] = governanceAddr; + deployLog[logName.DEPLOY_LOG_DEPLOY_TX_HASH] = transaction.hash; + deployLog[logName.DEPLOY_LOG_DEPLOY_BLOCK_NUMBER] = transaction.blockNumber; + fs.writeFileSync(deployLogPath, JSON.stringify(deployLog, null, 2)); + } else { + governanceAddr = deployLog[logName.DEPLOY_LOG_GOVERNANCE]; + } + console.log('governance', governanceAddr); + + // verify governance + if (!(logName.DEPLOY_LOG_GOVERNANCE_VERIFIED in deployLog) && !skipVerify) { + await verifyContractCode(hardhat, governanceAddr, allConstructParams); + deployLog[logName.DEPLOY_LOG_GOVERNANCE_VERIFIED] = true; + fs.writeFileSync(deployLogPath, JSON.stringify(deployLog, null, 2)); + } + }); + +task('encodeUUPSUpgradeCalldata', 'Encode calldata for uups upgrade') + .addParam('newImplementation', 'The new implementation', undefined, types.string, false) + .setAction(async (taskArgs, hardhat) => { + let newImplementation = taskArgs.newImplementation; + console.log('new implementation', newImplementation); + + const contractFactory = await hardhat.ethers.getContractAt( + 'UUPSUpgradeable', + '0x0000000000000000000000000000000000000000', + ); + const upgradeToCalldata = contractFactory.interface.encodeFunctionData('upgradeTo', [newImplementation]); + console.log('upgradeTo calldata', upgradeToCalldata); + }); + +task('encodeERC20Approve', 'Encode calldata for erc20 approve') + .addParam('spender', 'The spender address', undefined, types.string, false) + .addParam( + 'amount', + 'The approve amount', + '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff', + types.string, + true, + ) + .setAction(async (taskArgs, hardhat) => { + let spender = taskArgs.spender; + let amount = taskArgs.amount; + console.log('spender', spender); + console.log('approve amount', amount); + + const contractFactory = await hardhat.ethers.getContractAt('IERC20', '0x0000000000000000000000000000000000000000'); + const approveCalldata = contractFactory.interface.encodeFunctionData('approve', [spender, amount]); + console.log('approve calldata', approveCalldata); + }); + +task('encodeOperation', 'Encode operation') + .addParam('target', 'The target address', undefined, types.string, false) + .addParam('value', 'The call value to target', undefined, types.int, false) + .addParam('data', 'The call data to target', undefined, types.string, false) + .addParam( + 'predecessor', + 'The predecessor of operation', + '0x0000000000000000000000000000000000000000000000000000000000000000', + types.string, + true, + ) + .addParam( + 'salt', + 'The salt of operation', + '0x0000000000000000000000000000000000000000000000000000000000000000', + types.string, + true, + ) + .addParam('delay', 'The delay', 0, types.int, true) + .setAction(async (taskArgs, hardhat) => { + let target = taskArgs.target; + let value = taskArgs.value; + let data = taskArgs.data; + let predecessor = taskArgs.predecessor; + let salt = taskArgs.salt; + let delay = taskArgs.delay; + console.log('target', target); + console.log('value', value); + console.log('data', data); + console.log('predecessor', predecessor); + console.log('salt', salt); + console.log('delay', delay); + + const governanceAddr = readDeployContract(logName.DEPLOY_GOVERNANCE_LOG_PREFIX, logName.DEPLOY_LOG_GOVERNANCE); + if (!governanceAddr) { + console.log('governance address not found'); + return; + } + console.log('governance', governanceAddr); + const governance = await hardhat.ethers.getContractAt('Governance', governanceAddr); + if (value > 0) { + const governanceBalance = await hardhat.ethers.provider.getBalance(governanceAddr); + console.log('governance balance', governanceBalance); + if (governanceBalance < value) { + console.log('insufficient balance for execute transaction, please transfer some eth to governance'); + return; + } + } + + const call = { + target, + value, + data, + }; + const operation = { + calls: [call], + predecessor: predecessor, + salt: salt, + }; + + const scheduleTransparentCalldata = governance.interface.encodeFunctionData('scheduleTransparent', [ + operation, + delay, + ]); + console.log('scheduleTransparentCalldata', scheduleTransparentCalldata); + + const executeCalldata = governance.interface.encodeFunctionData('execute', [operation]); + console.log('executeCalldata', executeCalldata); + }); diff --git a/script/deploy_linea_l2_governance.js b/script/deploy_linea_l2_governance.js new file mode 100644 index 0000000..0b59b1d --- /dev/null +++ b/script/deploy_linea_l2_governance.js @@ -0,0 +1,80 @@ +const fs = require('fs'); +const { + verifyContractCode, + getDeployTx, + createOrGetDeployLog, + readDeployContract, + ChainContractDeployer, +} = require('./utils'); +const logName = require('./deploy_log_name'); +const { zkLinkConfig } = require('./zklink_config'); +const { task, types } = require('hardhat/config'); + +task('deployLineaL2Governance', 'Deploy linea l2 governance') + .addParam('skipVerify', 'Skip verify', false, types.boolean, true) + .setAction(async (taskArgs, hardhat) => { + let skipVerify = taskArgs.skipVerify; + console.log('skip verify contracts?', skipVerify); + + const netName = process.env.NET; + if (!netName || !netName.startsWith('LINEA')) { + console.log('LineaL2Governance only can be deployed on linea'); + return; + } + const chainInfo = zkLinkConfig[netName]; + if (chainInfo === undefined) { + console.log('current net not support'); + return; + } + const l2GatewayInfo = chainInfo.l2Gateway; + if (l2GatewayInfo === undefined) { + console.log('l2 gateway config not exist'); + return; + } + const messageServiceAddr = l2GatewayInfo['constructParams'][0]; + console.log('l2 message service address', messageServiceAddr); + const l1GatewayInfo = chainInfo.l1Gateway; + if (l1GatewayInfo === undefined) { + console.log('l1 gateway config not exist'); + return; + } + const l1NetName = l1GatewayInfo.netName; + const l1GovernanceAddr = readDeployContract( + logName.DEPLOY_GOVERNANCE_LOG_PREFIX, + logName.DEPLOY_LOG_GOVERNANCE, + l1NetName, + ); + if (l1GovernanceAddr === undefined) { + console.log('l1 governance not exist'); + return; + } + console.log('l1 governance', l1GovernanceAddr); + + const { deployLogPath, deployLog } = createOrGetDeployLog(logName.DEPLOY_LINEA_L2_GOVERNANCE_LOG_PREFIX); + const contractDeployer = new ChainContractDeployer(hardhat); + await contractDeployer.init(); + + // deploy governance + let governanceAddr; + const allConstructParams = [messageServiceAddr, l1GovernanceAddr]; + if (!(logName.DEPLOY_LOG_GOVERNANCE in deployLog)) { + console.log('deploy governance...'); + const contract = await contractDeployer.deployContract('LineaL2Governance', allConstructParams); + const transaction = await getDeployTx(contract); + governanceAddr = await contract.getAddress(); + deployLog[logName.DEPLOY_LOG_GOVERNANCE] = governanceAddr; + deployLog[logName.DEPLOY_LOG_DEPLOY_TX_HASH] = transaction.hash; + deployLog[logName.DEPLOY_LOG_DEPLOY_BLOCK_NUMBER] = transaction.blockNumber; + fs.writeFileSync(deployLogPath, JSON.stringify(deployLog, null, 2)); + } else { + governanceAddr = deployLog[logName.DEPLOY_LOG_GOVERNANCE]; + } + console.log('linea l2 governance', governanceAddr); + + // verify governance + if (!(logName.DEPLOY_LOG_GOVERNANCE_VERIFIED in deployLog) && !skipVerify) { + await verifyContractCode(hardhat, governanceAddr, allConstructParams); + deployLog[logName.DEPLOY_LOG_GOVERNANCE_VERIFIED] = true; + fs.writeFileSync(deployLogPath, JSON.stringify(deployLog, null, 2)); + } + }); diff --git a/script/deploy_log_name.js b/script/deploy_log_name.js index 581a3f9..f1ac348 100644 --- a/script/deploy_log_name.js +++ b/script/deploy_log_name.js @@ -33,6 +33,14 @@ const DEPLOY_LOG_ARBITRATOR_VERIFIED = 'arbitratorVerified'; const DEPLOY_LOG_ARBITRATOR_TARGET = 'arbitratorTarget'; const DEPLOY_LOG_ARBITRATOR_TARGET_VERIFIED = 'arbitratorTargetVerified'; +// consumed in deploy_governance.js +const DEPLOY_GOVERNANCE_LOG_PREFIX = 'deploy_governance'; +const DEPLOY_LOG_GOVERNANCE = 'governance'; +const DEPLOY_LOG_GOVERNANCE_VERIFIED = 'governanceVerified'; + +// consumed in deploy_linea_l2_governance.js +const DEPLOY_LINEA_L2_GOVERNANCE_LOG_PREFIX = 'deploy_linea_l2_governance'; + module.exports = { DEPLOY_ZKLINK_LOG_PREFIX, DEPLOY_LOG_DEPLOYER, @@ -61,4 +69,8 @@ module.exports = { DEPLOY_ERC20_BRIDGE_VERIFIED, DEPLOY_ERC20_BRIDGE_TARGET, DEPLOY_ERC20_BRIDGE_TARGET_VERIFIED, + DEPLOY_GOVERNANCE_LOG_PREFIX, + DEPLOY_LOG_GOVERNANCE, + DEPLOY_LOG_GOVERNANCE_VERIFIED, + DEPLOY_LINEA_L2_GOVERNANCE_LOG_PREFIX, }; diff --git a/script/deploy_zklink.js b/script/deploy_zklink.js index 18c8f59..05e9581 100644 --- a/script/deploy_zklink.js +++ b/script/deploy_zklink.js @@ -139,6 +139,50 @@ task('upgradeZkLink', 'Upgrade zkLink') } }); +task('deployZkLinkTarget', 'Deploy zkLink target') + .addOptionalParam('skipVerify', 'Skip verify', false, types.boolean) + .addOptionalParam('dummy', 'Deploy dummy contract for test', false, types.boolean) + .setAction(async (taskArgs, hardhat) => { + let skipVerify = taskArgs.skipVerify; + let dummy = taskArgs.dummy; + console.log('skip verify contracts?', skipVerify); + console.log('deploy dummy contracts?', dummy); + + const netName = process.env.NET; + const chainInfo = zkLinkConfig[netName]; + if (chainInfo === undefined) { + console.log('current net not support'); + return; + } + const isEthGasToken = chainInfo.eth; + console.log(`is eth the gas token of ${netName}?`, isEthGasToken); + + const contractDeployer = new ChainContractDeployer(hardhat); + await contractDeployer.init(); + + const { deployLogPath, deployLog } = createOrGetDeployLog(logName.DEPLOY_ZKLINK_LOG_PREFIX); + + // deploy zkLink target + let zkLinkTargetAddr; + console.log('deploy zkLink target...'); + const contractName = getZkLinkContractName(dummy); + const contract = await contractDeployer.deployContract(contractName, [isEthGasToken]); + const transaction = await getDeployTx(contract); + console.log('deploy tx hash', transaction.hash); + zkLinkTargetAddr = await contract.getAddress(); + console.log('zkLink target', zkLinkTargetAddr); + deployLog[logName.DEPLOY_LOG_ZKLINK_IS_ETH_GAS_TOKEN] = isEthGasToken; + deployLog[logName.DEPLOY_LOG_ZKLINK_TARGET] = zkLinkTargetAddr; + fs.writeFileSync(deployLogPath, JSON.stringify(deployLog, null, 2)); + + // verify target contract + if (!skipVerify) { + await verifyContractCode(hardhat, zkLinkTargetAddr, [isEthGasToken]); + deployLog[logName.DEPLOY_LOG_ZKLINK_TARGET_VERIFIED] = true; + fs.writeFileSync(deployLogPath, JSON.stringify(deployLog, null, 2)); + } + }); + task('setGateway', 'Set gateway for zkLink').setAction(async (taskArgs, hardhat) => { const l2GatewayAddr = readDeployContract(logName.DEPLOY_L2_GATEWAY_LOG_PREFIX, logName.DEPLOY_GATEWAY); if (l2GatewayAddr === undefined) {