Source Code
Overview
ETH Balance
0 ETH
ETH Value
$0.00Multichain Info
N/A
| Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
Latest 1 internal transaction
Advanced mode:
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 2225449 | 147 days ago | Contract Creation | 0 ETH |
Cross-Chain Transactions
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
StaticMerkleRootWeightedMultisigIsmFactory
Compiler Version
v0.8.22+commit.4fc1097e
Optimization Enabled:
Yes with 999999 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity >=0.8.0;
/*@@@@@@@ @@@@@@@@@
@@@@@@@@@ @@@@@@@@@
@@@@@@@@@ @@@@@@@@@
@@@@@@@@@ @@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@ HYPERLANE @@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@ @@@@@@@@@
@@@@@@@@@ @@@@@@@@@
@@@@@@@@@ @@@@@@@@@
@@@@@@@@@ @@@@@@@@*/
import {IInterchainSecurityModule} from "../../interfaces/IInterchainSecurityModule.sol";
import {AbstractMerkleRootMultisigIsm} from "./AbstractMerkleRootMultisigIsm.sol";
import {AbstractMessageIdMultisigIsm} from "./AbstractMessageIdMultisigIsm.sol";
import {AbstractStaticWeightedMultisigIsm} from "./AbstractWeightedMultisigIsm.sol";
import {AbstractMultisigIsm} from "./AbstractMultisigIsm.sol";
import {StaticWeightedValidatorSetFactory} from "../../libs/StaticWeightedValidatorSetFactory.sol";
import {MetaProxy} from "../../libs/MetaProxy.sol";
abstract contract AbstractMetaProxyWeightedMultisigIsm is
AbstractStaticWeightedMultisigIsm
{
/**
* @inheritdoc AbstractStaticWeightedMultisigIsm
*/
function validatorsAndThresholdWeight(
bytes calldata /* _message*/
) public pure override returns (ValidatorInfo[] memory, uint96) {
return abi.decode(MetaProxy.metadata(), (ValidatorInfo[], uint96));
}
}
contract StaticMerkleRootWeightedMultisigIsm is
AbstractMerkleRootMultisigIsm,
AbstractMetaProxyWeightedMultisigIsm
{
uint8 public constant moduleType =
uint8(IInterchainSecurityModule.Types.WEIGHTED_MERKLE_ROOT_MULTISIG);
}
contract StaticMessageIdWeightedMultisigIsm is
AbstractMessageIdMultisigIsm,
AbstractMetaProxyWeightedMultisigIsm
{
uint8 public constant moduleType =
uint8(IInterchainSecurityModule.Types.WEIGHTED_MESSAGE_ID_MULTISIG);
}
contract StaticMerkleRootWeightedMultisigIsmFactory is
StaticWeightedValidatorSetFactory
{
function _deployImplementation() internal override returns (address) {
return address(new StaticMerkleRootWeightedMultisigIsm());
}
}
contract StaticMessageIdWeightedMultisigIsmFactory is
StaticWeightedValidatorSetFactory
{
function _deployImplementation() internal override returns (address) {
return address(new StaticMessageIdWeightedMultisigIsm());
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)
pragma solidity ^0.8.0;
import "../utils/ContextUpgradeable.sol";
import "../proxy/utils/Initializable.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
function __Ownable_init() internal onlyInitializing {
__Ownable_init_unchained();
}
function __Ownable_init_unchained() internal onlyInitializing {
_transferOwnership(_msgSender());
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[49] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.2;
import "../../utils/AddressUpgradeable.sol";
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```solidity
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
*
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Indicates that the contract has been initialized.
* @custom:oz-retyped-from bool
*/
uint8 private _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool private _initializing;
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint8 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts.
*
* Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a
* constructor.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
bool isTopLevelCall = !_initializing;
require(
(isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),
"Initializable: contract is already initialized"
);
_initialized = 1;
if (isTopLevelCall) {
_initializing = true;
}
_;
if (isTopLevelCall) {
_initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* A reinitializer may be used after the original initialization step. This is essential to configure modules that
* are added through upgrades and that require initialization.
*
* When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
* cannot be nested. If one is invoked in the context of another, execution will revert.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*
* WARNING: setting the version to 255 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
modifier reinitializer(uint8 version) {
require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
_initialized = version;
_initializing = true;
_;
_initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
require(_initializing, "Initializable: contract is not initializing");
_;
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*
* Emits an {Initialized} event the first time it is successfully executed.
*/
function _disableInitializers() internal virtual {
require(!_initializing, "Initializable: contract is initializing");
if (_initialized != type(uint8).max) {
_initialized = type(uint8).max;
emit Initialized(type(uint8).max);
}
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint8) {
return _initialized;
}
/**
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _initializing;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library AddressUpgradeable {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
*
* Furthermore, `isContract` will also return true if the target contract within
* the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
* which only has an effect at the end of a transaction.
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
pragma solidity ^0.8.0;
import "../proxy/utils/Initializable.sol";
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract ContextUpgradeable is Initializable {
function __Context_init() internal onlyInitializing {
}
function __Context_init_unchained() internal onlyInitializing {
}
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[50] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
*
* Furthermore, `isContract` will also return true if the target contract within
* the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
* which only has an effect at the end of a transaction.
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Create2.sol)
pragma solidity ^0.8.0;
/**
* @dev Helper to make usage of the `CREATE2` EVM opcode easier and safer.
* `CREATE2` can be used to compute in advance the address where a smart
* contract will be deployed, which allows for interesting new mechanisms known
* as 'counterfactual interactions'.
*
* See the https://eips.ethereum.org/EIPS/eip-1014#motivation[EIP] for more
* information.
*/
library Create2 {
/**
* @dev Deploys a contract using `CREATE2`. The address where the contract
* will be deployed can be known in advance via {computeAddress}.
*
* The bytecode for a contract can be obtained from Solidity with
* `type(contractName).creationCode`.
*
* Requirements:
*
* - `bytecode` must not be empty.
* - `salt` must have not been used for `bytecode` already.
* - the factory must have a balance of at least `amount`.
* - if `amount` is non-zero, `bytecode` must have a `payable` constructor.
*/
function deploy(uint256 amount, bytes32 salt, bytes memory bytecode) internal returns (address addr) {
require(address(this).balance >= amount, "Create2: insufficient balance");
require(bytecode.length != 0, "Create2: bytecode length is zero");
/// @solidity memory-safe-assembly
assembly {
addr := create2(amount, add(bytecode, 0x20), mload(bytecode), salt)
}
require(addr != address(0), "Create2: Failed on deploy");
}
/**
* @dev Returns the address where a contract will be stored if deployed via {deploy}. Any change in the
* `bytecodeHash` or `salt` will result in a new destination address.
*/
function computeAddress(bytes32 salt, bytes32 bytecodeHash) internal view returns (address) {
return computeAddress(salt, bytecodeHash, address(this));
}
/**
* @dev Returns the address where a contract will be stored if deployed via {deploy} from a contract located at
* `deployer`. If `deployer` is this contract's address, returns the same value as {computeAddress}.
*/
function computeAddress(bytes32 salt, bytes32 bytecodeHash, address deployer) internal pure returns (address addr) {
/// @solidity memory-safe-assembly
assembly {
let ptr := mload(0x40) // Get free memory pointer
// | | ? ptr ... ? ptr + 0x0B (start) ... ? ptr + 0x20 ... ? ptr + 0x40 ... |
// |-------------------|---------------------------------------------------------------------------|
// | bytecodeHash | CCCCCCCCCCCCC...CC |
// | salt | BBBBBBBBBBBBB...BB |
// | deployer | 000000...0000AAAAAAAAAAAAAAAAAAA...AA |
// | 0xFF | FF |
// |-------------------|---------------------------------------------------------------------------|
// | memory | 000000...00FFAAAAAAAAAAAAAAAAAAA...AABBBBBBBBBBBBB...BBCCCCCCCCCCCCC...CC |
// | keccak(start, 85) | ?????????????????????????????????????????????????????????????? |
mstore(add(ptr, 0x40), bytecodeHash)
mstore(add(ptr, 0x20), salt)
mstore(ptr, deployer) // Right-aligned with 12 preceding garbage bytes
let start := add(ptr, 0x0b) // The hashed data starts at the final garbage byte which we will set to 0xff
mstore8(start, 0xff)
addr := keccak256(start, 85)
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol)
pragma solidity ^0.8.0;
import "./math/Math.sol";
import "./math/SignedMath.sol";
/**
* @dev String operations.
*/
library Strings {
bytes16 private constant _SYMBOLS = "0123456789abcdef";
uint8 private constant _ADDRESS_LENGTH = 20;
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
unchecked {
uint256 length = Math.log10(value) + 1;
string memory buffer = new string(length);
uint256 ptr;
/// @solidity memory-safe-assembly
assembly {
ptr := add(buffer, add(32, length))
}
while (true) {
ptr--;
/// @solidity memory-safe-assembly
assembly {
mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
}
value /= 10;
if (value == 0) break;
}
return buffer;
}
}
/**
* @dev Converts a `int256` to its ASCII `string` decimal representation.
*/
function toString(int256 value) internal pure returns (string memory) {
return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMath.abs(value))));
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
unchecked {
return toHexString(value, Math.log256(value) + 1);
}
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
/**
* @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
*/
function toHexString(address addr) internal pure returns (string memory) {
return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
}
/**
* @dev Returns true if the two strings are equal.
*/
function equal(string memory a, string memory b) internal pure returns (bool) {
return keccak256(bytes(a)) == keccak256(bytes(b));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/cryptography/ECDSA.sol)
pragma solidity ^0.8.0;
import "../Strings.sol";
/**
* @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
*
* These functions can be used to verify that a message was signed by the holder
* of the private keys of a given address.
*/
library ECDSA {
enum RecoverError {
NoError,
InvalidSignature,
InvalidSignatureLength,
InvalidSignatureS,
InvalidSignatureV // Deprecated in v4.8
}
function _throwError(RecoverError error) private pure {
if (error == RecoverError.NoError) {
return; // no error: do nothing
} else if (error == RecoverError.InvalidSignature) {
revert("ECDSA: invalid signature");
} else if (error == RecoverError.InvalidSignatureLength) {
revert("ECDSA: invalid signature length");
} else if (error == RecoverError.InvalidSignatureS) {
revert("ECDSA: invalid signature 's' value");
}
}
/**
* @dev Returns the address that signed a hashed message (`hash`) with
* `signature` or error string. This address can then be used for verification purposes.
*
* The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {toEthSignedMessageHash} on it.
*
* Documentation for signature generation:
* - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
* - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
*
* _Available since v4.3._
*/
function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {
if (signature.length == 65) {
bytes32 r;
bytes32 s;
uint8 v;
// ecrecover takes the signature parameters, and the only way to get them
// currently is to use assembly.
/// @solidity memory-safe-assembly
assembly {
r := mload(add(signature, 0x20))
s := mload(add(signature, 0x40))
v := byte(0, mload(add(signature, 0x60)))
}
return tryRecover(hash, v, r, s);
} else {
return (address(0), RecoverError.InvalidSignatureLength);
}
}
/**
* @dev Returns the address that signed a hashed message (`hash`) with
* `signature`. This address can then be used for verification purposes.
*
* The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {toEthSignedMessageHash} on it.
*/
function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, signature);
_throwError(error);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
*
* See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
*
* _Available since v4.3._
*/
function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError) {
bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
uint8 v = uint8((uint256(vs) >> 255) + 27);
return tryRecover(hash, v, r, s);
}
/**
* @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
*
* _Available since v4.2._
*/
function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, r, vs);
_throwError(error);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `v`,
* `r` and `s` signature fields separately.
*
* _Available since v4.3._
*/
function tryRecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address, RecoverError) {
// EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
// unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
// the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ? {27, 28}. Most
// signatures from current libraries generate a unique signature with an s-value in the lower half order.
//
// If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
// with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
// vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
// these malleable signatures as well.
if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
return (address(0), RecoverError.InvalidSignatureS);
}
// If the signature is valid (and not malleable), return the signer address
address signer = ecrecover(hash, v, r, s);
if (signer == address(0)) {
return (address(0), RecoverError.InvalidSignature);
}
return (signer, RecoverError.NoError);
}
/**
* @dev Overload of {ECDSA-recover} that receives the `v`,
* `r` and `s` signature fields separately.
*/
function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, v, r, s);
_throwError(error);
return recovered;
}
/**
* @dev Returns an Ethereum Signed Message, created from a `hash`. This
* produces hash corresponding to the one signed with the
* https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
* JSON-RPC method as part of EIP-191.
*
* See {recover}.
*/
function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32 message) {
// 32 is the length in bytes of hash,
// enforced by the type signature above
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, "\x19Ethereum Signed Message:\n32")
mstore(0x1c, hash)
message := keccak256(0x00, 0x3c)
}
}
/**
* @dev Returns an Ethereum Signed Message, created from `s`. This
* produces hash corresponding to the one signed with the
* https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
* JSON-RPC method as part of EIP-191.
*
* See {recover}.
*/
function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", Strings.toString(s.length), s));
}
/**
* @dev Returns an Ethereum Signed Typed Data, created from a
* `domainSeparator` and a `structHash`. This produces hash corresponding
* to the one signed with the
* https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]
* JSON-RPC method as part of EIP-712.
*
* See {recover}.
*/
function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 data) {
/// @solidity memory-safe-assembly
assembly {
let ptr := mload(0x40)
mstore(ptr, "\x19\x01")
mstore(add(ptr, 0x02), domainSeparator)
mstore(add(ptr, 0x22), structHash)
data := keccak256(ptr, 0x42)
}
}
/**
* @dev Returns an Ethereum Signed Data with intended validator, created from a
* `validator` and `data` according to the version 0 of EIP-191.
*
* See {recover}.
*/
function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\x19\x00", validator, data));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
enum Rounding {
Down, // Toward negative infinity
Up, // Toward infinity
Zero // Toward zero
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds up instead
* of rounding down.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
* @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
* with further edits by Uniswap Labs also under MIT license.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + prod0.
uint256 prod0; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
// Solidity will revert if denominator == 0, unlike the div opcode on its own.
// The surrounding unchecked block does not change this fact.
// See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
require(denominator > prod1, "Math: mulDiv overflow");
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
// See https://cs.stackexchange.com/q/138556/92363.
// Does not overflow because the denominator cannot be zero at this stage in the function.
uint256 twos = denominator & (~denominator + 1);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
// in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
//
// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
//
// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
// ? `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
// ? `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
//
// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
uint256 result = 1 << (log2(a) >> 1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
// into the expected uint128 result.
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10 ** 64) {
value /= 10 ** 64;
result += 64;
}
if (value >= 10 ** 32) {
value /= 10 ** 32;
result += 32;
}
if (value >= 10 ** 16) {
value /= 10 ** 16;
result += 16;
}
if (value >= 10 ** 8) {
value /= 10 ** 8;
result += 8;
}
if (value >= 10 ** 4) {
value /= 10 ** 4;
result += 4;
}
if (value >= 10 ** 2) {
value /= 10 ** 2;
result += 2;
}
if (value >= 10 ** 1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256, rounded down, of a positive value.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 256, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard signed math utilities missing in the Solidity language.
*/
library SignedMath {
/**
* @dev Returns the largest of two signed numbers.
*/
function max(int256 a, int256 b) internal pure returns (int256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two signed numbers.
*/
function min(int256 a, int256 b) internal pure returns (int256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two signed numbers without overflow.
* The result is rounded towards zero.
*/
function average(int256 a, int256 b) internal pure returns (int256) {
// Formula from the book "Hacker's Delight"
int256 x = (a & b) + ((a ^ b) >> 1);
return x + (int256(uint256(x) >> 255) & (a ^ b));
}
/**
* @dev Returns the absolute unsigned value of a signed value.
*/
function abs(int256 n) internal pure returns (uint256) {
unchecked {
// must be unchecked in order to support `n = type(int256).min`
return uint256(n >= 0 ? n : -n);
}
}
}// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity >=0.6.11;
/**
* @title PackageVersioned
* @notice Package version getter for contracts
**/
abstract contract PackageVersioned {
// GENERATED CODE - DO NOT EDIT
string public constant PACKAGE_VERSION = "7.1.10";
}// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity >=0.6.11;
interface IInterchainSecurityModule {
enum Types {
UNUSED,
ROUTING,
AGGREGATION,
LEGACY_MULTISIG,
MERKLE_ROOT_MULTISIG,
MESSAGE_ID_MULTISIG,
NULL, // used with relayer carrying no metadata
CCIP_READ,
ARB_L2_TO_L1,
WEIGHTED_MERKLE_ROOT_MULTISIG,
WEIGHTED_MESSAGE_ID_MULTISIG,
OP_L2_TO_L1
}
/**
* @notice Returns an enum that represents the type of security model
* encoded by this ISM.
* @dev Relayers infer how to fetch and format metadata.
*/
function moduleType() external view returns (uint8);
/**
* @notice Defines a security model responsible for verifying interchain
* messages based on the provided metadata.
* @param _metadata Off-chain metadata provided by a relayer, specific to
* the security model encoded by the module (e.g. validator signatures)
* @param _message Hyperlane encoded interchain message
* @return True if the message was verified
*/
function verify(
bytes calldata _metadata,
bytes calldata _message
) external returns (bool);
}
interface ISpecifiesInterchainSecurityModule {
function interchainSecurityModule()
external
view
returns (IInterchainSecurityModule);
}// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity >=0.6.11;
import {IInterchainSecurityModule} from "../IInterchainSecurityModule.sol";
interface IMultisigIsm is IInterchainSecurityModule {
/**
* @notice Returns the set of validators responsible for verifying _message
* and the number of signatures required
* @dev Can change based on the content of _message
* @dev Signatures provided to `verify` must be consistent with validator ordering
* @param _message Hyperlane formatted interchain message
* @return validators The array of validator addresses
* @return threshold The number of validator signatures needed
*/
function validatorsAndThreshold(
bytes calldata _message
) external view returns (address[] memory validators, uint8 threshold);
}// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity >=0.6.11;
/*@@@@@@@ @@@@@@@@@
@@@@@@@@@ @@@@@@@@@
@@@@@@@@@ @@@@@@@@@
@@@@@@@@@ @@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@ HYPERLANE @@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@ @@@@@@@@@
@@@@@@@@@ @@@@@@@@@
@@@@@@@@@ @@@@@@@@@
@@@@@@@@@ @@@@@@@@*/
import {IInterchainSecurityModule} from "../IInterchainSecurityModule.sol";
interface IStaticWeightedMultisigIsm is IInterchainSecurityModule {
// ============ Structs ============
// ValidatorInfo contains the signing address and weight of a validator
struct ValidatorInfo {
address signingAddress;
uint96 weight;
}
/**
* @notice Returns the validators and threshold weight for this ISM.
* @param _message The message to be verified
* @return validators The validators and their weights
* @return thresholdWeight The threshold weight required to pass verification
*/
function validatorsAndThresholdWeight(
bytes calldata _message
)
external
view
returns (ValidatorInfo[] memory validators, uint96 thresholdWeight);
}// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity >=0.8.0;
/**
* Format of metadata:
* [ 0: 32] Origin merkle tree address
* [ 32: 36] Index of message ID in merkle tree
* [ 36: 68] Signed checkpoint message ID
* [ 68:1092] Merkle proof
* [1092:1096] Signed checkpoint index (computed from proof and index)
* [1096:????] Validator signatures (length := threshold * 65)
*/
library MerkleRootMultisigIsmMetadata {
uint8 private constant ORIGIN_MERKLE_TREE_OFFSET = 0;
uint8 private constant MESSAGE_INDEX_OFFSET = 32;
uint8 private constant MESSAGE_ID_OFFSET = 36;
uint8 private constant MERKLE_PROOF_OFFSET = 68;
uint16 private constant MERKLE_PROOF_LENGTH = 32 * 32;
uint16 private constant SIGNED_INDEX_OFFSET = 1092;
uint16 private constant SIGNATURES_OFFSET = 1096;
uint8 private constant SIGNATURE_LENGTH = 65;
/**
* @notice Returns the origin merkle tree hook of the signed checkpoint as bytes32.
* @param _metadata ABI encoded Multisig ISM metadata.
* @return Origin merkle tree hook of the signed checkpoint as bytes32
*/
function originMerkleTreeHook(
bytes calldata _metadata
) internal pure returns (bytes32) {
return
bytes32(
_metadata[ORIGIN_MERKLE_TREE_OFFSET:ORIGIN_MERKLE_TREE_OFFSET +
32]
);
}
/**
* @notice Returns the index of the message being proven.
* @param _metadata ABI encoded Multisig ISM metadata.
* @return Index of the target message in the merkle tree.
*/
function messageIndex(
bytes calldata _metadata
) internal pure returns (uint32) {
return
uint32(
bytes4(_metadata[MESSAGE_INDEX_OFFSET:MESSAGE_INDEX_OFFSET + 4])
);
}
/**
* @notice Returns the index of the signed checkpoint.
* @param _metadata ABI encoded Multisig ISM metadata.
* @return Index of the signed checkpoint
*/
function signedIndex(
bytes calldata _metadata
) internal pure returns (uint32) {
return
uint32(
bytes4(_metadata[SIGNED_INDEX_OFFSET:SIGNED_INDEX_OFFSET + 4])
);
}
/**
* @notice Returns the message ID of the signed checkpoint.
* @param _metadata ABI encoded Multisig ISM metadata.
* @return Message ID of the signed checkpoint
*/
function signedMessageId(
bytes calldata _metadata
) internal pure returns (bytes32) {
return bytes32(_metadata[MESSAGE_ID_OFFSET:MESSAGE_ID_OFFSET + 32]);
}
/**
* @notice Returns the merkle proof branch of the message.
* @dev This appears to be more gas efficient than returning a calldata
* slice and using that.
* @param _metadata ABI encoded Multisig ISM metadata.
* @return Merkle proof branch of the message.
*/
function proof(
bytes calldata _metadata
) internal pure returns (bytes32[32] memory) {
return
abi.decode(
_metadata[MERKLE_PROOF_OFFSET:MERKLE_PROOF_OFFSET +
MERKLE_PROOF_LENGTH],
(bytes32[32])
);
}
/**
* @notice Returns the validator ECDSA signature at `_index`.
* @dev Assumes signatures are sorted by validator
* @dev Assumes `_metadata` encodes `threshold` signatures.
* @dev Assumes `_index` is less than `threshold`
* @param _metadata ABI encoded Multisig ISM metadata.
* @param _index The index of the signature to return.
* @return The validator ECDSA signature at `_index`.
*/
function signatureAt(
bytes calldata _metadata,
uint256 _index
) internal pure returns (bytes calldata) {
uint256 _start = SIGNATURES_OFFSET + (_index * SIGNATURE_LENGTH);
uint256 _end = _start + SIGNATURE_LENGTH;
return _metadata[_start:_end];
}
/**
* @notice Returns the number of signatures in the metadata.
* @param _metadata ABI encoded Merkle Root Multisig ISM metadata.
* @return The number of signatures in the metadata.
*/
function signatureCount(
bytes calldata _metadata
) internal pure returns (uint256) {
uint256 signatures = _metadata.length - SIGNATURES_OFFSET;
require(
signatures % SIGNATURE_LENGTH == 0,
"Invalid signatures length"
);
return signatures / SIGNATURE_LENGTH;
}
}// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity >=0.8.0;
/**
* Format of metadata:
* [ 0: 32] Origin merkle tree address
* [ 32: 64] Signed checkpoint root
* [ 64: 68] Signed checkpoint index
* [ 68:????] Validator signatures (length := threshold * 65)
*/
library MessageIdMultisigIsmMetadata {
uint8 private constant ORIGIN_MERKLE_TREE_OFFSET = 0;
uint8 private constant MERKLE_ROOT_OFFSET = 32;
uint8 private constant MERKLE_INDEX_OFFSET = 64;
uint8 private constant SIGNATURES_OFFSET = 68;
uint8 private constant SIGNATURE_LENGTH = 65;
/**
* @notice Returns the origin merkle tree hook of the signed checkpoint as bytes32.
* @param _metadata ABI encoded Multisig ISM metadata.
* @return Origin merkle tree hook of the signed checkpoint as bytes32
*/
function originMerkleTreeHook(
bytes calldata _metadata
) internal pure returns (bytes32) {
return
bytes32(
_metadata[ORIGIN_MERKLE_TREE_OFFSET:ORIGIN_MERKLE_TREE_OFFSET +
32]
);
}
/**
* @notice Returns the merkle root of the signed checkpoint.
* @param _metadata ABI encoded Multisig ISM metadata.
* @return Merkle root of the signed checkpoint
*/
function root(bytes calldata _metadata) internal pure returns (bytes32) {
return bytes32(_metadata[MERKLE_ROOT_OFFSET:MERKLE_ROOT_OFFSET + 32]);
}
/**
* @notice Returns the merkle index of the signed checkpoint.
* @param _metadata ABI encoded Multisig ISM metadata.
* @return Merkle index of the signed checkpoint
*/
function index(bytes calldata _metadata) internal pure returns (uint32) {
return
uint32(
bytes4(_metadata[MERKLE_INDEX_OFFSET:MERKLE_INDEX_OFFSET + 4])
);
}
/**
* @notice Returns the validator ECDSA signature at `_index`.
* @dev Assumes signatures are sorted by validator
* @dev Assumes `_metadata` encodes `threshold` signatures.
* @dev Assumes `_index` is less than `threshold`
* @param _metadata ABI encoded Multisig ISM metadata.
* @param _index The index of the signature to return.
* @return The validator ECDSA signature at `_index`.
*/
function signatureAt(
bytes calldata _metadata,
uint256 _index
) internal pure returns (bytes calldata) {
uint256 _start = SIGNATURES_OFFSET + (_index * SIGNATURE_LENGTH);
uint256 _end = _start + SIGNATURE_LENGTH;
return _metadata[_start:_end];
}
/**
* @notice Returns the number of signatures in the metadata.
* @param _metadata ABI encoded MessageId Multisig ISM metadata.
* @return The number of signatures in the metadata.
*/
function signatureCount(
bytes calldata _metadata
) internal pure returns (uint256) {
uint256 signatures = _metadata.length - SIGNATURES_OFFSET;
require(
signatures % SIGNATURE_LENGTH == 0,
"Invalid signatures length"
);
return signatures / SIGNATURE_LENGTH;
}
}// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity >=0.8.0;
// ============ Internal Imports ============
import {IInterchainSecurityModule} from "../../interfaces/IInterchainSecurityModule.sol";
import {AbstractMultisig} from "./AbstractMultisigIsm.sol";
import {MerkleRootMultisigIsmMetadata} from "../../isms/libs/MerkleRootMultisigIsmMetadata.sol";
import {Message} from "../../libs/Message.sol";
import {MerkleLib} from "../../libs/Merkle.sol";
import {CheckpointLib} from "../../libs/CheckpointLib.sol";
/**
* @title `AbstractMerkleRootMultisigIsm` — multi-sig ISM with the validators-censorship resistance guarantee.
* @notice This ISM allows using a newer signed checkpoint (say #33) to prove existence of an older message (#22) in the validators' MerkleTree.
* This guarantees censorship resistance as validators cannot hide a message
* by refusing to sign its checkpoint but later signing a checkpoint for a newer message.
* If validators decide to censor a message, they are left with only one option — to not produce checkpoints at all.
* Otherwise, the very next signed checkpoint (#33) can be used by any relayer to prove the previous message inclusion using this ISM.
* This is censorship resistance is missing in the sibling implementation `AbstractMessageIdMultisigIsm`,
* since it can only verify messages having the corresponding checkpoints.
* @dev Provides the default implementation of verifying signatures over a checkpoint and the message inclusion in that checkpoint.
* This abstract contract can be overridden for customizing the `validatorsAndThreshold()` (static or dynamic).
* @dev May be adapted in future to support batch message verification against a single root.
*/
abstract contract AbstractMerkleRootMultisigIsm is AbstractMultisig {
using MerkleRootMultisigIsmMetadata for bytes;
using Message for bytes;
// ============ Constants ============
/**
* @inheritdoc AbstractMultisig
*/
function digest(
bytes calldata _metadata,
bytes calldata _message
) internal pure virtual override returns (bytes32) {
require(
_metadata.messageIndex() <= _metadata.signedIndex(),
"Invalid merkle index metadata"
);
// We verify a merkle proof of (messageId, index) I to compute root J
bytes32 _signedRoot = MerkleLib.branchRoot(
_message.id(),
_metadata.proof(),
_metadata.messageIndex()
);
// We provide (messageId, index) J in metadata for digest derivation
return
CheckpointLib.digest(
_message.origin(),
_metadata.originMerkleTreeHook(),
_signedRoot,
_metadata.signedIndex(),
_metadata.signedMessageId()
);
}
/**
* @inheritdoc AbstractMultisig
*/
function signatureAt(
bytes calldata _metadata,
uint256 _index
) internal pure virtual override returns (bytes calldata) {
return _metadata.signatureAt(_index);
}
/**
* @inheritdoc AbstractMultisig
*/
function signatureCount(
bytes calldata _metadata
) public pure override returns (uint256) {
return _metadata.signatureCount();
}
}// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity >=0.8.0;
// ============ Internal Imports ============
import {IInterchainSecurityModule} from "../../interfaces/IInterchainSecurityModule.sol";
import {AbstractMultisig} from "./AbstractMultisigIsm.sol";
import {MessageIdMultisigIsmMetadata} from "../libs/MessageIdMultisigIsmMetadata.sol";
import {Message} from "../../libs/Message.sol";
import {CheckpointLib} from "../../libs/CheckpointLib.sol";
/**
* @title `AbstractMessageIdMultisigIsm` — multi-sig ISM for the censorship-friendly validators.
* @notice This ISM minimizes gas/performance overhead of the checkpoints verification by compromising on the censorship resistance.
* For censorship resistance consider using `AbstractMerkleRootMultisigIsm`.
* If the validators (`validatorsAndThreshold`) skip messages by not sign checkpoints for them,
* the relayers will not be able to aggregate a quorum of signatures sufficient to deliver these messages via this ISM.
* Integrations are free to choose the trade-off between the censorship resistance and the gas/processing overhead.
* @dev Provides the default implementation of verifying signatures over a checkpoint related to a specific message ID.
* This abstract contract can be customized to change the `validatorsAndThreshold()` (static or dynamic).
*/
abstract contract AbstractMessageIdMultisigIsm is AbstractMultisig {
using Message for bytes;
using MessageIdMultisigIsmMetadata for bytes;
// ============ Constants ============
/**
* @inheritdoc AbstractMultisig
*/
function digest(
bytes calldata _metadata,
bytes calldata _message
) internal pure override returns (bytes32) {
return
CheckpointLib.digest(
_message.origin(),
_metadata.originMerkleTreeHook(),
_metadata.root(),
_metadata.index(),
_message.id()
);
}
/**
* @inheritdoc AbstractMultisig
*/
function signatureAt(
bytes calldata _metadata,
uint256 _index
) internal pure virtual override returns (bytes calldata) {
return _metadata.signatureAt(_index);
}
/**
* @inheritdoc AbstractMultisig
*/
function signatureCount(
bytes calldata _metadata
) public pure override returns (uint256) {
return _metadata.signatureCount();
}
}// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity >=0.8.0;
/*@@@@@@@ @@@@@@@@@
@@@@@@@@@ @@@@@@@@@
@@@@@@@@@ @@@@@@@@@
@@@@@@@@@ @@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@ HYPERLANE @@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@ @@@@@@@@@
@@@@@@@@@ @@@@@@@@@
@@@@@@@@@ @@@@@@@@@
@@@@@@@@@ @@@@@@@@*/
// ============ External Imports ============
import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
// ============ Internal Imports ============
import {IInterchainSecurityModule} from "../../interfaces/IInterchainSecurityModule.sol";
import {IMultisigIsm} from "../../interfaces/isms/IMultisigIsm.sol";
import {Message} from "../../libs/Message.sol";
import {MerkleLib} from "../../libs/Merkle.sol";
import {PackageVersioned} from "../../PackageVersioned.sol";
/**
* @title AbstractMultisig
* @notice Manages per-domain m-of-n Validator sets
* @dev See ./AbstractMerkleRootMultisigIsm.sol and ./AbstractMessageIdMultisigIsm.sol
* for concrete implementations of `digest` and `signatureAt`.
* @dev See ./StaticMultisigIsm.sol for concrete implementations.
*/
abstract contract AbstractMultisig is PackageVersioned {
/**
* @notice Returns the digest to be used for signature verification.
* @param _metadata ABI encoded module metadata
* @param _message Formatted Hyperlane message (see Message.sol).
* @return digest The digest to be signed by validators
*/
function digest(
bytes calldata _metadata,
bytes calldata _message
) internal view virtual returns (bytes32);
/**
* @notice Returns the signature at a given index from the metadata.
* @param _metadata ABI encoded module metadata
* @param _index The index of the signature to return
* @return signature Packed encoding of signature (65 bytes)
*/
function signatureAt(
bytes calldata _metadata,
uint256 _index
) internal pure virtual returns (bytes calldata);
/**
* @notice Returns the number of signatures in the metadata.
* @param _metadata ABI encoded module metadata
* @return count The number of signatures
*/
function signatureCount(
bytes calldata _metadata
) public pure virtual returns (uint256);
}
/**
* @title AbstractMultisigIsm
* @notice Manages per-domain m-of-n Validator sets of AbstractMultisig that are used to verify
* interchain messages.
*/
abstract contract AbstractMultisigIsm is AbstractMultisig, IMultisigIsm {
// ============ Virtual Functions ============
// ======= OVERRIDE THESE TO IMPLEMENT =======
/**
* @notice Returns the set of validators responsible for verifying _message
* and the number of signatures required
* @dev Can change based on the content of _message
* @dev Signatures provided to `verify` must be consistent with validator ordering
* @param _message Hyperlane formatted interchain message
* @return validators The array of validator addresses
* @return threshold The number of validator signatures needed
*/
function validatorsAndThreshold(
bytes calldata _message
) public view virtual returns (address[] memory, uint8);
// ============ Public Functions ============
/**
* @notice Requires that m-of-n validators verify a merkle root,
* and verifies a merkle proof of `_message` against that root.
* @dev Optimization relies on the caller sorting signatures in the same order as validators.
* @dev Employs https://www.geeksforgeeks.org/two-pointers-technique/ to minimize gas usage.
* @param _metadata ABI encoded module metadata
* @param _message Formatted Hyperlane message (see Message.sol).
*/
function verify(
bytes calldata _metadata,
bytes calldata _message
) public view returns (bool) {
bytes32 _digest = digest(_metadata, _message);
(
address[] memory _validators,
uint8 _threshold
) = validatorsAndThreshold(_message);
require(_threshold > 0, "No MultisigISM threshold present for message");
uint256 _validatorCount = _validators.length;
uint256 _validatorIndex = 0;
// Assumes that signatures are ordered by validator
for (uint256 i = 0; i < _threshold; ++i) {
address _signer = ECDSA.recover(_digest, signatureAt(_metadata, i));
// Loop through remaining validators until we find a match
while (
_validatorIndex < _validatorCount &&
_signer != _validators[_validatorIndex]
) {
++_validatorIndex;
}
// Fail if we never found a match
require(_validatorIndex < _validatorCount, "!threshold");
++_validatorIndex;
}
return true;
}
}// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity >=0.8.0;
/*@@@@@@@ @@@@@@@@@
@@@@@@@@@ @@@@@@@@@
@@@@@@@@@ @@@@@@@@@
@@@@@@@@@ @@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@ HYPERLANE @@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@ @@@@@@@@@
@@@@@@@@@ @@@@@@@@@
@@@@@@@@@ @@@@@@@@@
@@@@@@@@@ @@@@@@@@*/
// ============ External Imports ============
import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import {Math} from "@openzeppelin/contracts/utils/math/Math.sol";
// ============ Internal Imports ============
import {IInterchainSecurityModule} from "../../interfaces/IInterchainSecurityModule.sol";
import {IStaticWeightedMultisigIsm} from "../../interfaces/isms/IWeightedMultisigIsm.sol";
import {Message} from "../../libs/Message.sol";
import {MerkleLib} from "../../libs/Merkle.sol";
import {AbstractMultisig} from "./AbstractMultisigIsm.sol";
/**
* @title AbstractStaticWeightedMultisigIsm
* @notice Manages per-domain m-of-n Validator sets with stake weights that are used to verify
* interchain messages.
*/
abstract contract AbstractStaticWeightedMultisigIsm is
AbstractMultisig,
IStaticWeightedMultisigIsm
{
// ============ Constants ============
// total weight of all validators
uint96 public constant TOTAL_WEIGHT = 1e10;
/**
* @inheritdoc IStaticWeightedMultisigIsm
*/
function validatorsAndThresholdWeight(
bytes calldata /* _message*/
) public view virtual returns (ValidatorInfo[] memory, uint96);
/**
* @inheritdoc IInterchainSecurityModule
*/
function verify(
bytes calldata _metadata,
bytes calldata _message
) public view virtual returns (bool) {
bytes32 _digest = digest(_metadata, _message);
(
ValidatorInfo[] memory _validators,
uint96 _thresholdWeight
) = validatorsAndThresholdWeight(_message);
require(
_thresholdWeight > 0 && _thresholdWeight <= TOTAL_WEIGHT,
"Invalid threshold weight"
);
uint256 _validatorCount = Math.min(
_validators.length,
signatureCount(_metadata)
);
uint256 _validatorIndex = 0;
uint96 _totalWeight = 0;
// assumes that signatures are ordered by validator
for (
uint256 signatureIndex = 0;
_totalWeight < _thresholdWeight && signatureIndex < _validatorCount;
++signatureIndex
) {
address _signer = ECDSA.recover(
_digest,
signatureAt(_metadata, signatureIndex)
);
// loop through remaining validators until we find a match
while (
_validatorIndex < _validatorCount &&
_signer != _validators[_validatorIndex].signingAddress
) {
++_validatorIndex;
}
// fail if we never found a match
require(_validatorIndex < _validatorCount, "Invalid signer");
// add the weight of the current validator
_totalWeight += _validators[_validatorIndex].weight;
++_validatorIndex;
}
require(
_totalWeight >= _thresholdWeight,
"Insufficient validator weight"
);
return true;
}
}// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity >=0.8.0;
import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import {TypeCasts} from "./TypeCasts.sol";
struct Checkpoint {
uint32 origin;
bytes32 merkleTree;
bytes32 root;
uint32 index;
bytes32 messageId;
}
library CheckpointLib {
using TypeCasts for bytes32;
/**
* @notice Returns the digest validators are expected to sign when signing checkpoints.
* @param _origin The origin domain of the checkpoint.
* @param _merkleTreeHook The address of the origin merkle tree hook as bytes32.
* @param _checkpointRoot The root of the checkpoint.
* @param _checkpointIndex The index of the checkpoint.
* @param _messageId The message ID of the checkpoint.
* @dev Message ID must match leaf content of checkpoint root at index.
* @return The digest of the checkpoint.
*/
function digest(
uint32 _origin,
bytes32 _merkleTreeHook,
bytes32 _checkpointRoot,
uint32 _checkpointIndex,
bytes32 _messageId
) internal pure returns (bytes32) {
bytes32 _domainHash = domainHash(_origin, _merkleTreeHook);
return
ECDSA.toEthSignedMessageHash(
keccak256(
abi.encodePacked(
_domainHash,
_checkpointRoot,
_checkpointIndex,
_messageId
)
)
);
}
/**
* @notice Returns the digest validators are expected to sign when signing checkpoints.
* @param checkpoint The checkpoint (struct) to hash.
* @return The digest of the checkpoint.
*/
function digest(
Checkpoint memory checkpoint
) internal pure returns (bytes32) {
return
digest(
checkpoint.origin,
checkpoint.merkleTree,
checkpoint.root,
checkpoint.index,
checkpoint.messageId
);
}
function merkleTreeAddress(
Checkpoint calldata checkpoint
) internal pure returns (address) {
return checkpoint.merkleTree.bytes32ToAddress();
}
/**
* @notice Returns the domain hash that validators are expected to use
* when signing checkpoints.
* @param _origin The origin domain of the checkpoint.
* @param _merkleTreeHook The address of the origin merkle tree as bytes32.
* @return The domain hash.
*/
function domainHash(
uint32 _origin,
bytes32 _merkleTreeHook
) internal pure returns (bytes32) {
// Including the origin merkle tree address in the signature allows the slashing
// protocol to enroll multiple trees. Otherwise, a valid signature for
// tree A would be indistinguishable from a fraudulent signature for tree B.
// The slashing protocol should slash if validators sign attestations for
// anything other than a whitelisted tree.
return
keccak256(abi.encodePacked(_origin, _merkleTreeHook, "HYPERLANE"));
}
}// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity >=0.6.11;
// work based on eth2 deposit contract, which is used under CC0-1.0
uint256 constant TREE_DEPTH = 32;
uint256 constant MAX_LEAVES = 2 ** TREE_DEPTH - 1;
/**
* @title MerkleLib
* @author Celo Labs Inc.
* @notice An incremental merkle tree modeled on the eth2 deposit contract.
**/
library MerkleLib {
/**
* @notice Struct representing incremental merkle tree. Contains current
* branch and the number of inserted leaves in the tree.
**/
struct Tree {
bytes32[TREE_DEPTH] branch;
uint256 count;
}
/**
* @notice Inserts `_node` into merkle tree
* @dev Reverts if tree is full
* @param _node Element to insert into tree
**/
function insert(Tree storage _tree, bytes32 _node) internal {
require(_tree.count < MAX_LEAVES, "merkle tree full");
_tree.count += 1;
uint256 size = _tree.count;
for (uint256 i = 0; i < TREE_DEPTH; i++) {
if ((size & 1) == 1) {
_tree.branch[i] = _node;
return;
}
_node = keccak256(abi.encodePacked(_tree.branch[i], _node));
size /= 2;
}
// As the loop should always end prematurely with the `return` statement,
// this code should be unreachable. We assert `false` just to be safe.
assert(false);
}
/**
* @notice Calculates and returns`_tree`'s current root given array of zero
* hashes
* @param _zeroes Array of zero hashes
* @return _current Calculated root of `_tree`
**/
function rootWithCtx(
Tree storage _tree,
bytes32[TREE_DEPTH] memory _zeroes
) internal view returns (bytes32 _current) {
uint256 _index = _tree.count;
for (uint256 i = 0; i < TREE_DEPTH; i++) {
uint256 _ithBit = (_index >> i) & 0x01;
bytes32 _next = _tree.branch[i];
if (_ithBit == 1) {
_current = keccak256(abi.encodePacked(_next, _current));
} else {
_current = keccak256(abi.encodePacked(_current, _zeroes[i]));
}
}
}
/// @notice Calculates and returns`_tree`'s current root
function root(Tree storage _tree) internal view returns (bytes32) {
return rootWithCtx(_tree, zeroHashes());
}
/// @notice Returns array of TREE_DEPTH zero hashes
/// @return _zeroes Array of TREE_DEPTH zero hashes
function zeroHashes()
internal
pure
returns (bytes32[TREE_DEPTH] memory _zeroes)
{
_zeroes[0] = Z_0;
_zeroes[1] = Z_1;
_zeroes[2] = Z_2;
_zeroes[3] = Z_3;
_zeroes[4] = Z_4;
_zeroes[5] = Z_5;
_zeroes[6] = Z_6;
_zeroes[7] = Z_7;
_zeroes[8] = Z_8;
_zeroes[9] = Z_9;
_zeroes[10] = Z_10;
_zeroes[11] = Z_11;
_zeroes[12] = Z_12;
_zeroes[13] = Z_13;
_zeroes[14] = Z_14;
_zeroes[15] = Z_15;
_zeroes[16] = Z_16;
_zeroes[17] = Z_17;
_zeroes[18] = Z_18;
_zeroes[19] = Z_19;
_zeroes[20] = Z_20;
_zeroes[21] = Z_21;
_zeroes[22] = Z_22;
_zeroes[23] = Z_23;
_zeroes[24] = Z_24;
_zeroes[25] = Z_25;
_zeroes[26] = Z_26;
_zeroes[27] = Z_27;
_zeroes[28] = Z_28;
_zeroes[29] = Z_29;
_zeroes[30] = Z_30;
_zeroes[31] = Z_31;
}
/**
* @notice Calculates and returns the merkle root for the given leaf
* `_item`, a merkle branch, and the index of `_item` in the tree.
* @param _item Merkle leaf
* @param _branch Merkle proof
* @param _index Index of `_item` in tree
* @return _current Calculated merkle root
**/
function branchRoot(
bytes32 _item,
bytes32[TREE_DEPTH] memory _branch, // cheaper than calldata indexing
uint256 _index
) internal pure returns (bytes32 _current) {
_current = _item;
for (uint256 i = 0; i < TREE_DEPTH; i++) {
uint256 _ithBit = (_index >> i) & 0x01;
// cheaper than calldata indexing _branch[i*32:(i+1)*32];
bytes32 _next = _branch[i];
if (_ithBit == 1) {
_current = keccak256(abi.encodePacked(_next, _current));
} else {
_current = keccak256(abi.encodePacked(_current, _next));
}
}
}
/**
* @notice Calculates and returns the merkle root as if the index is
* the topmost leaf in the tree.
* @param _item Merkle leaf
* @param _branch Merkle proof
* @param _index Index of `_item` in tree
* @dev Replaces siblings greater than the index (right subtrees) with zeroes.
* @return _current Calculated merkle root
**/
function reconstructRoot(
bytes32 _item,
bytes32[TREE_DEPTH] memory _branch, // cheaper than calldata indexing
uint256 _index
) internal pure returns (bytes32 _current) {
_current = _item;
bytes32[TREE_DEPTH] memory _zeroes = zeroHashes();
for (uint256 i = 0; i < TREE_DEPTH; i++) {
uint256 _ithBit = (_index >> i) & 0x01;
// cheaper than calldata indexing _branch[i*32:(i+1)*32];
if (_ithBit == 1) {
_current = keccak256(abi.encodePacked(_branch[i], _current));
} else {
// remove right subtree from proof
_current = keccak256(abi.encodePacked(_current, _zeroes[i]));
}
}
}
// keccak256 zero hashes
bytes32 internal constant Z_0 =
hex"0000000000000000000000000000000000000000000000000000000000000000";
bytes32 internal constant Z_1 =
hex"ad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5";
bytes32 internal constant Z_2 =
hex"b4c11951957c6f8f642c4af61cd6b24640fec6dc7fc607ee8206a99e92410d30";
bytes32 internal constant Z_3 =
hex"21ddb9a356815c3fac1026b6dec5df3124afbadb485c9ba5a3e3398a04b7ba85";
bytes32 internal constant Z_4 =
hex"e58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a19344";
bytes32 internal constant Z_5 =
hex"0eb01ebfc9ed27500cd4dfc979272d1f0913cc9f66540d7e8005811109e1cf2d";
bytes32 internal constant Z_6 =
hex"887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968";
bytes32 internal constant Z_7 =
hex"ffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83";
bytes32 internal constant Z_8 =
hex"9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af";
bytes32 internal constant Z_9 =
hex"cefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0";
bytes32 internal constant Z_10 =
hex"f9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5";
bytes32 internal constant Z_11 =
hex"f8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892";
bytes32 internal constant Z_12 =
hex"3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c";
bytes32 internal constant Z_13 =
hex"c1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb";
bytes32 internal constant Z_14 =
hex"5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc";
bytes32 internal constant Z_15 =
hex"da7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2";
bytes32 internal constant Z_16 =
hex"2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f";
bytes32 internal constant Z_17 =
hex"e1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a";
bytes32 internal constant Z_18 =
hex"5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0";
bytes32 internal constant Z_19 =
hex"b46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0";
bytes32 internal constant Z_20 =
hex"c65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2";
bytes32 internal constant Z_21 =
hex"f4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9";
bytes32 internal constant Z_22 =
hex"5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377";
bytes32 internal constant Z_23 =
hex"4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652";
bytes32 internal constant Z_24 =
hex"cdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef";
bytes32 internal constant Z_25 =
hex"0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d";
bytes32 internal constant Z_26 =
hex"b8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0";
bytes32 internal constant Z_27 =
hex"838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e";
bytes32 internal constant Z_28 =
hex"662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e";
bytes32 internal constant Z_29 =
hex"388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322";
bytes32 internal constant Z_30 =
hex"93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735";
bytes32 internal constant Z_31 =
hex"8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9";
}// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity >=0.8.0;
import {TypeCasts} from "./TypeCasts.sol";
/**
* @title Hyperlane Message Library
* @notice Library for formatted messages used by Mailbox
**/
library Message {
using TypeCasts for bytes32;
uint256 private constant VERSION_OFFSET = 0;
uint256 private constant NONCE_OFFSET = 1;
uint256 private constant ORIGIN_OFFSET = 5;
uint256 private constant SENDER_OFFSET = 9;
uint256 private constant DESTINATION_OFFSET = 41;
uint256 private constant RECIPIENT_OFFSET = 45;
uint256 private constant BODY_OFFSET = 77;
/**
* @notice Returns formatted (packed) Hyperlane message with provided fields
* @dev This function should only be used in memory message construction.
* @param _version The version of the origin and destination Mailboxes
* @param _nonce A nonce to uniquely identify the message on its origin chain
* @param _originDomain Domain of origin chain
* @param _sender Address of sender as bytes32
* @param _destinationDomain Domain of destination chain
* @param _recipient Address of recipient on destination chain as bytes32
* @param _messageBody Raw bytes of message body
* @return Formatted message
*/
function formatMessage(
uint8 _version,
uint32 _nonce,
uint32 _originDomain,
bytes32 _sender,
uint32 _destinationDomain,
bytes32 _recipient,
bytes calldata _messageBody
) internal pure returns (bytes memory) {
return
abi.encodePacked(
_version,
_nonce,
_originDomain,
_sender,
_destinationDomain,
_recipient,
_messageBody
);
}
/**
* @notice Returns the message ID.
* @param _message ABI encoded Hyperlane message.
* @return ID of `_message`
*/
function id(bytes memory _message) internal pure returns (bytes32) {
return keccak256(_message);
}
/**
* @notice Returns the message version.
* @param _message ABI encoded Hyperlane message.
* @return Version of `_message`
*/
function version(bytes calldata _message) internal pure returns (uint8) {
return uint8(bytes1(_message[VERSION_OFFSET:NONCE_OFFSET]));
}
/**
* @notice Returns the message nonce.
* @param _message ABI encoded Hyperlane message.
* @return Nonce of `_message`
*/
function nonce(bytes calldata _message) internal pure returns (uint32) {
return uint32(bytes4(_message[NONCE_OFFSET:ORIGIN_OFFSET]));
}
/**
* @notice Returns the message origin domain.
* @param _message ABI encoded Hyperlane message.
* @return Origin domain of `_message`
*/
function origin(bytes calldata _message) internal pure returns (uint32) {
return uint32(bytes4(_message[ORIGIN_OFFSET:SENDER_OFFSET]));
}
/**
* @notice Returns the message sender as bytes32.
* @param _message ABI encoded Hyperlane message.
* @return Sender of `_message` as bytes32
*/
function sender(bytes calldata _message) internal pure returns (bytes32) {
return bytes32(_message[SENDER_OFFSET:DESTINATION_OFFSET]);
}
/**
* @notice Returns the message sender as address.
* @param _message ABI encoded Hyperlane message.
* @return Sender of `_message` as address
*/
function senderAddress(
bytes calldata _message
) internal pure returns (address) {
return sender(_message).bytes32ToAddress();
}
/**
* @notice Returns the message destination domain.
* @param _message ABI encoded Hyperlane message.
* @return Destination domain of `_message`
*/
function destination(
bytes calldata _message
) internal pure returns (uint32) {
return uint32(bytes4(_message[DESTINATION_OFFSET:RECIPIENT_OFFSET]));
}
/**
* @notice Returns the message recipient as bytes32.
* @param _message ABI encoded Hyperlane message.
* @return Recipient of `_message` as bytes32
*/
function recipient(
bytes calldata _message
) internal pure returns (bytes32) {
return bytes32(_message[RECIPIENT_OFFSET:BODY_OFFSET]);
}
/**
* @notice Returns the message recipient as address.
* @param _message ABI encoded Hyperlane message.
* @return Recipient of `_message` as address
*/
function recipientAddress(
bytes calldata _message
) internal pure returns (address) {
return recipient(_message).bytes32ToAddress();
}
/**
* @notice Returns the message body.
* @param _message ABI encoded Hyperlane message.
* @return Body of `_message`
*/
function body(
bytes calldata _message
) internal pure returns (bytes calldata) {
return bytes(_message[BODY_OFFSET:]);
}
}// SPDX-License-Identifier: CC0-1.0
pragma solidity >=0.7.6;
/// @dev Adapted from https://eips.ethereum.org/EIPS/eip-3448
library MetaProxy {
bytes32 private constant PREFIX =
hex"600b380380600b3d393df3363d3d373d3d3d3d60368038038091363936013d73";
bytes13 private constant SUFFIX = hex"5af43d3d93803e603457fd5bf3";
function bytecode(
address _implementation,
bytes memory _metadata
) internal pure returns (bytes memory) {
return
abi.encodePacked(
PREFIX,
bytes20(_implementation),
SUFFIX,
_metadata,
_metadata.length
);
}
function metadata() internal pure returns (bytes memory) {
bytes memory data;
assembly {
let posOfMetadataSize := sub(calldatasize(), 32)
let size := calldataload(posOfMetadataSize)
let dataPtr := sub(posOfMetadataSize, size)
data := mload(64)
// increment free memory pointer by metadata size + 32 bytes (length)
mstore(64, add(data, add(size, 32)))
mstore(data, size)
let memPtr := add(data, 32)
calldatacopy(memPtr, dataPtr, size)
}
return data;
}
}// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity >=0.8.0;
// ============ External Imports ============
import {Address} from "@openzeppelin/contracts/utils/Address.sol";
import {Create2} from "@openzeppelin/contracts/utils/Create2.sol";
import {IStaticWeightedMultisigIsm} from "../interfaces/isms/IWeightedMultisigIsm.sol";
// ============ Internal Imports ============
import {MetaProxy} from "./MetaProxy.sol";
import {PackageVersioned} from "../PackageVersioned.sol";
abstract contract StaticWeightedValidatorSetFactory is PackageVersioned {
// ============ Immutables ============
address public immutable implementation;
// ============ Constructor ============
constructor() {
implementation = _deployImplementation();
}
function _deployImplementation() internal virtual returns (address);
/**
* @notice Deploys a StaticWeightedValidatorSet contract address for the given
* values
* @dev Consider sorting addresses to ensure contract reuse
* @param _validators An array of addresses
* @param _thresholdWeight The threshold weight value to use
* @return set The contract address representing this StaticWeightedValidatorSet
*/
function deploy(
IStaticWeightedMultisigIsm.ValidatorInfo[] calldata _validators,
uint96 _thresholdWeight
) public returns (address) {
(bytes32 _salt, bytes memory _bytecode) = _saltAndBytecode(
_validators,
_thresholdWeight
);
address _set = _getAddress(_salt, _bytecode);
if (!Address.isContract(_set)) {
_set = Create2.deploy(0, _salt, _bytecode);
}
return _set;
}
/**
* @notice Returns the StaticWeightedValidatorSet contract address for the given
* values
* @dev Consider sorting addresses to ensure contract reuse
* @param _validators An array of addresses
* @param _thresholdWeight The threshold weight value to use
* @return set The contract address representing this StaticWeightedValidatorSet
*/
function getAddress(
IStaticWeightedMultisigIsm.ValidatorInfo[] calldata _validators,
uint96 _thresholdWeight
) external view returns (address) {
(bytes32 _salt, bytes memory _bytecode) = _saltAndBytecode(
_validators,
_thresholdWeight
);
return _getAddress(_salt, _bytecode);
}
/**
* @notice Returns the StaticWeightedValidatorSet contract address for the given
* values
* @param _salt The salt used in Create2
* @param _bytecode The metaproxy bytecode used in Create2
* @return set The contract address representing this StaticWeightedValidatorSet
*/
function _getAddress(
bytes32 _salt,
bytes memory _bytecode
) internal view returns (address) {
bytes32 _bytecodeHash = keccak256(_bytecode);
return Create2.computeAddress(_salt, _bytecodeHash);
}
/**
* @notice Returns the create2 salt and bytecode for the given values
* @param _validators An array of addresses
* @param _thresholdWeight The threshold weight value to use
* @return _salt The salt used in Create2
* @return _bytecode The metaproxy bytecode used in Create2
*/
function _saltAndBytecode(
IStaticWeightedMultisigIsm.ValidatorInfo[] calldata _validators,
uint96 _thresholdWeight
) internal view returns (bytes32, bytes memory) {
bytes memory _metadata = abi.encode(_validators, _thresholdWeight);
bytes memory _bytecode = MetaProxy.bytecode(implementation, _metadata);
bytes32 _salt = keccak256(_metadata);
return (_salt, _bytecode);
}
}// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity >=0.6.11;
library TypeCasts {
// alignment preserving cast
function addressToBytes32(address _addr) internal pure returns (bytes32) {
return bytes32(uint256(uint160(_addr)));
}
// alignment preserving cast
function bytes32ToAddress(bytes32 _buf) internal pure returns (address) {
require(
uint256(_buf) <= uint256(type(uint160).max),
"TypeCasts: bytes32ToAddress overflow"
);
return address(uint160(uint256(_buf)));
}
}{
"evmVersion": "paris",
"libraries": {},
"optimizer": {
"enabled": true,
"runs": 999999
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"name":"PACKAGE_VERSION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"signingAddress","type":"address"},{"internalType":"uint96","name":"weight","type":"uint96"}],"internalType":"struct IStaticWeightedMultisigIsm.ValidatorInfo[]","name":"_validators","type":"tuple[]"},{"internalType":"uint96","name":"_thresholdWeight","type":"uint96"}],"name":"deploy","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"signingAddress","type":"address"},{"internalType":"uint96","name":"weight","type":"uint96"}],"internalType":"struct IStaticWeightedMultisigIsm.ValidatorInfo[]","name":"_validators","type":"tuple[]"},{"internalType":"uint96","name":"_thresholdWeight","type":"uint96"}],"name":"getAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"implementation","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]Contract Creation Code
60a060405234801561001057600080fd5b5061001961002a565b6001600160a01b0316608052610067565b60006040516100389061005a565b604051809103906000f080158015610054573d6000803e3d6000fd5b50905090565b61139d8061071783390190565b60805161068f61008860003960008181605601526101c3015261068f6000f3fe608060405234801561001057600080fd5b506004361061004c5760003560e01c80635c60da1b146100515780636a373128146100a257806393c44847146100b5578063f0118ba6146100fe575b600080fd5b6100787f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b6100786100b0366004610449565b610111565b6100f16040518060400160405280600681526020017f372e312e3130000000000000000000000000000000000000000000000000000081525081565b60405161009991906104f1565b61007861010c366004610449565b61013b565b6000806000610121868686610190565b9150915061012f8282610200565b925050505b9392505050565b600080600061014b868686610190565b91509150600061015b8383610200565b905073ffffffffffffffffffffffffffffffffffffffff81163b61012f576101856000848461021c565b979650505050505050565b6000606060008585856040516020016101ab93929190610542565b604051602081830303815290604052905060006101e87f000000000000000000000000000000000000000000000000000000000000000083610380565b82516020909301929092209791965090945050505050565b8051602082012060009061021484826103f6565b949350505050565b60008347101561028d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f437265617465323a20696e73756666696369656e742062616c616e636500000060448201526064015b60405180910390fd5b81516000036102f8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f437265617465323a2062797465636f6465206c656e677468206973207a65726f6044820152606401610284565b8282516020840186f5905073ffffffffffffffffffffffffffffffffffffffff8116610134576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f437265617465323a204661696c6564206f6e206465706c6f79000000000000006044820152606401610284565b60607f600b380380600b3d393df3363d3d373d3d3d3d60368038038091363936013d738360601b7f5af43d3d93803e603457fd5bf3000000000000000000000000000000000000008485516040516020016103df9594939291906105da565b604051602081830303815290604052905092915050565b60006101348383306000604051836040820152846020820152828152600b8101905060ff815360559020949350505050565b80356bffffffffffffffffffffffff8116811461044457600080fd5b919050565b60008060006040848603121561045e57600080fd5b833567ffffffffffffffff8082111561047657600080fd5b818601915086601f83011261048a57600080fd5b81358181111561049957600080fd5b8760208260061b85010111156104ae57600080fd5b6020928301955093506104c49186019050610428565b90509250925092565b60005b838110156104e85781810151838201526020016104d0565b50506000910152565b60208152600082518060208401526105108160408501602087016104cd565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b6040808252818101849052600090856060840183805b888110156105b657833573ffffffffffffffffffffffffffffffffffffffff8116808214610584578384fd5b84525060206bffffffffffffffffffffffff6105a1868301610428565b16908401529284019291840191600101610558565b50508093505050506bffffffffffffffffffffffff83166020830152949350505050565b8581527fffffffffffffffffffffffffffffffffffffffff000000000000000000000000851660208201527fffffffffffffffffffffffffff0000000000000000000000000000000000000084166034820152600083516106428160418501602088016104cd565b60419201918201929092526061019594505050505056fea2646970667358221220f8b589c09372efb15e6255feda8c22c01ffbfd45fdf9878c5e16767c247d310c64736f6c63430008160033608060405234801561001057600080fd5b5061137d806100206000396000f3fe608060405234801561001057600080fd5b50600436106100725760003560e01c8063ec29dbde11610050578063ec29dbde14610100578063ed2a2f9d14610121578063f7e83aee1461014a57600080fd5b806322a8d6fc146100775780636465e69f1461009d57806393c44847146100b7575b600080fd5b61008a610085366004610cec565b61016d565b6040519081526020015b60405180910390f35b6100a5600981565b60405160ff9091168152602001610094565b6100f36040518060400160405280600681526020017f372e312e3130000000000000000000000000000000000000000000000000000081525081565b6040516100949190610d2e565b61011361010e366004610cec565b610182565b604051610094929190610d9b565b61012d6402540be40081565b6040516bffffffffffffffffffffffff9091168152602001610094565b61015d610158366004610e26565b6101ad565b6040519015158152602001610094565b600061017983836104bc565b90505b92915050565b6060600061018e610552565b8060200190518101906101a19190610f89565b915091505b9250929050565b6000806101bc86868686610582565b90506000806101cb8686610182565b915091506000816bffffffffffffffffffffffff1611801561020057506402540be4006bffffffffffffffffffffffff821611155b61026b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f496e76616c6964207468726573686f6c6420776569676874000000000000000060448201526064015b60405180910390fd5b6000610281835161027c8b8b61016d565b61078a565b905060008060005b846bffffffffffffffffffffffff16826bffffffffffffffffffffffff161080156102b357508381105b15610424576000610303886102c98f8f866107a0565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506107ba92505050565b90505b848410801561035e575086848151811061032257610322611090565b60200260200101516000015173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614155b156103735761036c846110ee565b9350610306565b8484106103dc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f496e76616c6964207369676e65720000000000000000000000000000000000006044820152606401610262565b8684815181106103ee576103ee611090565b602002602001015160200151836104059190611126565b9250610410846110ee565b9350508061041d906110ee565b9050610289565b50836bffffffffffffffffffffffff16816bffffffffffffffffffffffff1610156104ab576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f496e73756666696369656e742076616c696461746f72207765696768740000006044820152606401610262565b5060019a9950505050505050505050565b6000806104cb61044884611152565b90506104d8604182611194565b1561053f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f496e76616c6964207369676e617475726573206c656e677468000000000000006044820152606401610262565b61054a6041826111a8565b949350505050565b60608060203603803580820391506040519250602081018301604052808352602083018183823750919392505050565b600061058e85856107de565b63ffffffff1661059e8686610814565b63ffffffff16111561060c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f496e76616c6964206d65726b6c6520696e646578206d657461646174610000006044820152606401610262565b600061066f61065085858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061083592505050565b61065a8888610840565b6106648989610814565b63ffffffff16610876565b905061078061067e8585610914565b6106888888610924565b836106938a8a6107de565b61069d8b8b61094d565b604080517fffffffff0000000000000000000000000000000000000000000000000000000060e097881b811660208084019190915260248301979097527f48595045524c414e45000000000000000000000000000000000000000000000060448301528251808303602d018152604d83018452805190880120606d830152608d8201959095529290951b90921660ad82015260b1808201929092528351808203909201825260d10190925281519101207f19457468657265756d205369676e6564204d6573736167653a0a3332000000006000908152601c91909152603c902090565b9695505050505050565b60008183106107995781610179565b5090919050565b3660006107ae85858561095e565b91509150935093915050565b60008060006107c985856109a4565b915091506107d6816109e6565b509392505050565b600082610444836107f08260046111bc565b61ffff1692610801939291906111d7565b61080a91611201565b60e01c9392505050565b600082602083610825826004611249565b60ff1692610801939291906111d7565b805160209091012090565b610848610c8b565b82604483610858610400836111bc565b61ffff1692610869939291906111d7565b8101906101799190611262565b8260005b60208110156107d657600183821c16600085836020811061089d5761089d611090565b60200201519050816001036108dd57604080516020810183905290810185905260600160405160208183030381529060405280519060200120935061090a565b60408051602081018690529081018290526060016040516020818303038152906040528051906020012093505b505060010161087a565b60006108016009600584866111d7565b6000828183610934826020611249565b60ff1692610944939291906111d7565b610179916112e1565b600082602483610934826020611249565b3660008061096d60418561131d565b61097990610448611334565b90506000610988604183611334565b90506109968183888a6111d7565b935093505050935093915050565b60008082516041036109da5760208301516040840151606085015160001a6109ce87828585610b9c565b945094505050506101a6565b506000905060026101a6565b60008160048111156109fa576109fa610e92565b03610a025750565b6001816004811115610a1657610a16610e92565b03610a7d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610262565b6002816004811115610a9157610a91610e92565b03610af8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610262565b6003816004811115610b0c57610b0c610e92565b03610b99576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610262565b50565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115610bd35750600090506003610c82565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015610c27573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff8116610c7b57600060019250925050610c82565b9150600090505b94509492505050565b6040518061040001604052806020906020820280368337509192915050565b60008083601f840112610cbc57600080fd5b50813567ffffffffffffffff811115610cd457600080fd5b6020830191508360208285010111156101a657600080fd5b60008060208385031215610cff57600080fd5b823567ffffffffffffffff811115610d1657600080fd5b610d2285828601610caa565b90969095509350505050565b60006020808352835180602085015260005b81811015610d5c57858101830151858201604001528201610d40565b5060006040828601015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168501019250505092915050565b60408082528351828201819052600091906020906060850190828801855b82811015610e02578151805173ffffffffffffffffffffffffffffffffffffffff1685528501516bffffffffffffffffffffffff16858501529285019290840190600101610db9565b5050508093505050506bffffffffffffffffffffffff831660208301529392505050565b60008060008060408587031215610e3c57600080fd5b843567ffffffffffffffff80821115610e5457600080fd5b610e6088838901610caa565b90965094506020870135915080821115610e7957600080fd5b50610e8687828801610caa565b95989497509550505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040805190810167ffffffffffffffff81118282101715610f1357610f13610ec1565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715610f6057610f60610ec1565b604052919050565b80516bffffffffffffffffffffffff81168114610f8457600080fd5b919050565b6000806040808486031215610f9d57600080fd5b835167ffffffffffffffff80821115610fb557600080fd5b818601915086601f830112610fc957600080fd5b8151602082821115610fdd57610fdd610ec1565b610feb818360051b01610f19565b828152818101935060069290921b84018101918983111561100b57600080fd5b938101935b828510156110755785858b0312156110285760008081fd5b611030610ef0565b855173ffffffffffffffffffffffffffffffffffffffff811681146110555760008081fd5b8152611062868401610f68565b8184015284529385019392810192611010565b9650611082888201610f68565b955050505050509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361111f5761111f6110bf565b5060010190565b6bffffffffffffffffffffffff81811683821601908082111561114b5761114b6110bf565b5092915050565b8181038181111561017c5761017c6110bf565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000826111a3576111a3611165565b500690565b6000826111b7576111b7611165565b500490565b61ffff81811683821601908082111561114b5761114b6110bf565b600080858511156111e757600080fd5b838611156111f457600080fd5b5050820193919092039150565b7fffffffff0000000000000000000000000000000000000000000000000000000081358181169160048510156112415780818660040360031b1b83161692505b505092915050565b60ff818116838216019081111561017c5761017c6110bf565b600061040080838503121561127657600080fd5b83601f84011261128557600080fd5b60405181810181811067ffffffffffffffff821117156112a7576112a7610ec1565b6040529083019080858311156112bc57600080fd5b845b838110156112d65780358252602091820191016112be565b509095945050505050565b8035602083101561017c577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff602084900360031b1b1692915050565b808202811582820484141761017c5761017c6110bf565b8082018082111561017c5761017c6110bf56fea26469706673582212203ea3fbafc54230bedf30a9016e4a3d33f41732bfca1c13e2967f89d84ace91f964736f6c63430008160033
Deployed Bytecode
0x608060405234801561001057600080fd5b506004361061004c5760003560e01c80635c60da1b146100515780636a373128146100a257806393c44847146100b5578063f0118ba6146100fe575b600080fd5b6100787f0000000000000000000000003b9f24fd2ecfed0d3a88fa7f0e4e5747671981d781565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b6100786100b0366004610449565b610111565b6100f16040518060400160405280600681526020017f372e312e3130000000000000000000000000000000000000000000000000000081525081565b60405161009991906104f1565b61007861010c366004610449565b61013b565b6000806000610121868686610190565b9150915061012f8282610200565b925050505b9392505050565b600080600061014b868686610190565b91509150600061015b8383610200565b905073ffffffffffffffffffffffffffffffffffffffff81163b61012f576101856000848461021c565b979650505050505050565b6000606060008585856040516020016101ab93929190610542565b604051602081830303815290604052905060006101e87f0000000000000000000000003b9f24fd2ecfed0d3a88fa7f0e4e5747671981d783610380565b82516020909301929092209791965090945050505050565b8051602082012060009061021484826103f6565b949350505050565b60008347101561028d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f437265617465323a20696e73756666696369656e742062616c616e636500000060448201526064015b60405180910390fd5b81516000036102f8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f437265617465323a2062797465636f6465206c656e677468206973207a65726f6044820152606401610284565b8282516020840186f5905073ffffffffffffffffffffffffffffffffffffffff8116610134576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f437265617465323a204661696c6564206f6e206465706c6f79000000000000006044820152606401610284565b60607f600b380380600b3d393df3363d3d373d3d3d3d60368038038091363936013d738360601b7f5af43d3d93803e603457fd5bf3000000000000000000000000000000000000008485516040516020016103df9594939291906105da565b604051602081830303815290604052905092915050565b60006101348383306000604051836040820152846020820152828152600b8101905060ff815360559020949350505050565b80356bffffffffffffffffffffffff8116811461044457600080fd5b919050565b60008060006040848603121561045e57600080fd5b833567ffffffffffffffff8082111561047657600080fd5b818601915086601f83011261048a57600080fd5b81358181111561049957600080fd5b8760208260061b85010111156104ae57600080fd5b6020928301955093506104c49186019050610428565b90509250925092565b60005b838110156104e85781810151838201526020016104d0565b50506000910152565b60208152600082518060208401526105108160408501602087016104cd565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b6040808252818101849052600090856060840183805b888110156105b657833573ffffffffffffffffffffffffffffffffffffffff8116808214610584578384fd5b84525060206bffffffffffffffffffffffff6105a1868301610428565b16908401529284019291840191600101610558565b50508093505050506bffffffffffffffffffffffff83166020830152949350505050565b8581527fffffffffffffffffffffffffffffffffffffffff000000000000000000000000851660208201527fffffffffffffffffffffffffff0000000000000000000000000000000000000084166034820152600083516106428160418501602088016104cd565b60419201918201929092526061019594505050505056fea2646970667358221220f8b589c09372efb15e6255feda8c22c01ffbfd45fdf9878c5e16767c247d310c64736f6c63430008160033
Loading...
Loading
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.